The issue, here, is one of design.
The way you’re supposed to use the list and column views in GTK4 is via the model-view-controller pattern:
- you have an object that contains the whole state you want to represent for each row
- you have a list object, containing all the rows
- you have a row widget that represents a row object in the list
- you have a view widget that represents the (visible) rows
Each row widget has to be “bound” to a row object; whenever the row object changes state, the row widget gets updated. The way this happens is through GObject properties, which have an automatic notification system on change.
That’s what the “bind” function is supposed to do: bind one or more properties on the list view item to one or more properties to the list view widget.
By way of an example, let’s suppose you have a “Person” object that contains an identifier and a name:
class Person(GObject.Object):
__gtype_name__ = 'Person'
def __init__(self, person_id, name):
super().__init__()
self._id = person_id
self._name = name
@GObject.Property(type=str, flags=GObject.ParamFlags.READABLE)
def person_id(self):
return self._id
@GObject.Property(type=str)
def person_name(self):
return self._name
@person_name.setter
def set_person_name(self, name):
if self._name != name:
self._name = name
self.notify("person-name")
Now we populate a Gio.ListStore
with a bunch of people:
nodes = {
"aaa": "Clark Kent",
"aab": "Bruce Wayne",
"aac": "Barry Allen",
# ...
}
self.model = Gio.ListStore(item_type=Person)
for n in nodes.keys():
self.model.append(Person(person_id=n, person_name=nodes[n]))
And we set up a factory to be used by any list or column view, so we can bind rows in the views to rows in the model:
factory = Gtk.SignalListItemFactory()
def _on_factory_setup(factory, list_item):
label = Gtk.Label()
list_item.set_child(label)
factory.connect("setup", _on_factory_setup)
def _on_factory_bind(factory, list_item):
label = list_item.get_child()
person = list_item.get_item()
person.bind_property("person_name",
label, "label",
GObject.BindingFlags.SYNC_CREATE)
factory.connect("bind", _on_factory_bind)
Now, every time a Person object in the model changes the value of the “person-name” property, the label widget that represents that Person in the view will update the “label” property.
If you have more complex rows, you will need to create your own composite widget and add properties to them that you can bind to objects in your model. In C, some of the complexity between nesting widgets and properties can be avoided by using GtkExpression
instead of GObject.bind_property
, but that’s not available to the Python bindings.