6

I want to popup a context menu when the user right-clicks on the header row of a Gtk.TreeView. In GTK3, Gtk.TreeViewColumn has a get_button() method, which makes this easy; simply attach the menu to the button and connect it to a 'clicked' event. However, in GTK2, this won't work. You can only call a get_widget() method, which returns None if you haven't set a widget via set_widget(). I've tried putting a Gtk.Label with the column name into a Gtk.EventBox and set that as the widget After connecting the EventBox to a callback for the 'button_press_event', clicking on it doesn't generate the event.

I tried to do something like what's listed here but doing get_parent() on the column widget returns None, and never reaches the button as their code implies.

What solutions have people found for this?

  • I should clarify that by "in GTK2, this won't work", I should have said, "in GTK2, the `get_button()` method wasn't implemented. –  Aug 05 '11 at 22:04
  • Now I'm also finding out that `menu.attach_to_widget()` and `menu.popup()` apparently are not introspectable in GTK2. According to the [PyGObject site](https://live.gnome.org/PyGObject/IntrospectionPorting), in GTK3 `menu.popup()` was implemented through an override, however I can't find documentation on how this was done. –  Aug 06 '11 at 13:02

3 Answers3

3

This is pretty easy actually, but you need a couple of hacks.

First you need to force Gtk to create a header button for the GtkTreeViewColumn:

    label = gtk.Label("Column title")
    label.show()
    treeview_column.set_widget(label)

After that you need to fetch the internal GtkButton of the header:

    widget = treeview_column.get_widget()
    while not isinstance(widget, gtk.Button):
        widget = widget.get_parent()

Finally with a button reference you can do something useful:

    def button_release_event(button, event):
        if event.button == 3:
           menu.popup(event)

    widget.connect('button-release-event', button_release_event)

This was taken from the kiwi library which has an ObjectList which provides a python list like api for creating GtkTreeViews.

Johan Dahlin
  • 25,300
  • 6
  • 40
  • 55
  • I'm writing in Perl, but this same approach works. Thanks! Of note, I have to add the column to the treeview before calling get_widget. – TheAmigo Aug 07 '15 at 15:34
0

I love working examples on S.O, so I decided to post one. All the credits are for @Johan Dahlin!

#!/usr/bin/env python3

from gi.repository import Gtk

def button_release_event(button, event):
    if event.button == 3:
        menu.popup(None, None, None, None, event.button, event.time)


window = Gtk.Window()
window.connect("destroy", lambda q: Gtk.main_quit())

liststore = Gtk.ListStore(str)
liststore.append(["1"])
liststore.append(["2"])

menu=Gtk.Menu()
menu.append(Gtk.ImageMenuItem("Yep it works!"))
menu.append(Gtk.ImageMenuItem(":)"))
menu.show_all()

treeview = Gtk.TreeView(model=liststore)
window.add(treeview)

treeviewcolumn = Gtk.TreeViewColumn()
treeview.append_column(treeviewcolumn)    

# Set the treeviewcolum as clickable
#
treeviewcolumn.set_clickable(True)

# force Gtk to create a header button for the Gtk.TreeViewColumn
#
label = Gtk.Label("Numbers")
label.show()
treeviewcolumn.set_widget(label)

# fetch the internal GtkButton of the header:
#
widget = treeviewcolumn.get_widget()
while not isinstance(widget, Gtk.Button):
    widget = widget.get_parent()

widget.connect('button-release-event', button_release_event)

cellrenderertext = Gtk.CellRendererText()
treeviewcolumn.pack_start(cellrenderertext, True)
treeviewcolumn.add_attribute(cellrenderertext, 'text', 0)

window.show_all()
Gtk.main()

happy hacking!

0

This indeed seems complicated, I had a look at the source. Apparently the parent trick works (and returns the alignment object), however your custom label is only added to the button after the TreeviewColumn has been realized, so before that the parent attribute stays None So probably latest after your show command of the Treeview, you should be able to retrieve the parents (Button->HBox->Alignment->Label) and can attach your handler to the signal.

rumpel
  • 7,870
  • 2
  • 38
  • 39