Chapter 3. GtkTreeModels for Data Storage: GtkListStore and GtkTreeStore

It is important to realise what GtkTreeModel is and what it is not. GtkTreeModel is basically just an 'interface' to the data store, meaning that it is a standardised set of functions that allows a GtkTreeView widget (and the application programmer) to query certain characteristics of a data store, for example how many rows there are, which rows have children, and how many children a particular row has. It also provides functions to retrieve data from the data store, and tell the tree view what type of data is stored in the model. Every data store must implement the GtkTreeModel interface and provide these functions, which you can use by casting a store to a tree model with GTK_TREE_MODEL(store). GtkTreeModel itself only provides a way to query a data store's characteristics and to retrieve existing data, it does not provide a way to remove or add rows to the store or put data into the store. This is done using the specific store's functions.

Gtk+ comes with two built-in data stores (models): GtkListStore and GtkTreeStore. As the names imply, GtkListStore is used for simple lists of data items where items have no hierarchical parent-child relationships, and GtkTreeStore is used for tree-like data structures, where items can have parent-child relationships. A list of files in a directory would be an example of a simple list structure, whereas a directory tree is an example for a tree structure. A list is basically just a special case of a tree with none of the items having any children, so one could use a tree store to maintain a simple list of items as well. The only reason GtkListStore exists is in order to provide an easier interface that does not need to cater for child-parent relationships, and because a simple list model can be optimised for the special case where no children exist, which makes it faster and more efficient.

GtkListStore and GtkTreeStore should cater for most types of data an application developer might want to display in a GtkTreeView. However, it should be noted that GtkListStore and GtkTreeStore have been designed with flexibility in mind. If you plan to store a lot of data, or have a large number of rows, you should consider implementing your own custom model that stores and manipulates data your own way and implements the GtkTreeModel interface. This will not only be more efficient, but probably also lead to saner code in the long run, and give you more control over your data. See below for more details on how to implement custom models.

Tree model implementations like GtkListStore and GtkTreeStore will take care of the view side for you once you have configured the GtkTreeView to display what you want. If you change data in the store, the model will notify the tree view and your data display will be updated. If you add or remove rows, the model will also notify the store, and your row will appear in or disappear from the view as well.

3.1. How Data is Organised in a Store

A model (data store) has model columns and rows. While a tree view will display each row in the model as a row in the view, the model's columns are not to be confused with a view's columns. A model column represents a certain data field of an item that has a fixed data type. You need to know what kind of data you want to store when you create a list store or a tree store, as you can not add new fields later on.

For example, we might want to display a list of files. We would create a list store with two fields: a field that stores the filename (ie. a string) and a field that stores the file size (ie. an unsigned integer). The filename would be stored in column 0 of the model, and the file size would be stored in column 1 of the model. For each file we would add a row to the list store, and set the row's fields to the filename and the file size.

The GLib type system (GType) is used to indicate what type of data is stored in a model column. These are the most commonly used types:

You do not need to understand the type system, it will usually suffice to know the above types, so you can tell a list store or tree store what kind of data you want to store. Advanced users can derive their own types from the fundamental GLib types. For simple structures you could register a new boxed type for example, but that is usually not necessary. G_TYPE_POINTER will often do as well, you will just need to take care of memory allocation and freeing yourself then.

Storing GObject-derived types (most GDK_TYPE_FOO and GTK_TYPE_FOO) is a special case that is dealt with further below.

Here is an example of how to create a list store:

  GtkListStore *list_store;

  list_store = gtk_list_store_new (2, G_TYPE_STRING, G_TYPE_UINT);

This creates a new list store with two columns. Column 0 stores a string and column 1 stores an unsigned integer for each row. At this point the model has no rows yet of course. Before we start to add rows, let's have a look at the different ways used to refer to a particular row.