Chapter 14. Gtk2::TreeView

Objective

This is a meaty, beefy, big and bouncy section on the sometimes complex and misunderstood Gtk2::TreeView and the classes used with it. It will start with a gentle introduction, and then move on to cover more intimate detail. Again, like the Gtk2::TextView section, this one borrows heavily from the PyGtk tutorial.

14.1. Overview

The Gtk2::TreeView widget is the user interface object that displays data stored in an object that implements the Gtk2::TreeModel interface. Two base tree model classes are provided in Gtk2-Perl:

The two additional Gtk2::TreeModels stack on top of (or interpose on) the base models:

A Gtk2::TreeView displays all of the rows of a Gtk2::TreeModel but may display only some of the columns. The columns may also be presented in a different order than that of the Gtk2::TreeModel.

The Gtk2::TreeView uses Gtk2::TreeViewColumn objects to organize the display of the columnar data. Each Gtk2::TreeViewColumn displays one column with an optional header that may contain the data from several Gtk2::TreeModel columns. The individual Gtk2::TreeViewColumns are packed (similar to Gtk2::HBox containers) with Gtk2::CellRenderer objects to render the display of the associated data from a Gtk2::TreeModel row and column location. There are five predefined Gtk2::CellRenderer classes:

A Gtk2::TreeViewColumn can contain several Gtk2::CellRenderer objects to provide a column that, for example, may have an image and text packed together.

Finally, the Gtk2::TreeIter, Gtk2::TreeRowReference and Gtk2::TreeSelection objects provide a transient pointer to a row in a Gtk2::TreeModel; a persistent pointer to a row in a Gtk2::TreeModel; and an object managing the selections in a Gtk2::TreeView respectively.

A Gtk2::TreeView display is composed using the following general operations not necessarily in this order:

Simple Gtk2::TreeView

14.1.1. The Screenshot.

Figure 14-1. Simple Gtk2::TreeView

14.1.2. Classes

Table 14-1. Gtk2 object classes used

Gtk2 Class Name
Gtk2::Window
Gtk2::VBox
Gtk2::ScrolledWindow
Gtk2::TreeStore
Gtk2::TreeView
Gtk2::TreeViewColumn
Gtk2::CellRendererText
Gtk2::TreeIter

14.1.3. The Code.

The program can be found here: 'Simple Gtk2::TreeView Demo'

  1 #! /usr/bin/perl -w
  2 
  3 use strict;
  4 use Gtk2 '-init';
  5 use Glib qw/TRUE FALSE/; 
  6  
  7 #standard window creation, placement, and signal connecting
  8 my $window = Gtk2::Window->new('toplevel');
  9 $window->signal_connect('delete_event' => sub { Gtk2->main_quit; });
 10 $window->set_border_width(5);
 11 $window->set_position('center_always');
 12 
 13 #this vbox will geturn the bulk of the gui
 14 my $vbox = &ret_vbox();
 15 
 16 #add and show the vbox
 17 $window->add($vbox);
 18 $window->show();
 19 
 20 #our main event-loop
 21 Gtk2->main();
 22 
 23 
 24 sub ret_vbox {
 25 
 26 my $vbox = Gtk2::VBox->new(FALSE,5);
 27 
 28 	#create a scrolled window that will host the treeview
 29 	my $sw = Gtk2::ScrolledWindow->new (undef, undef);
 30     		$sw->set_shadow_type ('etched-out');
 31 		$sw->set_policy ('automatic', 'automatic');
 32 		#This is a method of the Gtk2::Widget class,it will force a minimum 
 33 		#size on the widget. Handy to give intitial size to a 
 34 		#Gtk2::ScrolledWindow class object
 35 		$sw->set_size_request (300, 300);
 36 		#method of Gtk2::Container
 37 		$sw->set_border_width(5);
 38 	
 39 	#this is one of the provided base Gtk2::TreeModel classes.
 40 	my $tree_store = Gtk2::TreeStore->new(qw/Glib::String/);
 41 
 42 	#fill it with arbitry data
 43 	foreach (1..3) {
 44 	
 45 		my $parent_nr = $_;
 46 		#the iter is a pointer in the treestore. We
 47 		#use to add data.
 48                 my $iter = $tree_store->append(undef);
 49 		$tree_store->set ($iter,0 => "Parent $parent_nr");
 50 		
 51                  foreach (1..3){
 52 		 	#here we append child iters to the parent iter
 53 			#and add data to those chils iters.
 54                       my $iter_child = $tree_store->append($iter);
 55 		      $tree_store->set ($iter_child,0 => "Child $_ of Parent $parent_nr");
 56 		}
 57 	}
 58 	
 59 	#this will create a treeview, specify $tree_store as its model
 60 	my $tree_view = Gtk2::TreeView->new($tree_store);
 61 
 62 		
 63 		#create a Gtk2::TreeViewColumn to add to $tree_view
 64 		my $tree_column = Gtk2::TreeViewColumn->new();
 65 		
 66 		$tree_column->set_title ("Click to sort");
 67 			
 68 			#create a renderer that will be used to display info
 69 			#in the model
 70 			my $renderer = Gtk2::CellRendererText->new;
 71 		#add this renderer to $tree_column. This works like a Gtk2::Hbox
 72 		# so you can add more than one renderer to $tree_column			
 73 		$tree_column->pack_start ($renderer, FALSE);
 74 		
 75 		 # set the cell "text" attribute to column 0   
 76 		 #- retrieve text from that column in treestore 
 77 		 # Thus, the "text" attribute's value will depend on the row's value
 78 		 # of column 0 in the model($treestore),
 79 		 # and this will be displayed by $renderer,
 80 		 # which is a text renderer
 81 		$tree_column->add_attribute($renderer, text => 0);
 82 	
 83 	#add $tree_column to the treeview
 84 	$tree_view->append_column ($tree_column);
 85 	
 86 	 # make it searchable
 87    	$tree_view->set_search_column(0);
 88 	
 89 		# Allow sorting on the column
 90 		$tree_column->set_sort_column_id(0);
 91    
 92 	# Allow drag and drop reordering of rows
 93         $tree_view->set_reorderable(TRUE);
 94 	
 95 	$sw->add($tree_view);
 96 	
 97 $vbox->pack_start($sw,TRUE,TRUE,0);
 98 $vbox->show_all();
 99 return $vbox;
100 }

14.1.4. Important points

  • In order to add something to the model, we use a two step process:

    • You have to add a row to the Gtk2::TreeStore, using one of various available methods. The chosen method depends where you want the row to be added. This newly added row will be empty. The methods used to add it, will return a reference to a Gtk2::TreeIter that you must use in the second step to append data to the row.

    • After a row is added to the Gtk2::TreeStore, and you have a GGtk2::TreeIter reference pointing to that row. Use Gtk2::TreeStore's "set" method to append data to this row.

      Warning

      The list of pairs must contain as many items as the number of columns in the Gtk2::TreeStore. The items must also match the data type of their respective Gtk2::TreeStore columns.

      Tip

      Now you know the long way, you can look at the "insert_with_values" method which does both in one step!

  • The Gtk2::TreeView's "headers-clickable" property really just sets the "clickable" property of the underlying Gtk2::TreeViewColumn.

    A Gtk2::TreeViewColumn will not be sortable unless the tree model implements the TreeSortable interface and the Gtk2::TreeViewColumn's set_sort_column_id() method has been called with a valid column number.

    When calling set_sort_column_id(), the "headers-clickable" property of the Gtk2::TreeView is implicitly set to "TRUE" behind the scenes.

  • The "reorderable" property of Gtk2::TreeView enables the user to reorder the Gtk2::TreeView model by dragging and dropping the Gtk2::TreeView rows displayed.

  • The "rules-hint" property of Gtk2::TreeView hint to the theme engine to draw rows in alternating colors. This eases readability.