I am trying to implement a custom widget in GTK3. This widget is a row in a Gtk.ListBox widget, which contains a label and a button. When the button is clicked, the listbox should remove the row which contained the button.
The relevant code looks like this:
import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk
class MainWindow(Gtk.Window):
def __init__(self):
Gtk.Window.__init__(self)
self.set_default_size(200, -1)
self.connect("destroy", Gtk.main_quit)
self.listbox = Gtk.ListBox()
self.add(self.listbox)
row = self.CustomRow('label content')
self.listbox.add(row)
def remove_row(button, row):
MainWindow().listbox.remove(row)
class CustomRow(Gtk.ListBoxRow):
def __init__(self, content):
Gtk.ListBoxRow.__init__(self)
self.content = content
box = Gtk.Box()
box.set_orientation(Gtk.Orientation.HORIZONTAL)
label = Gtk.Label().new(str=self.content)
button_remove = Gtk.Button().new_from_icon_name(icon_name='gtk-close', size=1)
button_remove.connect('clicked', MainWindow.remove_row, self)
box.pack_start(label, True, True, 5)
box.pack_start(button_remove, False, False, 5)
self.add(box)
window = MainWindow()
window.show_all()
Gtk.main()
The example code above creates a window containing a listbox with a custom row widget (CustomRow) added to it. The custom row widget contains a label and a delete button. When the delete button is clicked, the remove_row function is called (with the row passed as an extra argument), which should remove the row from the listbox.
The issue is that it doesn't, as GTK throws an error, as apparently the listbox is not a parent of the row that was passed as an argument (in remove_row function). This is confirmed as the output of print(row.get_parent()) and print(MainWindow().listbox), which returns a different memory address for the two objects. I don't understand why.
I also have two questions regarding how the signals are handled:
1.Why does the remove_row function not inherit from the MainWindow class when given the self argument, such that:
def remove_row(self, button, row):
self.listbox.remove(row)
2.Why does button_remove.connect('clicked', MainWindow.remove_row) not pass self as an argument by default when called from the CustomRow class?
When you write:
you seem to assume that the first argument is the button and the second is the row to remove. In reality, you have that the first argument is the main window, and the second is the button which triggered the signal. So you have:
The problem is that the row information is lost at the main window level. To solve this, I moved the handler to the
CustomRowclass and used the reference to the parent list (fromGtkListBoxRow.get_parent()) to remove the row:This makes the row responsible to remove itself, and the main window doesn't have to handle lists at all.