14.10. TreeModelSort and TreeModelFilter
Prev | Chapter 14. Tree View Widget | Next

## 14.10. TreeModelSort and TreeModelFilter

The `TreeModelSort` and `TreeModelFilter` objects are tree models that interpose between the base `TreeModel` (either a `TreeStore` or a `ListStore`) and the `TreeView` to provide a modified model while still retaining the original structure of the base model. These interposing models implement the `TreeModel` and `TreeSortable` interfaces but do not provide any methods for inserting or removing rows in the model; you have to insert or remove rows from the underlying store. The `TreeModelSort` provides a model where the rows are always sorted while the `TreeModelFilter` provides a model containing a subset of the rows of the base model.

These models can be chained to an arbitrary length if desired; i.e a `TreeModelFilter` could have a child `TreeModelSort` that could have a child `TreeModelFilter`, and so on. As long as there is a `TreeStore` or `ListStore` as the anchor of the chain it should just work. In PyGTK 2.0 and 2.2 the `TreeModelSort` and `TreeModelFilter` objects do not support the `TreeModel` Python mapping protocol.

### 14.10.1. TreeModelSort

The `TreeModelSort` maintains a sorted model of the child model specified in its constructor. The main use of a `TreeModelSort` is to provide multiple views of a model that can be sorted differently. If you have multiple views of the same model then any sorting activity is reflected in all the views. By using the `TreeModelSort` the base store is left in its original unsorted state and the sort models absorb all the sorting activity. To create a `TreeModelSort` use the constructor:

      treemodelsort = gtk.TreeModelSort(child_model)

where `child_model` is a `TreeModel`. Most of the methods of a `TreeModelSort` deal with converting tree paths and `TreeIter`s from the child model to the sorted model and back:

      sorted_path = treemodelsort.convert_child_path_to_path(child_path)
      child_path = treemodelsort.convert_path_to_child_path(sorted_path)

These path conversion methods return `None` if the given path cannot be converted to a path in the sorted model or the child model respectively. The `TreeIter` conversion methods are:

      sorted_iter = treemodelsort.convert_child_iter_to_iter(sorted_iter, child_iter)
     child_iter = treemodelsort.convert_iter_to_child_iter(child_iter, sorted_iter)

The `TreeIter` conversion methods duplicate the converted argument (its both the return value and the first argument) due to backward compatibility issues; you should set the first arguments to `None` and just use the return value. For example:

      sorted_iter = treemodelsort.convert_child_iter_to_iter(None, child_iter)
      child_iter = treemodelsort.convert_iter_to_child_iter(None, sorted_iter)

Like the path conversion methods, these methods return `None` if the given `TreeIter` cannot be converted.

You can retrieve the child `TreeModel` using the `get_model`() method.

A simple example program using `TreeModelSort` objects is treemodelsort.py. Figure 14.9, “TreeModelSort Example” illustrates the result of running the program and adding six rows:

Figure 14.9. TreeModelSort Example

Each of the columns in the windows can be clicked to change the sort order independent of the other windows. When the "Add a Row" button is clicked a new row is added to the base `ListStore` and the new row is displayed in each `TreeView` as the selected row.

### 14.10.2. TreeModelFilter

### Note

The `TreeModelFilter` is available in PyGTK 2.4 and above.

A `TreeModelFilter` object provides several ways of modifying the view of the base `TreeModel` including:

- displaying a subset of the rows in the child model either based on boolean data in a "visible column", or based on the boolean return value of a "visible function" that takes the child model, a `TreeIter` pointing at a row in the child model and user data. In both cases if the boolean value is `TRUE` the row will be displayed; otherwise, the row will be hidden.
- using a virtual root node to provide a view of a subtree of the children of a row in the child model. This only makes sense if the underlying store is a `TreeStore`.
- synthesizing the columns and data of a model based on the data in the child model. For example, you can provide a column where the data is calculated from data in several child model columns.

A `TreeModelFilter` object is created using the `TreeModel` method:

      treemodelfilter = treemodel.filter_new(root=None)

where `root` is a tree path in `treemodel` specifying the virtual root for the model or `None` if the root node of `treemodel` is to be used.

By setting a "virtual root" when creating the `TreeModelFilter`, you can limit the model view to the child rows of "root" row in the child model hierarchy. This, of course is only useful when the child model is based on a `TreeStore`. For example, you might want to provide a view of the parts list that makes up a CDROM drive separate from the full parts list of a computer.

The visibility modes are mutually exclusive and can only be set once i.e. once a visibility function or column is set it cannot be changed and the alternative mode cannot be set. The simplest visibility mode extracts a boolean value from a column in the child model to determine if the row should be displayed. The visibility columns is set using:

      treemodelfilter.set_visible_column(column)

where `column` is the number of the column in the child `TreeModel` to extract the boolean values from. For example, the following code fragment uses the values in the third column to set the visibility of the rows:

      ...
      treestore = gtk.TreeStore(str, str, "gboolean")
      ...
      modelfilter = treestore.filter_new()
      modelfilter.set_visible_column(2)
      ...

Thus any rows in `treestore` that have a value of `TRUE` in the third column will be displayed.

If you have more complicated visibility criteria setting a visibility function should provide sufficient power:

      treemodelfilter.set_visible_func(func, data=None)

where `func` is the function called for each child model row to determine if it should be displayed and `data` is user data passed to `func`. `func` should return `TRUE` if the row should be displayed. The signature of `func` is:

      def func(model, iter, user_data)

where `model` is the child `TreeModel`, `iter` is a `TreeIter` pointing at a row in `model` and `user_data` is the passed in `data`.

If you make a change to the visibility criteria you should call:

      treemodelfilter.refilter()

to force a refiltering of the child model rows.

For example, the following code fragment illustrates a `TreeModelFilter` that displays rows based on a comparison between the value in the third column and the contents of the user data:

      ...
      def match_type(model, iter, udata):
          value = model.get_value(iter, 2)
          return value in udata
      ...
      show_vals = ['OPEN', 'NEW', 'RESO']
      liststore = gtk.ListStore(str, str, str)
      ...
      modelfilter = liststore.filter_new()
      modelfilter.set_visible_func(match_type, show_vals)
      ...

The program treemodelfilter.py illustrates the use of the `set_visible_func`() method. Figure 14.10, “TreeModelFilter Visibility Example” shows the result of running the program.

Figure 14.10. TreeModelFilter Visibility Example

By toggling the buttons at the bottom the contents of the `TreeView` are changed to display only the rows that match one of the active buttons.

A modify function gives you another level of control over the `TreeView` display to the point where you can synthesize one or more (or even all) columns that are represented by the `TreeModelFilter`. You still have to use a base child model that is a `TreeStore` or `ListStore` to determine the number of rows and the hierarchy but the columns can be anything you specify in the method:

      treemodelfilter.set_modify_func(types, func, data=None)

where `types` is a sequence (list or tuple) specifying the column types being represented, `func` is a function called to return the value for a row and column and `data` is an argument to be passed to `func`. The signature of `func` is:

      def func(model, iter, column, user_data)

where `model` is the `TreeModelFilter`, `iter` is a `TreeIter` that points to a row in model, `column` is the number of the column that a value is needed for and `user_data` is the parameter `data`. `func` must return a value matching the type for `column`.

A modify function is useful where you want to provide a column of data that needs to be generated using the data in the child model columns. For example if you had a column containing birth dates and wanted to provide a column displaying ages, a modify function could generate the age information using the birth date and the current date. Another example would be to decide what image to display based on some analysis of the data (say, a filename) in a column. This effect can also be achieved using the `TreeViewColumn` `set_cell_data_func`() method.

Usually within the modify function, you will have to convert the `TreeModelFilter` `TreeIter` to a `TreeIter` in the child model using:

      child_iter = treemodelfilter.convert_iter_to_child_iter(filter_iter)

Of course, you'll also need to retrieve the child model using:

      child_model = treemodelfilter.get_model()

These give you access to the child model row and its values for generating the value for the specified `TreeModelFilter` row and column. There's also a method to convert a child `TreeIter` to a filter model `TreeIter` and methods to convert filter model paths to and from child tree paths:

      filter_iter = treemodelfilter.convert_child_iter_to_iter(child_iter)

      child_path = treemodelfilter.convert_path_to_child_path(filter_path)
      filter_path = treemodelfilter.convert_child_path_to_path(child_path)

Of course, you can combine the visibility modes and the modify function to both filter rows and synthesize columns. To get even more control over the view you would have to use a custom `TreeModel`.

Prev | Up | Next
14.9. TreeView Drag and Drop | Home | 14.11. The Generic TreeModel