14.2. The TreeModel Interface and Data Stores
Prev | Chapter 14. Tree View Widget | Next

## 14.2. The TreeModel Interface and Data Stores

### 14.2.1. Introduction

The `TreeModel` interface is implemented by all the `TreeModel` subclasses and provides methods to:

- retrieve the characteristics of the data store such as the number of columns and the type of data in a column.
- retrieve a `TreeIter` (a transient reference) that points at a row in the model
- retrieve information about a node (or row) such as the number of its child nodes, a list of its child nodes, the contents of its columns and a pointer to its parent node
- provide notification of `TreeModel` data changes

### 14.2.2. Creating TreeStore and ListStore Objects

The base data store classes: `ListStore` and `TreeStore` provide the means to define and manage the rows and columns of data in the tree model. The constructors of both these objects require the column types to be specified as any of:

- Python types such as the built-in types: int, str, long, float and object
- PyGTK types such as `Button`, `VBox`, `gdk.Rectangle`, `gdk.Pixbuf`

- `GObject` types (GTK+ GTypes) specified either as GObject Type constants or as strings. Most GTypes are mapped to a Python type:

  - gobject.TYPE_CHAR or 'gchar'
  - gobject.TYPE_UCHAR or 'guchar'
  - gobject.TYPE_BOOLEAN or 'gboolean'
  - gobject.TYPE_INT or 'gint'
  - gobject.TYPE_UINT or 'guint'
  - gobject.TYPE_LONG or 'glong
  - gobject.TYPE_ULONG or 'gulong
  - gobject.TYPE_INT64 or 'gint64'
  - gobject.TYPE_UINT64 or 'guint64'
  - gobject.TYPE_FLOAT or 'gfloat'
  - gobject.TYPE_DOUBLE or 'gdouble'
  - gobject.TYPE_STRING or 'gchararray'
  - gobject.TYPE_OBJECT or 'GObject

For example to create a `ListStore` or `TreeStore` with rows containing a `gdk.Pixbuf`, an integer, a string and boolean you could do something like:

      liststore = ListStore(gtk.gdk.Pixbuf, int, str, 'gboolean')

      treestore = TreeStore(gtk.gdk.Pixbuf, int, str, 'gboolean')

Once a `ListStore` or `TreeStore` is created and its columns defined, they cannot be changed or modified. It's also important to realize that there is no preset relation between the columns in a `TreeView` and the columns of its `TreeModel`. That is, the fifth column of data in a `TreeModel` may be displayed in the first column of one `TreeView` and in the third column in another. So you don't have to worry about how the data will be displayed when creating the data store.

If these two data stores do not fit your application it is possible to define your own custom data store in Python as long as it implements the TreeModel interface. I'll talk more about this later in Section 14.11, “The Generic TreeModel”.

### 14.2.3. Referring to TreeModel Rows

Before we can talk about managing the data rows in a `TreeStore` or `ListStore` we need a way of specifying which row we want to deal with. PyGTK has three ways of referring to `TreeModel` rows: a tree path, a `TreeIter` and a `TreeRowReference`.

#### 14.2.3.1. Tree Paths

A tree path is a int, string or tuple representation of the location of a row in the store. An int value specifies the top level row in the model starting from 0. For example, a tree path value of 4 would specify the fifth row in the store. By comparison, a string representation of the same row would be "4" and the tuple representation would be (4,). This is sufficient for specifying any row in a `ListStore` but for a TreeStore we have to be able to represent the child rows. For these cases we have to use either the string or tuple representations.

Since a `TreeStore` can have an arbitrarily deep hierarchy the string representation specifies the path from the top level to the designated row using ints separated by the ":" character. Similarly, the tuple representation specifies the tree path starting from the top level to the row as a sequence of ints. For example, valid tree path string representations are: "0:2" (specifies the row that is the third child of the first row) and "4:0:1" (specifies the row that is the second child of the first child of the fifth row). By comparison the same tree paths are represented by the tuples (0, 2) and (4, 0, 1) respectively.

A tree path provides the only way to map from a `TreeView` row to a `TreeModel` row because the tree path of a `TreeView` row is the same as the tree path of the corresponding `TreeModel` row. There are also some problems with tree paths:

- a tree path can specify a row that doesn't exist in the ListStore or TreeStore.
- a tree path can point to a different data row after inserting or deleting a row in the `ListStore` or `TreeStore`.

PyGTK uses the tuple representation when returning tree paths but will accept any of the three forms for a tree path representation. You should use the tuple representation for a tree path for consistency.

A tree path can be retrieved from a `TreeIter` using the `get_path`() method:

      path = store.get_path(iter)

where `iter` is a `TreeIter` pointing at a row in store and `path` is the row's tree path as a tuple.

#### 14.2.3.2. TreeIters

A `TreeIter` is an object that provides a transient reference to a `ListStore` or `TreeStore` row. If the contents of the store change (usually because a row is added or deleted) the `TreeIter`s can become invalid. A `TreeModel` that supports persistent TreeIters should set the `gtk.TREE_MODEL_ITERS_PERSIST` flag. An application can check for this flag using the `get_flags`() method.

A `TreeIter` is created by one of the `TreeModel` methods that are applicable to both `TreeStore` and `ListStore` objects:

      treeiter = store.get_iter(path)

where `treeiter` points at the row at the tree path `path`. The ValueError exception is raised if the tree path is invalid.

      treeiter = store.get_iter_first()

where `treeiter` is a TreeIter pointing at the row at tree path (0,). `treeiter` will be `None` if the store is empty.

      treeiter = store.iter_next(iter)

where `treeiter` is a `TreeIter` that points at the next row at the same level as the `TreeIter` specified by `iter`. `treeiter` will be `None` if there is no next row (`iter` is also invalidated).

The following methods are useful only for retrieving a `TreeIter` from a `TreeStore`:

      treeiter = treestore.iter_children(parent)

where `treeiter` is a `TreeIter` pointing at the first child row of the row specified by the `TreeIter` `parent`. `treeiter` will be `None` if there is no child.

      treeiter = treestore.iter_nth_child(parent, n)

where `treeiter` is a `TreeIter` pointing at the child row (with the index `n`) of the row specified by the `TreeIter` `parent`. `parent` may be `None` to retrieve a top level row. `treeiter` will be `None` if there is no child.

      treeiter = treestore.iter_parent(child)

where `treeiter` is a `TreeIter` pointing at the parent row of the row specified by the `TreeIter` `child`. treeiter will be `None` if there is no child.

A tree path can be retrieved from a `TreeIter` using the `get_path`() method:

      path = store.get_path(iter)

where `iter` is a `Treeiter` pointing at a row in store and `path` is the row's tree path as a tuple.

#### 14.2.3.3. TreeRowReferences

A `TreeRowReference` is a persistent reference to a row of data in a store. While the tree path (i.e. the location) of the row might change as rows are added to or deleted from the store, the `TreeRowReference` will point at the same data row as long as it exists.

### Note

`TreeRowReference`s are only available in PyGTK 2.4 and above.

You can create a `TreeRowReference` using its constructor:

      treerowref = TreeRowReference(model, path)

where `model` is the `TreeModel` containing the row and `path` is the tree path of the row to track. If `path` isn't a valid tree path for `model`, `None` is returned.

### 14.2.4. Adding Rows

#### 14.2.4.1. Adding Rows to a ListStore

Once you have a `ListStore` you'll need to add data rows using one of the following methods:

      iter = append(row=None)
      iter = prepend(row=None)
      iter = insert(position, row=None)
      iter = insert_before(sibling, row=None)
      iter = insert_after(sibling, row=None)

Each of these methods inserts a row at an implied or specified position in the `ListStore`. The `append`() and `prepend`() methods use implied positions: after the last row and before the first row, respectively. The `insert`() method takes an integer (the parameter `position`) that specifies the location where the row will be inserted. The other two methods take a `TreeIter` (`sibling`) that references a row in the `ListStore` to insert the row before or after.

The `row` parameter specifies the data that should be inserted in the row after it is created. If `row` is `None` or not specified, an empty row will be created. If `row` is specified it must be a tuple or list containing as many items as the number of columns in the `ListStore`. The items must also match the data type of their respective `ListStore` columns.

All methods return a `TreeIter` that points at the newly inserted row. The following code fragment illustrates the creation of a `ListStore` and the addition of data rows to it:

      ...
      liststore = gtk.ListStore(int, str, gtk.gdk.Color)
      liststore.append([0,'red',colormap.alloc_color('red')])
      liststore.append([1,'green',colormap.alloc_color('green')])
      iter = liststore.insert(1, (2,'blue',colormap.alloc_color('blue')) )
      iter = liststore.insert_after(iter, [3,'yellow',colormap.alloc_color('blue')])
      ...

#### 14.2.4.2. Adding Rows to a TreeStore

Adding a row to a `TreeStore` is similar to adding a row to a `ListStore` except that you also have to specify a parent row (using a `TreeIter`) to add the new row to. The `TreeStore` methods are:

      iter = append(parent, row=None)
      iter = prepend(parent, row=None)
      iter = insert(parent, position, row=None)
      iter = insert_before(parent, sibling, row=None)
      iter = insert_after(parent, sibling, row=None)

If `parent` is `None`, the row will be added to the top level rows.

Each of these methods inserts a row at an implied or specified position in the `TreeStore`. The `append`() and `prepend`() methods use implied positions: after the last child row and before the first child row, respectively. The `insert`() method takes an integer (the parameter `position`) that specifies the location where the child row will be inserted. The other two methods take a `TreeIter` (`sibling`) that references a child row in the `TreeStore` to insert the row before or after.

The `row` parameter specifies the data that should be inserted in the row after it is created. If `row` is `None` or not specified, an empty row will be created. If `row` is specified it must be a tuple or list containing as many items as the number of columns in the `TreeStore`. The items must also match the data type of their respective `TreeStore` columns.

All methods return a `TreeIter` that points at the newly inserted row. The following code fragment illustrates the creation of a `TreeStore` and the addition of data rows to it:

      ...
      folderpb = gtk.gdk.pixbuf_from_file('folder.xpm')
      filepb = gtk.gdk.pixbuf_from_file('file.xpm')
      treestore = gtk.TreeStore(int, str, gtk.gdk.Pixbuf)
      iter0 = treestore.append(None, [1,'(0,)',folderpb] )
      treestore.insert(iter0, 0, [11,'(0,0)',filepb])
      treestore.append(iter0, [12,'(0,1)',filepb])
      iter1 = treestore.insert_after(None, iter0, [2,'(1,)',folderpb])
      treestore.insert(iter1, 0, [22,'(1,1)',filepb])
      treestore.prepend(iter1, [21,'(1,0)',filepb])
      ...

#### 14.2.4.3. Large Data Stores

When a `ListStore` or `TreeStore` contains a large number of data rows, adding new rows can become very slow. There are a few things that you can do to mitigate this problem:

- If adding a large number of rows disconnect the `TreeModel` from its `TreeView` (using the `set_model`() method with the `model` parameter set to `None`) to avoid `TreeView` updates for each row entered.
- Likewise, disable sorting (using the `set_default_sort_func`() method with the `sort_func` set to `None`) while adding a large number of rows.
- Limit the number of `TreeRowReference`s in use since they update their path with each addition or removal.
- Set the `TreeView` "fixed-height-mode" property to `TRUE` making all rows have the same height and avoiding the individual calculation of the height of each row. Only available in PyGTK 2.4 and above.

### 14.2.5. Removing Rows

#### 14.2.5.1. Removing Rows From a ListStore

You can remove a data row from a `ListStore` by using the `remove`() method:

      treeiter = liststore.remove(iter)

where `iter` is a `TreeIter` pointing at the row to remove. The returned `TreeIter` (`treeiter`) points at the next row or is invalid if `iter` was pointing at the last row.

The `clear`() method removes all rows from the `ListStore`:

      liststore.clear()

#### 14.2.5.2. Removing Rows From a TreeStore

The methods for removing data rows from a `TreeStore` are similar to the `ListStore` methods:

      result = treestore.remove(iter)
      treestore.clear()

where `result` is `TRUE` if the row was removed and `iter` points at the next valid row. Otherwise, `result` is `FALSE` and `iter` is invalidated.

### 14.2.6. Managing Row Data

#### 14.2.6.1. Setting and Retrieving Data Values

The methods for accessing the data values in a `ListStore` and `TreeStore` have the same format. All store data manipulations use a `TreeIter` to specify the row that you are working with. Once you have a `TreeIter` it can be used to retrieve the values of a row column using the `get_value`() method:

      value = store.get_value(iter, column)

where `iter` is a `TreeIter` pointing at a row, `column` is a column number in `store`, and, `value` is the value stored at the row-column location.

If you want to retrieve the values from multiple columns in one call use the `get`() method:

      values = store.get(iter, column, ...)

where `iter` is a `TreeIter` pointing at a row, `column` is a column number in `store`, and, `...` represents zero or more additional column numbers and `values` is a tuple containing the retrieved data values. For example to retrieve the values in columns 0 and 2:

      val0, val2 = store.get(iter, 0, 2)

### Note

The `get`() method is only available in PyGTK 2.4 and above.

Setting a single column value is effected using the `set_value`() method:

      store.set_value(iter, column, value)

where `iter` (a `TreeIter`) and `column` (an int) specify the row-column location in `store` and `column` is the column number where `value` is to be set. `value` must be the same data type as the `store` column.

If you wish to set the value of more than one column in a row at a time, use the `set`() method:

      store.set(iter, ...)

where `iter` specifies the store row and `...` is one or more column number - value pairs indicating the column and and value to set. For example, the following call:

      store.set(iter, 0, 'Foo', 5, 'Bar', 1, 123)

sets the first column to 'Foo', the sixth column to 'Bar' and the second column to 123 in the `store` row specified by `iter`.

#### 14.2.6.2. Rearranging ListStore Rows

Individual `ListStore` rows can be moved using one of the following methods that are available in PyGTK 2.2 and above:

      liststore.swap(a, b)
      liststore.move_after(iter, position)
      liststore.move_before(iter, position)

`swap`() swaps the locations of the rows referenced by the `TreeIter`s `a` and `b`. `move_after`() and `move_before`() move the row referenced by the `TreeIter` `iter` after or before the row referenced by the `TreeIter` `position`. If `position` is `None`, `move_after`() will place the row at the beginning of the store while `move_before`(), at the end of the store.

If you want to completely rearrange the `ListStore` data rows, use the following method:

      liststore.reorder(new_order)

where `new_order` is a list of integers that specify the new row order as:

      new_order[newpos] = oldpos

For example, if `liststore` contained four rows:

      'one'
      'two'
      'three'
      'four'

The method call:

      liststore.reorder([2, 1, 3, 0])

would produce the resulting order:

      'three'
      'two'
      'four'
      'one'

### Note

These methods will only rearrange unsorted `ListStore`s.

If you want to rearrange rows in PyGTK 2.0 you have to remove and insert rows using the methods described in Section 14.2.4, “Adding Rows” and Section 14.2.5, “Removing Rows”.

#### 14.2.6.3. Rearranging TreeStore Rows

The methods used to rearrange `TreeStore` rows are similar to the `ListStore` methods except they only affect the child rows of an implied parent row - it is not possible to, say, swap rows with different parent rows.:

      treestore.swap(a, b)
      treestore.move_after(iter, position)
      treestore.move_before(iter, position)

`swap`() swaps the locations of the child rows referenced by the TreeIters `a` and `b`. `a` and `b` must both have the same parent row. `move_after`() and `move_before`() move the row referenced by the `TreeIter` `iter` after or before the row referenced by the `TreeIter` `position`. `iter` and `position` must both have the same parent row. If `position` is `None`, `move_after`() will place the row at the beginning of the store while `move_before`(), at the end of the store.

The `reorder`() method requires an additional parameter specifying the parent row whose child rows will be reordered:

      treestore.reorder(parent, new_order)

where `new_order` is a list of integers that specify the new child row order of the parent row specified by the `TreeIter` `parent` as:

      new_order[newpos] = oldpos

For example, if `treestore` contained four rows:

      'parent'
          'one'
          'two'
          'three'
          'four'

The method call:

      treestore.reorder(parent, [2, 1, 3, 0])

would produce the resulting order:

      'parent'
          'three'
          'two'
          'four'
          'one'

### Note

These methods will only rearrange unsorted `TreeStore`s.

#### 14.2.6.4. Managing Multiple Rows

One of the trickier aspects of dealing with `ListStore`s and `TreeStore`s is the operation on multiple rows, e.g. moving multiple rows, say, from one parent row to another or removing rows based on certain criteria. The difficulty arises from the need to use a `TreeIter` that may become invalid as the result of the operation. For `ListStore`s and `TreeStore`s the TreeIters are persistent as can be checked by using the `get_flags`() method and testing for the `gtk.TREE_MODEL_ITERS_PERSIST` flag. However the stackable `TreeModelFilter` and `TreeModelSort` classes do not have persistent `TreeIter`s.

Assuming that `TreeIter`s don't persist how do we move all the child rows from one parent row to another? We have to:

- iterate over the parent's children
- retrieve each row's data
- remove each child row
- insert a new row with the old row data in the new parent's list

We can't rely on the `remove`() method to return a valid `TreeIter` so we'll just ask for the first child iter until it returns `None`. A possible function to move child rows is:

      def move_child_rows(treestore, from_parent, to_parent):
        n_columns = treestore.get_n_columns()
        iter = treestore.iter_children(from_parent)
        while iter:
          values = treestore.get(iter, *range(n_columns))
          treestore.remove(iter)
          treestore.append(to_parent, values)
          iter = treestore.iter_children(from_parent)
        return

The above function covers the simple case of moving all child rows of a single parent row but what if you want to remove all rows in the `TreeStore` based on some match criteria, say the first column value? Here you might think that you could use the `foreach`() method to iterate over all the rows and remove the matching ones:

      store.foreach(func, user_data)

where `func` is a function that is invoked for each store row and has the signature:

      def func(model, path, iter, user_data):

where `model` is the `TreeModel` data store, `path` is the tree path of a row in `model`, `iter` is a `TreeIter` pointing at `path` and `user_data` is the passed in data. if `func` returns `TRUE` the `foreach`() method will cease iterating and return.

The problem with that is that changing the contents of the store while the `foreach`() method is iterating over it may have unpredictable results. Using the `foreach`() method to create and save TreeRowReferences to the rows to be removed and then removing them after the `foreach`() method completes would be a good strategy except that it doesn't work for PyGTK 2.0 and 2.2 where `TreeRowReference`s are not available.

A reliable strategy that covers all the PyGTK variants is to use the `foreach`() method to gather the tree paths of rows to be removed and then remove them in reverse order to preserve the validity of the tree paths. An example code fragment utilizing this strategy is:

      ...
      # match if the value in the first column is >= the passed in value
      # data is a tuple containing the match value and a list to save paths
      def match_value_cb(model, path, iter, data):
        if model.get_value(iter, 0) >= data[0]:
          data[1].append(path)
        return False     # keep the foreach going

      pathlist = []
      treestore.foreach(match_value_cb, (10, pathlist))

      # foreach works in a depth first fashion
      pathlist.reverse()
      for path in pathlist:
        treestore.remove(treestore.get_iter(path))
      ...

If you want to search a `TreeStore` for the first row that matches some criteria, you probably want to do the iteration yourself using something like:

       treestore = TreeStore(str)
       ...
       def match_func(model, iter, data):
           column, key = data # data is a tuple containing column number, key
           value = model.get_value(iter, column)
           return value == key
       def search(model, iter, func, data):
           while iter:
               if func(model, iter, data):
                   return iter
               result = search(model, model.iter_children(iter), func, data)
               if result: return result
               iter = model.iter_next(iter)
           return None
       ...
       match_iter = search(treestore, treestore.iter_children(None),
                           match_func, (0, 'foo'))

The `search`() function iterates recursively over the row (specified by `iter`) and its siblings and their child rows in a depth first fashion looking for a row that has a column matching the given key string. The search terminates when a row is found.

### 14.2.7. Python Protocol Support

The classes that implement the `TreeModel` interface (`TreeStore` and `ListStore` and in PyGTK 2.4, also the `TreeModelSort` and `TreeModelFilter`) support the Python mapping and iterator protocols. The iterator protocol allows you to use the Python `iter`() function on a `TreeModel` to create an iterator to be used to iterate over the top level rows in the `TreeModel`. A more useful capability is to iterate using the `for` statement or a list comprehension. For example:

      ...
      liststore = gtk.ListStore(str, str)
      ...
      # add some rows to liststore
      ...
      # for looping
      for row in liststore:
          # do individual row processing
      ...
      # list comprehension returning a list of values in the first column
      values = [ r[0] for r in liststore ]
      ...

Other parts of the mapping protocols that are supported are using `del` to delete a row in the model and extracting a PyGTK `TreeModelRow` from the model using a key value that is a tree path or `TreeIter`. For example, the following statements all return the first row in a `TreeModel` and the final statement deletes the first child row of the first row:

      row = model[0]
      row = model['0']
      row = model["0"]
      row = model[(0,)]
      i = model.get_iter(0)
      row = model[i]
      del model[(0,0)]

In addition, you can set the values in an existing row similar to the following:

      ...
      liststore = gtk.ListStore(str, int, object)
      ...
      liststore[0] = ['Button', 23, gtk.Button('Label')]

A PyGTK `TreeModelRow` object supports the Python sequence and iterator protocols. You can get an iterator to iterate over the column values in the row or use the for statement or list comprehension as well. A `TreeModelRow` uses the column number as the index to extract a value. For example:

      ...
      liststore = gtk.ListStore(str, int)
      liststore.append(['Random string', 514])
      ...
      row = liststore[0]
      value1 = row[1]
      value0 = liststore['0'][0]
      for value in row:
          print value
      val0, val1 = row
      ...

Using the example from the previous section to iterate over a `TreeStore` to locate a row containing a particular value, the code becomes:

       treestore = TreeStore(str)
       ...
       def match_func(row, data):
           column, key = data # data is a tuple containing column number, key
           return row[column] == key
       ...
       def search(rows, func, data):
           if not rows: return None
           for row in rows:
               if func(row, data):
                   return row
               result = search(row.iterchildren(), func, data)
               if result: return result
           return None
       ...
       match_row = search(treestore, match_func, (0, 'foo'))

You can also set a value in an existing column using:

      treestore[(1,0,1)][1] = 'abc'

The `TreeModelRow` also supports the `del` statement and conversion to lists and tuples using the Python `list`() and `tuple`() functions. As illustrated in the above example the `TreeModelRow` has the `iterchildren`() method that returns an iterator for iterating over the child rows of the `TreeModelRow`.

### 14.2.8. TreeModel Signals

Your application can track changes in a `TreeModel` by connecting to the signals that are emitted by the `TreeModel`: "row-changed", "row-deleted", "row-inserted", "row-has-child-toggled" and "rows-reordered". These signals are used by a `TreeView` to track changes in its `TreeModel`.

If you connect to these signals in your application, you may see clusters of signals when some methods are called. For example the call to add the first child row to a parent row:

      treestore.append(parent, ['qwe', 'asd', 123])

will cause the following signal emissions:

- "row-inserted" where the inserted row will be empty.
- "row-has-child-toggled" since `parent` didn't previously have any child rows.
- "row-changed" for the inserted row when setting the value 'qwe' in the first column.
- "row-changed" for the inserted row when setting the value 'asd in the second column.
- "row-changed" for the inserted row when setting the value 123 in the third column.

Note that you can't retrieve the row order in the "rows-reordered" callback since the new row order is passed as an opaque pointer to an array of integers.

See the PyGTK Reference Manual for more information on the `TreeModel` signals.

### 14.2.9. Sorting TreeModel Rows

#### 14.2.9.1. The TreeSortable Interface

The `ListStore` and `TreeStore` objects implement the `TreeSortable` interface that provides methods for controlling the sorting of `TreeModel` rows. The key element of the interface is a "sort column ID" which is an arbitrary integer value referring to a sort comparison function and associated user data. A sort column ID must be greater than or equal to zero. A sort column ID is created by using the method:

      treesortable.set_sort_func(sort_column_id, sort_func, user_data=None)

where `sort_column_id` is a programmer assigned integer value, `sort_func` is a function or method used to compare rows and `user_data` is context data. `sort_func` has the signature:

      def sort_func_function(model, iter1, iter2, data)
      def sort_func_method(self, model, iter1, iter2, data)

where `model` is the `TreeModel` containing the rows pointed to by the `TreeIter`s `iter1` and `iter2` and `data` is `user_data`. `sort_func` should return: -1 if the `iter1` row should precede the `iter2` row; 0, if the rows are equal; and, 1 if the `iter2` row should precede the `iter1` row. The sort comparison function should always assume that the sort order is `gtk.SORT_ASCENDING` as the sort order will be taken into account by the `TreeSortable` implementations.

The same sort comparison function can be used for multiple sort column IDs by varying the user_data to provide context information. For example, the `user_data` specified in the `set_sort_func`() method could be the index of the column to extract the sort data from.

Once a sort column ID is created a store can use it for sorting by calling the method:

      treesortable.set_sort_column_id(sort_column_id, order)

where `order` is the sort order either `gtk.SORT_ASCENDING` or `gtk.SORT_DESCENDING`.

The sort column ID of -1 means that the store should use the default sort function that is set using the method:

      treesortable.set_default_sort_func(sort_func, user_data=None)

You can check if a store has a default sort function using the method:

      result = treesortable.has_default_sort_func()

which returns `TRUE` if a default sort function has been set.

Once a sort column ID has been set on a `TreeModel` implementing the `TreeSortable` interface it cannot be returned to the original unsorted state. You can change the sort function or use a default sort function but you cannot set the `TreeModel` to have no sort function.

#### 14.2.9.2. Sorting in ListStores and TreeStores

When a `ListStore` or `TreeStore` object is created it automatically sets up sort column IDs corresponding to the columns in the store using the column index number. For example, a `ListStore` with three columns would have three sort column IDs (0, 1, 2) setup automatically. These sort column IDs are associated with an internal sort comparison function that handles the fundamental types:

- 'gboolean'
- str
- int
- long
- float

Initially a `ListStore` or `TreeStore` is set with a sort column ID of -2 that indicates that no sort function is being used and that the store is unsorted. Once you set a sort column ID on a `ListStore` or `TreeStore` you cannot set it back to -2.

If you want to maintain the default sort column IDs you can set up a sort column ID well out of the range of the number of columns such as 1000 and up. Then you can switch between the default sort function and your application sort functions as needed.

Prev | Up | Next
Chapter 14. Tree View Widget | Home | 14.3. TreeViews