GTK+ By Example/Tree View/Introduction

GtkTreeView is a widget that displays single- or multi-columned lists and trees. It replaces the old Gtk+-1.2 GtkCList and GtkCTree widgets. Even though GtkTreeView is slightly harder to master than its predecessors, it is so much more powerful and flexible that most application developers will not want to miss it once they have come to know it.

The purpose of this chapter is not to provide an exhaustive documentation of GtkTreeView - that is what the API documentation is for, which should be read alongside with this tutorial. The goal is rather to present an introduction to the most commonly-used aspects of GtkTreeView, and to demonstrate how the various GtkTreeView components and concepts work together. Furthermore, an attempt has been made to shed some light on custom tree models and custom cell renderers, which seem to be often-mentioned, but rarely explained.

Developers looking for a quick and dirty introduction that teaches them everything they need to know in less than five paragraphs will not find it here. In the author's experience, developers who do not understand how the tree view and the models work together will run into problems once they try to modify the given examples, whereas developers who have worked with other toolkits that employ the Model/View/Controller-design will find that the API reference provides all the information they need to know in more condensed form anyway. Those who disagree may jump straight to the working example code of course.

Please note that the code examples in the following sections do not necessarily demonstrate how GtkTreeView is used best in a particular situation. There are different ways to achieve the same result, and the examples merely show those different ways, so that developers are able to decide which one is most suitable for the task at hand.

Hello World edit

/* 
 * Compile with:
 *  gcc -o helloworld helloworld.c `pkg-config --cflags --libs gtk+-2.0`
 *
 */

#include <gtk/gtk.h>

enum
{
  COL_NAME = 0,
  COL_AGE,
  NUM_COLS
} ;


static GtkTreeModel *
create_and_fill_model (void)
{
  GtkListStore  *store;
  GtkTreeIter    iter;
  
  store = gtk_list_store_new (NUM_COLS, G_TYPE_STRING, G_TYPE_UINT);

  /* Append a row and fill in some data */
  gtk_list_store_append (store, &iter);
  gtk_list_store_set (store, &iter,
                      COL_NAME, "Heinz El-Mann",
                      COL_AGE, 51,
                      -1);
  
  /* append another row and fill in some data */
  gtk_list_store_append (store, &iter);
  gtk_list_store_set (store, &iter,
                      COL_NAME, "Jane Doe",
                      COL_AGE, 23,
                      -1);
  
  /* ... and a third row */
  gtk_list_store_append (store, &iter);
  gtk_list_store_set (store, &iter,
                      COL_NAME, "Joe Bungop",
                      COL_AGE, 91,
                      -1);
  
  return GTK_TREE_MODEL (store);
}

static GtkWidget *
create_view_and_model (void)
{
  GtkCellRenderer     *renderer;
  GtkTreeModel        *model;
  GtkWidget           *view;

  view = gtk_tree_view_new ();

  /* --- Column #1 --- */

  renderer = gtk_cell_renderer_text_new ();
  gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (view),
                                               -1,      
                                               "Name",  
                                               renderer,
                                               "text", COL_NAME,
                                               NULL);

  /* --- Column #2 --- */

  renderer = gtk_cell_renderer_text_new ();
  gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (view),
                                               -1,      
                                               "Age",  
                                               renderer,
                                               "text", COL_AGE,
                                               NULL);

  model = create_and_fill_model ();

  gtk_tree_view_set_model (GTK_TREE_VIEW (view), model);

  /* The tree view has acquired its own reference to the
   *  model, so we can drop ours. That way the model will
   *  be freed automatically when the tree view is destroyed */

  g_object_unref (model);

  return view;
}


int
main (int argc, char **argv)
{
  GtkWidget *window;
  GtkWidget *view;

  gtk_init (&argc, &argv);

  window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
  g_signal_connect (window, "delete_event", gtk_main_quit, NULL); /* dirty */

  view = create_view_and_model ();

  gtk_container_add (GTK_CONTAINER (window), view);

  gtk_widget_show_all (window);

  gtk_main ();

  return 0;
}