How do you attach a popup menu to a column header button in GTK2 using PyGObject?
I want to popup a context menu when the user right-clicks o开发者_如何学运维n 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?
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.
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.
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!
精彩评论