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.
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
TreeIters 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:
Each of the columns in the windows can be clicked to change the
sort order independent of the other windows. When the "" 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.
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:
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.TreeStore.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.
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.