Context menus for Gtk.TreeView headers
Friday, March 24th, 2006[The following mini-HOWTO is posted in the hopes of saving someone else the trouble of figuring out all this magic later]
This past week at work, I came upon the interesting problem of adding a right click menu to the *header* of a Gtk.TreeView. The issue being that TreeViewColumn is not infact a Gtk.Widget, but merely a Gtk.Object, exposes no Child or Children property like a Gtk.Bin or Gtk.Container, and is generally relatively API limited.
The following code snippet was adopted from some random bug on the GNOME bugzilla that I’m now failing to locate and link to. The full example in Boo can be found here. I have a version in C# as well, but it’s not nicely formatted, and lacks the inline comments that the above Boo version has.
The basic gist of the trick is to set TreeViewColumn.Widget to a new Gtk.Label instance:
col.Widget = Label (”Right Click Me!”)
col.Widget.Show ()
and then iterating over the Parent Gtk.Widgets of the label until you find one that is an instance of a Gtk.Button:
parent_widget = col.Widget.Parent
parent_button = parent_widget as Button
while (parent_widget != null and parent_button == null):
parent_widget = parent_widget.Parent
parent_button = parent_widget as Button
This Button will actually be the one used for the header, and you can connect to the ButtonPressEvent here, and in that handler do any menu pop up, etc. that you desire:
if parent_button is not null:
parent_button.ButtonPressEvent += OnHeaderButtonPress
In your handler, you can then pop up a menu if it’s the correct button, etc:
[GLib.ConnectBefore]
def OnHeaderButtonPress (o as object, e as ButtonPressEventArgs):
if e.Event.Button == 3:
menu.Popup ()
e.RetVal = false
Couple of gotchyas:
- You *must* add the TreeViewColumn to the TreeView before doing any of the custom widget parent stuff. The column doesn’t do most of the setup unless this has happened first.
- Make sure you use [GLib.ConnectBefore] on your method attaching to the ButtonPressEvent, so it gets called before TreeViewColumn’s handler does, otherwise you’ll never even see the event. Similarly, if you handle the event, you’ll want to set args.RetVal = false to stop propogation of the event.
- There’ s no guarantee this won’t break if the gtk+ folks change the internals of GtkTreeViewColumn.
- Your TreeView must have HeadersVisible and HeadersClickable true.
Checkout the full Boo code for all the magic, with inline comments.
UPDATE: As Joe pointed out in the comments, you can actually optimize the ‘find the parent button’ process by using Gtk.Widget.GetAncestor (GLib.GType). There’s a new version of the full boo file found here. Thanks Joe!