3.3. Adding Rows to a Store

3.3.1. Adding Rows to a List Store

Rows are added to a list store with gtk_list_store_append. This will insert a new empty row at the end of the list. There are other functions, documented in the GtkListStore API reference, that give you more control about where exactly the new row is inserted, but as they work very similar to gtk_list_store_append and are fairly straight-forward to use, we will not deal with them here.

Here is a simple example of how to create a list store and add some (empty) rows to it:


  GtkListStore *liststore;
  GtkTreeIter   iter;

  liststore = gtk_list_store_new(1, G_TYPE_STRING);

  /* Append an empty row to the list store. Iter will point to the new row */
  gtk_list_store_append(liststore, &iter);

  /* Append an empty row to the list store. Iter will point to the new row */
  gtk_list_store_append(liststore, &iter);

  /* Append an empty row to the list store. Iter will point to the new row */
  gtk_list_store_append(liststore, &iter);

This in itself is not very useful yet of course. We will add data to the rows in the next section.

3.3.2. Adding Rows to a Tree Store

Adding rows to a tree store works similar to adding rows to a list store, only that gtk_tree_store_append is the function to use and one more argument is required, namely the tree iter to the parent of the row to insert. If you supply NULL instead of providing the tree iter of another row, a new top-level row will be inserted. If you do provide a parent tree iter, the new empty row will be inserted after any already existing children of the parent. Again, there are other ways to insert a row into the tree store and they are documented in the GtkTreeStore API reference manual. Another short example:


  GtkListStore *treestore;
  GtkTreeIter   iter, child;

  treestore = gtk_tree_store_new(1, G_TYPE_STRING);

  /* Append an empty top-level row to the tree store.
   *  Iter will point to the new row */
  gtk_tree_store_append(treestore, &iter, NULL);

  /* Append another empty top-level row to the tree store.
   *  Iter will point to the new row */
  gtk_tree_store_append(treestore, &iter, NULL);

  /* Append a child to the row we just added.
   *  Child will point to the new row */
  gtk_tree_store_append(treestore, &child, &iter);

  /* Get the first row, and add a child to it as well (could have been done
   *  right away earlier of course, this is just for demonstration purposes) */
  if (gtk_tree_model_get_iter_first(GTK_TREE_MODEL(treestore), &iter))
  {
    /* Child will point to new row */
    gtk_tree_store_append(treestore, &child, &iter);
  }
  else
  {
    g_error("Oops, we should have a first row in the tree store!\n");
  }

3.3.3. Speed Issues when Adding a Lot of Rows

A common scenario is that a model needs to be filled with a lot of rows at some point, either at start-up, or when some file is opened. An equally common scenario is that this takes an awfully long time even on powerful machines once the model contains more than a couple of thousand rows, with an exponentially decreasing rate of insertion. As already pointed out above, writing a custom model might be the best thing to do in this case. Nevertheless, there are some things you can do to work around this problem and speed things up a bit even with the stock Gtk+ models:

Firstly, you should detach your list store or tree store from the tree view before doing your mass insertions, then do your insertions, and only connect your store to the tree view again when you are done with your insertions. Like this:


  ...

  model = gtk_tree_view_get_model(GTK_TREE_VIEW(view));

  g_object_ref(model); /* Make sure the model stays with us after the tree view unrefs it */

  gtk_tree_view_set_model(GTK_TREE_VIEW(view), NULL); /* Detach model from view */

  ... insert a couple of thousand rows ...

  gtk_tree_view_set_model(GTK_TREE_VIEW(view), model); /* Re-attach model to view */

  g_object_unref(model);

  ...

Secondly, you should make sure that sorting is disabled while you are doing your mass insertions, otherwise your store might be resorted after each and every single row insertion, which is going to be everything but fast.

Thirdly, you should not keep around a lot of tree row references if you have so many rows, because with each insertion (or removal) every single tree row reference will check whether its path needs to be updated or not.