Chapter 9. The TreeView widget

Table of Contents

The Gtk::TreeView widget can contain lists or trees of data, in columns.

The Model

Each Gtk::TreeView has an associated Gtk::TreeModel, which contains the data displayed by the TreeView. Each Gtk::TreeModel can be used by more than one Gtk::TreeView. For instance, this allows the same underlying data to be displayed and edited in 2 different ways at the same time. Or the 2 Views might display different columns from the same Model data, in the same way that 2 SQL queries (or "views") might show different fields from the same database table.

Although you can theoretically implement your own Model, you will normally use either the ListStore or TreeStore model classes.

Reference

ListStore, for rows

The ListStore contains simple rows of data, and each row has no children.

Figure 9.1. TreeView - ListStore

TreeView - ListStore

Reference

TreeStore, for a hierarchy

The TreeStore contains rows of data, and each row may have child rows.

Figure 9.2. TreeView - TreeStore

TreeView - TreeStore

Reference

Model Columns

The TreeModelColumnRecord class is used to keep track of the columns and their data types. You add TreeModelColumn instances to the ColumnRecord and then use those TreeModelColumns when getting and setting the data in model rows. You will probably find it convenient to derive a new TreeModelColumnRecord which has your TreeModelColumn instances as member data.

class ModelColumns : public Gtk::TreeModelColumnRecord
{
public:

  ModelColumns()
    { add(m_col_text); add(m_col_number); }

  Gtk::TreeModelColumn<Glib::ustring> m_col_text;
  Gtk::TreeModelColumn<int> m_col_number;
};

ModelColumns m_Columns;

You specify the ColumnRecord when creating the Model, like so:

Glib::RefPtr<Gtk::ListStore> refListStore =
    Gtk::ListStore::create(m_Columns);

As a TreeModelColumnRecord describes structure, not data, it can be shared among multiple models, and this is preferable for efficiency. However, the instance (such as m_Columns here) should usually not be static, because it often needs to be instantiated after glibmm has been initialized. The best solution is to make it a lazily instantiated singleton, so that it will be constructed on-demand, whenever the first model accesses it.

Adding Rows

Add rows to the model with the append(), prepend(), or insert() methods.

Gtk::TreeModel::iterator iter = m_refListStore->append();

You can dereference the iterator to get the Row:

Gtk::TreeModel::Row row = *iter;

Adding child rows

Gtk::TreeStore models can have child items. Add them with the append(), prepend(), or insert() methods, like so:

Gtk::TreeModel::iterator iter_child =
    m_refTreeStore->append(row.children());

Setting values

You can use the operator[] override to set the data for a particular column in the row, specifying the TreeModelColumn used to create the model.

row[m_Columns.m_col_text] = "sometext";

Getting values

You can use the operator[] override to get the data in a particular column in a row, specifiying the TreeModelColumn used to create the model.

Glib::ustring strText = row[m_Columns.m_col_text];
int number = row[m_Columns.m_col_number];

The compiler will complain if you use an inappropriate type. For instance, this would generate a compiler error:

//compiler error - no conversion from ustring to int.
int number = row[m_Columns.m_col_text];

"Hidden" Columns

You might want to associate extra data with each row. If so, just add it as a Model column, but don't add it to the View.