Site Overlay

pyGTK – TreeView model with both filter and sort features

For someone who wants to write adminstrative office software that communicates with a database in the background, Gtk’s TreeView object is probably one of the most interesting widgets. Unfortunately, with its versatile features, it is also more challenging to program and there is hardly any documentation with hands-on examples. One problem I got stuck with for a while is that there are code examples for sorting functions and there are code examples for filters. But there is little Python code out there to produce a TreeView featuring both filtering and sorting the data displayed at the same time.

1. The Problem

The usual point of departure to get acquainted with TreeViews is probably the readthedocs.io turoial on TreeViews. The (complete) coding example included produces a TreeView that allows to filter a store but cannot sort the data displayed.

Now how should we amend the code in case we would like to add sortable columns on top of the language filter?

According to the documentation, a sorting feature for a column can be added by issuing a set_sort_column_id() method call to the TreeViewColumn object before appending it to the TreeView:

The integer argument passed to the set_sort_column(int) method call refers to the column number in the ListStore model.

This works fine if there is no filter at the same time as can be seen in the following youtube demonstration. In case the TreeView also includes filtering functionality, though, clicking on the column will have no visible effect. Instead, GTK’s Python wrapper will issue a couple of warnings at the Eclipse IDE Console:

I found the solution to this problem in a discussion on stackoverflow:

The idea is to stack a ListStore, a TreeModelFilter and a TreeSortFilter one inside the other and feed the last one as the model for the treeview.

2. Solution

So we will do as suggested, here’s the recipe:

  • Start creating the ListStore using the Gtk.ListStore() constructor and append all entries.
  • Create a TreeModelFilter object connected to the ListStore using the filter_new() method. Link it to a custom filter function that governs the filtering process when one of the filter buttons is clicked. To that purpose, create an instance variable that is later read by the custom filter function and set by the filtering buttons.
  • Now comes the new part: We create an instance of the TreeModelSortclass. We will pass the TreeModelFilter object from the pevious step as an argument to the TreeModelSortconstructor.
  • We will finally create an instance of our TreeView class and then connect it to the TreeModelSort object from the previous by sending the set_model() message to the TreeView object.
  • Produce TreeViewColumn objects to form the columns of the TreeView. Use the set_sort_column_id to determine which column should be sortable according to which data in the ListStore.

The following sections show the detailed steps:

2.1 Create the ListStore and populate it with data

We start with preparing the ListStore, no big suprises here:

2.2 Create a TreeModelFilter and prepare its connection to the filtering function

Note that the filtering function is defined later inside the same class. For the moment, it’s enough to create an instance of TreeModelFilter and to specify the name of the function which is later used to do the filtering.

Keep in mind that the filter_new()method returns a filter object that can be used on the softwareListStore. So the instance variable language_filter holds an object of  TreeModelFilter.

2.3 Create a TreeModelSortobject from the TreeModelFilterobject

This is going to be the additional part that really makes the difference. In the reathedocs example, we would take the TreeModelFilter object and directly produce  a TreeView object. But instead we will now take the TreeModelFilter object and first produce a TreeModelSortobject from it. – No sorting without a TreeModelSort object!

Note that the sorted_and_filtered_model instance variable holds an object of type TreeModelSort but now also allows not only sorting but filtering because its constructor was called with a TreeModelFilter object as an argument.

2.4 Set the TreeView‘s underlying model to the TreeModelSort object

While in the standard example the underlying model has been set in one shot by adding it as an argument to the TreeView constructor call, we will do that in 2 steps now. First construct, then set the model:

2.5 Create sortable TreeViewColumn objects for the TreeView

The final step is to create the TreeViewColumn object that should constitute the TreeView. The only new thing as compared to the basic example from readthedocs is that now that we have an underlying model of TreeModelSort, we can safely use the set_sort_column_id() method on each column object.

3. Complete code

Here’s the complete code for our extended example: