Search code examples
pythongtk4

How do I use GTK4's ColumnView to replace TreeView in Python?


I'm converting a Python (3.10) application from GTK3 to GTK4, and I would like to move away from TreeView/CellRenderer usage, and try to use ColumnView instead. I've read the documentation on GTK4's new list widgets, read their blog post about them, searched for examples, and am still quite confused.

As I understand it, a ColumnView has a single model (i.e. Gtk.SingleSelection), which itself is based on a GListModel (i.e. Gio.ListStore). Gio.ListStore does not accept a list, like a Gtk.ListStore does, so my question is, how do I store data for multiple columns, when the model (Gio.ListStore) doesn't accept a list?


Solution

  • You have to define your own Gobject.Object to put into the Gio.ListStore and then make your own factory to get those items. For example, I have a custom object defined as follows:

    class FamilieRow(GObject.Object):
        familie: str
        anzahl: int
    
        def __init__(self, familie: str, anzahl: int):
            super().__init__()
            self.familie = familie
            self.anzahl = anzahl
    

    The Gio.ListStore then stores those items:

    ls = Gio.ListStore()
    ls.append(FamilieRow("Steffens", 15))
    

    To populate the row familie the factory is defined as

    factory = Gtk.SignalListItemFactory()
    factory.connect("setup", lambda _fact, item:
        item.set_child(Gtk.Label(halign=Gtk.Align.START))
    factory.connect("bind", lambda _fact, item:
        item.get_child().set_label(item.get_item().familie))
    
    col_f = Gtk.ColumnViewColumn(
            title="Familie",
            factory=factory,
    )
    

    If you wanted to change more than just the label, it could be inconvenient to use a lambda. Then you could let the custom object itself set up the widget by defining

    factory.bind("bind", lambda _fact, item: item.get_item().bind_familie(item.get_child()))
    

    and defining a bind_familie method on your row object

    class FamilieRow(GObject.Object):
        ...
        def bind_familie(self, label: Gtk.Label, column: str):
            label.set_label(self.familie)
            label.set_style_classes(["big"] if self.anzahl > 40 else [])