Chapter 14. Tree View Widget

Table of Contents

14.1. Overview
14.2. The TreeModel Interface and Data Stores
14.2.1. Introduction
14.2.2. Creating TreeStore and ListStore Objects
14.2.3. Referring to TreeModel Rows
14.2.4. Adding Rows
14.2.5. Removing Rows
14.2.6. Managing Row Data
14.2.7. Python Protocol Support
14.2.8. TreeModel Signals
14.2.9. Sorting TreeModel Rows
14.3. TreeViews
14.3.1. Creating a TreeView
14.3.2. Getting and Setting the TreeView Model
14.3.3. Setting TreeView Properties
14.4. CellRenderers
14.4.1. Overview
14.4.2. CellRenderer Types
14.4.3. CellRenderer Properties
14.4.4. CellRenderer Attributes
14.4.5. Cell Data Function
14.4.6. CellRendererText Markup
14.4.7. Editable Text Cells
14.4.8. Activatable Toggle Cells
14.4.9. Editable and Activatable Cell Example Program
14.5. TreeViewColumns
14.5.1. Creating TreeViewColumns
14.5.2. Managing CellRenderers
14.6. Manipulating TreeViews
14.6.1. Managing Columns
14.6.2. Expanding and Collapsing Child Rows
14.7. TreeView Signals
14.8. TreeSelections
14.8.1. Getting the TreeSelection
14.8.2. TreeSelection Modes
14.8.3. Retrieving the Selection
14.8.4. Using a TreeSelection Function
14.8.5. Selecting and Unselecting Rows
14.9. TreeView Drag and Drop
14.9.1. Drag and Drop Reordering
14.9.2. External Drag and Drop
14.9.3. TreeView Drag and Drop Example
14.10. TreeModelSort and TreeModelFilter
14.10.1. TreeModelSort
14.10.2. TreeModelFilter
14.11. The Generic TreeModel
14.11.1. GenericTreeModel Overview
14.11.2. The GenericTreeModel Interface
14.11.3. Adding and Removing Rows
14.11.4. Memory Management
14.11.5. Other Interfaces
14.11.6. Applying The GenericTreeModel
14.12. The Generic CellRenderer

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:

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 TreeViewColumns 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 TreeViewColumns are created and inserted in the TreeView. Each of these will present a single display column.
  • For each TreeViewColumn one or more CellRenderers 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

Basic TreeView Example Program

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