Data view

Deutsch   |   Source

Display TreeStore data

(Continuation of the ListStore article)

/images/12_treestore.thumbnail.png

TreeStore vs. ListStore

In contrast to ListStores TreeStore rows can possess child rows. That's why the append function requires another parameter that specifies the parent row reference:

#append row to liststore
store.append([value1,value2,value3])

#append row to treestore
store.append(parent,[value1,value2,value3])

The parent value is either

  • None if the current row is not a child row of another, or
  • TreeIter pointing to the superordinate row.

The TreeIter value is generated when creating a row, subordinate rows are created by

row1 = store.append(None,[value1,value2,value3])
row2 = store.append(row1,[value1,value2,value3])

The TreeIter of a cell is obtained by calling the get_selection function of the automatically generated GtkTreeSelection widget.

Glade

In the example there are two TreeStores with some columns and the coresponding TreeView widgets to display the data columns.

TreeModelSort

Sorting a column is set by calling set_sort_column_id. If this is applied to the TreeStore all TreeView widgets using this store are equally sorted.

If this behaviour is not diesired TreeModelSort elements come into play and which are "interposed" between store and view widgets. First the TreeModelSort is created via "Miscellaneous > Tree Model Sort" from the widget sidebar. Then you choose a source TreeView to use data from. After that the model in the TreeView widget is replaced by the newly created TreeModelSort.

The sort function is now simply applied to the TreeModelSort object instead to the TreeView object.

TreeModelFilter

TreeModelFilter allows to only show data that matches the specified filter criteria. Handling this object is analogue to TreeModelSort.

In the example the varieties can be filtered according to fruit colour so there is a GtkButtonBox required to put the corresponding buttons into.

Load formatting values from the model

Besides the columns containing displayed data there is a "weight" column in the first TreeStore. This value is used to show the cell in bold text. It is realized by setting the CellRenderer's property of "Font weight" to the column containing the corresponding value (normal font is 400). In this way the appearance of cells can be defined, for example colours or font formating.

Python

TreeModelSort

Requesting a position by calling GtkTreeSelection.get_selected() returns a tuple (model, pos), pos of model points to TreeModelSort (or TreeModelFilter) and requires conversion to the TreeStore position:

model,pos = selection.get_selected()
converted_iter = treesort.convert_iter_to_child_iter(pos)
store.set_value(converted_iter,column,value)

TreeModelFilter

First of all a filter function is required defining the visibility of cells, in the example it's the variable self.color:

def color_filter_func(self,model,iter,data):
    if model[iter][2] == self.color:
        return True
    else:
        return False

This function has to be assigned to TreeFilter

treefilter.set_visible_func(filter_func)

A filter process is then executed by calling the refilter() function on the TreeFilter object:

def on_button_clicked(self,widget):
    x.color = widget.get_label()
    x.obj("treefilter").refilter()

Listings

Glade

12_treestore.glade (Source)

<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.20.0 -->
<interface>
  <requires lib="gtk+" version="3.20"/>
  <object class="GtkTreeStore" id="filterstore">
    <columns>
      <!-- column-name var -->
      <column type="gchararray"/>
      <!-- column-name spec -->
      <column type="gchararray"/>
      <!-- column-name color -->
      <column type="gchararray"/>
    </columns>
  </object>
  <object class="GtkTreeModelFilter" id="treefilter">
    <property name="child_model">filterstore</property>
  </object>
  <object class="GtkTreeStore" id="store">
    <columns>
      <!-- column-name name -->
      <column type="gchararray"/>
      <!-- column-name spec -->
      <column type="gchararray"/>
      <!-- column-name color -->
      <column type="gchararray"/>
      <!-- column-name note -->
      <column type="gchararray"/>
      <!-- column-name weight -->
      <column type="gint"/>
      <!-- column-name counter -->
      <column type="gint"/>
    </columns>
  </object>
  <object class="GtkTreeModelSort" id="treesort">
    <property name="model">store</property>
  </object>
  <object class="GtkApplicationWindow" id="window">
    <property name="width_request">600</property>
    <property name="height_request">500</property>
    <property name="can_focus">False</property>
    <property name="title" translatable="yes">Titel</property>
    <signal name="destroy" handler="on_window_destroy" swapped="no"/>
    <child>
      <object class="GtkBox" id="box">
        <property name="visible">True</property>
        <property name="can_focus">False</property>
        <property name="orientation">vertical</property>
        <property name="spacing">12</property>
        <property name="homogeneous">True</property>
        <child>
          <object class="GtkScrolledWindow">
            <property name="visible">True</property>
            <property name="can_focus">True</property>
            <property name="shadow_type">in</property>
            <child>
              <object class="GtkTreeView" id="view">
                <property name="visible">True</property>
                <property name="can_focus">True</property>
                <property name="model">treesort</property>
                <property name="headers_clickable">False</property>
                <property name="rules_hint">True</property>
                <child internal-child="selection">
                  <object class="GtkTreeSelection" id="selection"/>
                </child>
                <child>
                  <object class="GtkTreeViewColumn">
                    <property name="title" translatable="yes">Name</property>
                    <property name="sort_order">descending</property>
                    <property name="sort_column_id">5</property>
                    <child>
                      <object class="GtkCellRendererText"/>
                      <attributes>
                        <attribute name="text">0</attribute>
                        <attribute name="weight">4</attribute>
                      </attributes>
                    </child>
                  </object>
                </child>
                <child>
                  <object class="GtkTreeViewColumn">
                    <property name="title" translatable="yes">Farbe</property>
                    <child>
                      <object class="GtkCellRendererText"/>
                      <attributes>
                        <attribute name="text">2</attribute>
                      </attributes>
                    </child>
                  </object>
                </child>
                <child>
                  <object class="GtkTreeViewColumn">
                    <property name="title" translatable="yes">Bemerkung</property>
                    <child>
                      <object class="GtkCellRendererText" id="cellrenderer_note">
                        <property name="editable">True</property>
                        <signal name="edited" handler="on_cellrenderer_note_edited" swapped="no"/>
                      </object>
                      <attributes>
                        <attribute name="text">3</attribute>
                      </attributes>
                    </child>
                  </object>
                </child>
              </object>
            </child>
          </object>
          <packing>
            <property name="expand">False</property>
            <property name="fill">True</property>
            <property name="position">0</property>
          </packing>
        </child>
        <child>
          <object class="GtkBox">
            <property name="visible">True</property>
            <property name="can_focus">False</property>
            <child>
              <object class="GtkScrolledWindow">
                <property name="visible">True</property>
                <property name="can_focus">True</property>
                <property name="shadow_type">in</property>
                <property name="propagate_natural_width">True</property>
                <child>
                  <object class="GtkTreeView">
                    <property name="visible">True</property>
                    <property name="can_focus">True</property>
                    <property name="model">treefilter</property>
                    <child internal-child="selection">
                      <object class="GtkTreeSelection"/>
                    </child>
                    <child>
                      <object class="GtkTreeViewColumn">
                        <property name="title" translatable="yes">Sorte</property>
                        <child>
                          <object class="GtkCellRendererText"/>
                          <attributes>
                            <attribute name="text">0</attribute>
                          </attributes>
                        </child>
                      </object>
                    </child>
                    <child>
                      <object class="GtkTreeViewColumn">
                        <property name="title" translatable="yes">Art</property>
                        <child>
                          <object class="GtkCellRendererText"/>
                          <attributes>
                            <attribute name="text">1</attribute>
                          </attributes>
                        </child>
                      </object>
                    </child>
                  </object>
                </child>
              </object>
              <packing>
                <property name="expand">True</property>
                <property name="fill">True</property>
                <property name="position">0</property>
              </packing>
            </child>
            <child>
              <object class="GtkButtonBox" id="buttonbox">
                <property name="visible">True</property>
                <property name="can_focus">False</property>
                <property name="orientation">vertical</property>
                <property name="layout_style">start</property>
                <child>
                  <placeholder/>
                </child>
              </object>
              <packing>
                <property name="expand">False</property>
                <property name="fill">True</property>
                <property name="padding">5</property>
                <property name="pack_type">end</property>
                <property name="position">1</property>
              </packing>
            </child>
          </object>
          <packing>
            <property name="expand">False</property>
            <property name="fill">True</property>
            <property name="position">2</property>
          </packing>
        </child>
      </object>
    </child>
    <child type="titlebar">
      <placeholder/>
    </child>
  </object>
</interface>

Python

12_treestore.py (Source)

#!/usr/bin/python
# -*- coding: utf-8 -*-

import gi
gi.require_version('Gtk','3.0')
from gi.repository import Gtk

class Handler:

    def on_window_destroy(self,*args):
        Gtk.main_quit()

    def on_button_clicked(self,widget):
        x.color = widget.get_label()
        x.obj("treefilter").refilter()

    def on_cellrenderer_note_edited(self,widget,row,edit):
        model,pos = x.obj("selection").get_selected()
        conv_iter = x.obj("treesort").convert_iter_to_child_iter(pos)
        x.obj("store").set_value(conv_iter,3,edit)

class Example:

    def __init__(self):

        self.builder = Gtk.Builder()
        self.builder.add_from_file("12_treestore.glade")
        self.builder.connect_signals(Handler())
        self.obj = self.builder.get_object

        #read data from text file
        with open("12_capsicum.txt") as f:
            data = [line.strip("\n") for line in f]

        colors = set()
        species = set()
        varieties = []
        for line in data:
            variety = line.split(";")
            colors.add(variety[2])
            species.add(variety[1])
            try:
                variety[3]
            except IndexError:
                variety.append("")
            varieties.append(variety)

        #append lines to 1st treestore
        for s in species:
            counter = 0
            row = self.obj("store").append(None,[None,None,None,None,800,None])
            for v in varieties:
                if v[1] == s:
                    self.obj("store").append(row,[v[0],v[1],v[2],v[3],400,None])
                    counter += 1
            self.obj("store").set_value(row,0,"%s (%d)" % (s,counter))
            self.obj("store").set_value(row,5,counter)

        #append lines to 2nd treestore
        [self.obj("filterstore").append(None,[v[0],v[1],v[2]]) for v in varieties]

        #create buttons in buttonbox
        for c in colors:
            button = Gtk.Button.new_with_label(c)
            button.connect("clicked",Handler().on_button_clicked)
            self.obj("buttonbox").add(button)

        self.obj("view").expand_all()
        self.obj("treesort").set_sort_column_id(5, Gtk.SortType.DESCENDING)
        self.obj("treefilter").set_visible_func(self.color_filter_func)
        self.obj("window").show_all()

    def color_filter_func(self,model,iter,data):
        if model[iter][2] == self.color:
            return True
        else:
            return False

    def main(self):
        Gtk.main()

x = Example()
x.main()
Comments powered by Disqus