Chapter 14. Tree View Widget
Prev |  | Next

## Chapter 14. Tree View Widget

The `TreeView` widget displays lists and trees displaying multiple columns. It replaces the previous set of List, `CList`, `Tree` and `CTree` widgets with a much more powerful and flexible set of objects that use the Model-View-Controller (MVC) principle to provide the following features:

- two pre-defined models: one for lists and one for trees
- multiple views of the same model are automatically updated when the model changes
- selective display of the model data
- use of model data to customize the TreeView display on a row-by-row basis
- pre-defined data rendering objects for displaying text, images and boolean data
- stackable models for providing sorted and filtered views of the underlying model data
- reorderable and resizeable columns
- automatic sort by clicking column headers
- drag and drop support
- support for custom models entirely written in Python
- support for custom cell renderers entirely written in Python

Of course, all this capability comes at the price of a significantly more complex set of objects and interfaces that appear overwhelming at first. In the rest of this chapter we'll explore the TreeView objects and interfaces to reach an understanding of common usage. The more esoteric aspects, you'll have to explore on your own.

We'll start with a quick overview tour of the objects and interfaces and then dive into the `TreeModel` interface and the predefined `ListStore` and `TreeStore` classes.

## 14.1. Overview

A `TreeView` widget is the user interface object that displays the data stored in an object that implements the `TreeModel` interface. Two base tree model classes are provided in PyGTK 2.0:

- the `TreeStore` that provides hierarchical data storage organized as tree rows with columnar data. Each tree row can have zero or more child rows. All rows must have the same number of columns.
- the `ListStore` that provides tabular data storage organized in rows and columns similar to a table in a relational database. The `ListStore` is really a simplified version of a `TreeStore` where the rows have no children. It has been created to provide a simpler (and presumably more efficient) interface to this common data model. And,

The two additional tree models stack on top of (or interpose on) the base models:

- the `TreeModelSort` that provides a model where the data of the underlying tree model is maintained in a sorted order. And,
- the `TreeModelFilter` that provides a model containing a subset of the data in the underlying model. Note this model is available only in PyGTK 2.4 and above.

A `TreeView` displays all of the rows of a `TreeModel` but may display only some of the columns. Also the columns may be presented in a different order than the `TreeModel` stores them.

The `TreeView` uses `TreeViewColumn` objects to organize the display of the columnar data. Each `TreeViewColumn` displays one column with an optional header that may contain the data from several `TreeModel` columns. The individual `TreeViewColumn`s are packed (similar to `HBox` containers) with `CellRenderer` objects to render the display of the associated data from a `TreeModel` row and column location. There are three predefined `CellRenderer` classes:

- the `CellRendererPixbuf` that renders a pixbuf image into the cells of a `TreeViewColumn`.
- the `CellRendererText` that renders a string into the cells of a `TreeViewColumn`. It will convert the column data to a string format if needed i.e. if displaying a model column containing float data, the `CellRendererText` will convert it to a string before rendering it.
- the `CellRendererToggle` that renders a boolean value as a toggle button into the cells of a `TreeViewColumn`.

A `TreeViewColumn` can contain several `CellRenderer` objects to provide a column that, for example, may have an image and text packed together.

Finally, the `TreeIter`, `TreeRowReference` and `TreeSelection` objects provide a transient pointer to a row in a `TreeModel`, a persistent pointer to a row in a `TreeModel` and an object managing the selections in a `TreeView`.

A `TreeView` display is composed using the following general operations not necessarily in this order:

- A tree model object is created usually a `ListStore` or `TreeStore` with one or more columns of a specified data type.
- The tree model may be populated with one or more rows of data.
- A `TreeView` widget is created and associated with the tree model.
- One or more `TreeViewColumn`s are created and inserted in the `TreeView`. Each of these will present a single display column.
- For each `TreeViewColumn` one or more `CellRenderer`s are created and added to the `TreeViewColumn`.
- The attributes of each `CellRenderer` are set to indicate from which column of the tree model to retrieve the attribute data. for example the text to be rendered. This allows the `CellRenderer` to render each column in a row differently.
- The `TreeView` is inserted and displayed in a `Window` or `ScrolledWindow`.
- The data in the tree model is manipulated programmatically in response to user actions. The `TreeView` will automatically track the changes.

The example program basictreeview.py illustrates the creation and display of a simple `TreeView`:

        1   #!/usr/bin/env python
        2
        3   # example basictreeview.py
        4
        5   import pygtk
        6   pygtk.require('2.0')
        7   import gtk
        8
        9   class BasicTreeViewExample:
       10
       11       # close the window and quit
       12       def delete_event(self, widget, event, data=None):
       13           gtk.main_quit()
       14           return False
       15
       16       def __init__(self):
       17           # Create a new window
       18           self.window = gtk.Window(gtk.WINDOW_TOPLEVEL)
       19
       20           self.window.set_title("Basic TreeView Example")
       21
       22           self.window.set_size_request(200, 200)
       23
       24           self.window.connect("delete_event", self.delete_event)
       25
       26           # create a TreeStore with one string column to use as the model
       27           self.treestore = gtk.TreeStore(str)
       28
       29           # we'll add some data now - 4 rows with 3 child rows each
       30           for parent in range(4):
       31               piter = self.treestore.append(None, ['parent %i' % parent])
       32               for child in range(3):
       33                   self.treestore.append(piter, ['child %i of parent %i' %
       34                                                 (child, parent)])
       35
       36           # create the TreeView using treestore
       37           self.treeview = gtk.TreeView(self.treestore)
       38
       39           # create the TreeViewColumn to display the data
       40           self.tvcolumn = gtk.TreeViewColumn('Column 0')
       41
       42           # add tvcolumn to treeview
       43           self.treeview.append_column(self.tvcolumn)
       44
       45           # create a CellRendererText to render the data
       46           self.cell = gtk.CellRendererText()
       47
       48           # add the cell to the tvcolumn and allow it to expand
       49           self.tvcolumn.pack_start(self.cell, True)
       50
       51           # set the cell "text" attribute to column 0 - retrieve text
       52           # from that column in treestore
       53           self.tvcolumn.add_attribute(self.cell, 'text', 0)
       54
       55           # make it searchable
       56           self.treeview.set_search_column(0)
       57
       58           # Allow sorting on the column
       59           self.tvcolumn.set_sort_column_id(0)
       60
       61           # Allow drag and drop reordering of rows
       62           self.treeview.set_reorderable(True)
       63
       64           self.window.add(self.treeview)
       65
       66           self.window.show_all()
       67
       68   def main():
       69       gtk.main()
       70
       71   if __name__ == "__main__":
       72       tvexample = BasicTreeViewExample()
       73       main()

In real programs the `TreeStore` would likely be populated with data after the `TreeView` is displayed due to some user action. We'll look at the details of the `TreeView` interfaces in more detail in the sections to come. Figure 14.1, “Basic TreeView Example Program” shows the window created by the basictreeview.py program after a couple of parent rows have been expanded.

Figure 14.1. Basic TreeView Example Program

Next let's examine the `TreeModel` interface and the models that implement it.

Prev | Up | Next
13.7. A TextView Example | Home | 14.2. The TreeModel Interface and Data Stores