The API has evolved since this question was asked, so I thought I would post an updated answer. (I had stumbled across this while dealing with a similar issue, although in my case I was trying to put two Buttons in the column header, not an Entry.)
First, some background. As mentioned in the question's edit, the issue stems from the way a TreeViewColumn is structured. The header of the column is a Button, and when you set_widget
, that widget becomes a descendant of the Button. (This can be easily overlooked since the header does not respond like a button unless you set the column to be clickable. Also, the documentation does not help, as it seems to assume everyone already knows this.) A further cause of the issue is the way Buttons collect events. Unlike most widgets that respond to events, a Button does not have its own spot in the Gdk.Window hierarchy. Instead, it creates a special event window when it is realized. The method for accessing this window is Button-specific: get_event_window
(distinct from the more generic get_window
and get_parent_window
). This event window sits invisibly above the Button, collecting events before they trickle down to any descendants of the Button. Hence, the widget you place in the column header does not receive the events required for interactivity.
The accepted solution is one way around this obstacle, and it was a worthy answer at the time. However, there is now an easier way. (I should mention that this is a GTK+ issue, independent of the language binding being used. Personally, I was using the C++ binding. I also peeked at the GTK+ source files – in C – to confirm that this is core GTK+ behavior and not some artifact of the binding.)
1) Find the header Button.
If column
is the TreeViewColumn in question, the API for getting the button is now simply:
header_button = column.get_button()
The get_button
method was added in version 3.0, which was tagged about six months after this question was asked. So close.
2) Propagate events from the Button to the Entry.
It took another four years (version 3.18) for this step to simplify. The key development was set_pass_through
, which can tell the event window to let events pass through. As the documentation states: "In the terminology of the web this would be called 'pointer-events: none'."
def pass_through_event_window(button, event):
if not isinstance(button, gtk.Button):
raise TypeError("%r is not a gtk.Button" % button)
event_window = button.get_event_window()
event_window.set_pass_through(True)
The remaining trick is one of timing. The event window is not created until the Button is realized, so connecting to the Button's realize
signal is in order.
header_button.connect('realize', pass_through_event_window)
And that's it (there is no step 3). Events will now propagate to the Entry or whatever widget you put in the column header.
My apologies if I messed up the syntax; I am translating from the C++ binding. If there are errors, I would request a kindly Python guru to correct them.