GTK GUI with PyGObject (5)

Date: 2021/07/18 (initial publish), 2021/07/24 (last update)

Source: en/note-00018.md

Previous Post Top Next Post

TOC

GtkListBox and GtkFlowBox

These are like Gtk.Box and Gtk.Grid but its contents can by dynamically sorted and filtered.

The children of these are Gtk.ListBoxRow and Gtk.FlowBoxChild respectively and these can be fairly complex. If the content of these are simple enough, use of Gtk.TreeView and Gtk.IconView may save your efforts.

GtkTreeView

Although Gtk.TreeView was mentioned as a simpler tool to use than Gtk.ListBox, it is still quite complex since this involves Model-View type GUI conventions.. Let’s use this with Gtk.Template and Glade to learn how it works.

NOTE: Please don’t consider things described here and subsequent pages are the best known methods. I am merely recording how I got it work (sort of …).

GtkTreeView is used with Gtk.TreeModel such as GtkListStore or GtkTreeStore.

I wasn’t clear what is the difference between these GtkListStore and GtkTreeStore and; what is “view”. Python (GTK) : Can someone explain the difference between TreeStore, Listmodel and all the rest? was a good one. Then I found The Model/View/Controller design which gave me some general idea.

For this let’s create a phone-book.py/phone-book.ui example. It took me a while to make this working since existing examples usually don’t use Glade nor Gtk.Template.

You place GtkTreeView under the “Display” button to the desired window box. Then click on pen-icon in the “TreeView Model:” entry on the right side panel, and select “New” in the pop-up window. This will fill “TreeView Model:” entry box with “liststore1”.

The Glade screen

Then you select newly created “liststore1” object on the left side panel. You can set types of data for each column and initial data to be filled-in. Since column header is represented as comment in XML, these seems to be just placeholders.

The Glade screen

The rest of operations are pretty much routines.

Example: GtkTreeView (Phone book)

Now we are ready to use this Glade origin header bar widget from simple3.py by header = Gtk.Template.Child():

import gi

gi.require_version("Gtk", "3.0")
from gi.repository import Gtk
from gi.repository import Pango
import sys

# columns are not in XML so only these are used
columns = ["First Name",
           "Last Name",
           "Phone Number"]

# data are in XML so this goes after existing ones
phonebook = [["Jurg", "Billeter", "555-0123"],
             ["Johannes", "Schmid", "555-1234"],
             ["Julita", "Inca", "555-2345"],
             ["Javier", "Jardon", "555-3456"],
             ["Jason", "Clinton", "555-4567"],
             ["Random J.", "Hacker", "555-5678"]]

@Gtk.Template(filename="phone-book.ui")
class SimpleWindow(Gtk.Window):

    # corresponding name in XML 'class' attribute for this class
    __gtype_name__ = "phone_book"
    # corresponding name in XML 'id' attribute sets this class member variable
    liststore1 = Gtk.Template.Child() # MODEL
    treeview = Gtk.Template.Child()   # VIEW
    label = Gtk.Template.Child()

    def __init__(self):
        super().__init__()
        # initialize MODEL by row (append)
        for phonedata in phonebook:
            self.liststore1.append(phonedata)

        # treeview VIEW is linked to liststore1 MODEL
        # treeview VIEW lacks renderer
        for i, column in enumerate(columns):
            renderer_text = Gtk.CellRendererText()
            # 0-th column in MODEL should be in boldface
            if i == 0:
                renderer_text.props.weight_set = True
                renderer_text.props.weight = Pango.Weight.BOLD
            # create a view_col for i-th column in MODEL
            view_col = Gtk.TreeViewColumn(title=column, cell_renderer=renderer_text, text=i)
            # append view_col to VIEW
            self.treeview.append_column(view_col)

    @Gtk.Template.Callback()
    def onDestroy(self, *args):
        Gtk.main_quit()

    @Gtk.Template.Callback()
    def onChanged(self, selection):
        # get MODEL and the iterator that points at the data in MODEL
        (model, iter) = selection.get_selected()
        # set the label to a new value depending on the selection
        self.label.set_text("{} {} --> Phone: {}".format(model[iter][0],  model[iter][1], model[iter][2]))
        return True

window = SimpleWindow()
window.show()
Gtk.main()

Running this with python3 phone-book.py will start the GUI as:

Run simple3

Please play with this GUI to see label get updated as you select listed item..

How Glade generated XML looks

Just in case I forget which items were selected via Glade session, here is the Glade generated XML simple3.ui:

<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.38.2 -->
<interface>
  <requires lib="gtk+" version="3.24"/>
  <object class="GtkListStore" id="liststore1">
    <columns>
      <!-- column-name name -->
      <column type="gchararray"/>
      <!-- column-name surname -->
      <column type="gchararray"/>
      <!-- column-name phonenumber -->
      <column type="gchararray"/>
    </columns>
    <data>
      <row>
        <col id="0" translatable="yes">John</col>
        <col id="1" translatable="yes">Doe</col>
        <col id="2" translatable="yes">911</col>
      </row>
      <row>
        <col id="0" translatable="yes">Call</col>
        <col id="1" translatable="yes">Me</col>
        <col id="2" translatable="yes">411</col>
      </row>
    </data>
  </object>
  <template class="phone_book" parent="GtkWindow">
    <property name="can-focus">False</property>
    <signal name="destroy" handler="onDestroy" swapped="no"/>
    <child>
      <object class="GtkBox">
        <property name="visible">True</property>
        <property name="can-focus">False</property>
        <property name="orientation">vertical</property>
        <property name="baseline-position">top</property>
        <child>
          <object class="GtkTreeView" id="treeview">
            <property name="name">view</property>
            <property name="visible">True</property>
            <property name="can-focus">True</property>
            <property name="model">liststore1</property>
            <child internal-child="selection">
              <object class="GtkTreeSelection" id="treeselect">
                <signal name="changed" handler="onChanged" swapped="no"/>
              </object>
            </child>
          </object>
          <packing>
            <property name="expand">False</property>
            <property name="fill">True</property>
            <property name="position">0</property>
          </packing>
        </child>
        <child>
          <object class="GtkLabel" id="label">
            <property name="visible">True</property>
            <property name="can-focus">False</property>
          </object>
          <packing>
            <property name="expand">False</property>
            <property name="fill">True</property>
            <property name="position">1</property>
          </packing>
        </child>
      </object>
    </child>
  </template>
</interface>

For adding capability to sort by column and filter, you can follow The Python GTK+ 3 Tutorial: 13. Tree and List Widgets.

Previous Post Top Next Post