14.3. Display tricks using Gtk2::CellRenderers

14.3.1. Introduction

Gtk2::TreeViewColumns and Gtk2::CellRenderers work together to display a column of data in a Gtk2::TreeView. The Gtk2::TreeViewColumn provides the column title and a vertical space for the Gtk2::CellRenderers to render a portion of the data from the Gtk2::TreeView data store. A Gtk2::CellRenderer handles the rendering of each row and column data within the confines of the Gtk2::TreeViewColumn. A Gtk2::TreeViewColumn can contain more than one Gtk2::CellRenderer to provide a row display similar to an Gtk2::HBox. A common use of multiple Gtk2::CellRenderers is to combine a Gtk2::CellRendererPixbuf and a Gtk2::CellRendererText in one column.

This lesson will look at various ways to present the data of the Gtk2::TreeView data store in Gtk2::CellRenderers.

14.3.2. Background

Gtk2-Perl provides five pre-defined cell renderers. We will only look at three of them in this lesson. They are subclasses of Gtk2::CellRenderer. If they do not supply a means to display your data, it is always possible to create your own subclass.

Table 14-2. Pre-defined Gtk2::CellRenderer Types

Gtk2 Class NameRendering Type
Gtk2::CellRendererPixbufRenders pixbuf images, either created by the program or one of the stock items.
Gtk2::CellRendererTextRenders text strings, and numbers that can be converted to a string.
Gtk2::CellRendererToggleRenders a boolean value as a toggle button or a radio button.
Gtk2::CellRendererComboA subclass of Gtk2::CellRendererText, renders a Gtk2::ComboBox into the cells of a Gtk2::TreeViewColumn
Gtk2::CellRendererProgressrenders a progressbar into the cells of a Gtk2::TreeViewColumn.;

Each of the pre-defined cell renderers has various properties that determine how the data will be rendered. Some of the properties is part of Gtk2::CellRenderer, and gets inherited by all the subclasses. Each subclass also feature its own set of properties. To find available properties, consult the man pages.

To associate a tree model column with a Gtk2::CellRenderer property, you define an attribute to the Gtk2::TreeViewColumn. The Gtk2::CellRenderer sets the property from the row's column value before rendering the cell. This allows you to customize the cell display by using tree model data. Consult the man page of Gtk2::TreeViewColumn for the various methods available to add attributes to the Gtk2::TreeViewColumn.

You will typically associate a column of type "Glib::String" in the tree model with the "text" or "markup" property of a Gtk2::CellRendererText, and you are most likely to associate a column of type "Glib::Boolean" in the tree model with the "active" property of Gtk2::CellRendererToggle.

Note

The properties can be set for all rows by using Glib::Object's set_property() method.

	$renderer_txt->set_property('cell-background', 'yellow');

14.3.3. A Sample Program

Table 14-3. Gtk2 object classes used

Gtk2 Class Name
Gtk2::Window
Gtk2::VBox
Gtk2::ListStore
Gtk2::TreeView
Gtk2::TreeViewColumn
Gtk2::CellRendererPixbuf
Gtk2::CellRendererText
Gtk2::CellRendererToggle
Gtk2::TreePath

14.3.3.1. The Screenshot

Figure 14-2. Rendering Tricks

14.3.3.2. The Code

The program can be found here: 'Rendering data'

  1 #! /usr/bin/perl -w
  2 
  3 use strict;
  4 use Gtk2 '-init';
  5 use Glib qw/TRUE FALSE/;
  6 
  7 #Declare our columns
  8 use constant C_MARKUP		=> 0;
  9 use constant C_BACKGROUND	=> 1;
 10 use constant C_STOCK		=> 2;
 11 use constant C_TOGGLE		=> 3;
 12 
 13 #the data for the model
 14 my @data = (
 15   
 16 {markup => '<b>This is Bold</b>',
 17  background => 'red',
 18  stock => 'gtk-open',
 19  toggle => TRUE},
 20  
 21 {markup => '<span foreground="orange" size="15000"><i>Some Value</i></span>', 
 22 background => undef,
 23 stock => 'gtk-close',
 24 toggle => FALSE	},
 25 
 26 { markup => '<span foreground="blue" size="30000"><u>Blue text</u></span>',
 27  background => 'green',
 28  stock => 'gtk-cdrom',
 29  toggle => TRUE},
 30 
 31 );
 32 
 33 #standard window creation, placement, and signal connecting
 34 my $window = Gtk2::Window->new('toplevel');
 35 $window->signal_connect('delete_event' => sub { Gtk2->main_quit; });
 36 $window->set_border_width(5);
 37 $window->set_position('center_always');
 38 
 39 #this vbox will geturn the bulk of the gui
 40 my $vbox = &ret_vbox();
 41 
 42 #add and show the vbox
 43 $window->add($vbox);
 44 $window->show();
 45 
 46 #our main event-loop
 47 Gtk2->main();
 48 
 49 
 50 
 51 
 52 sub ret_vbox {
 53 
 54 my $vbox = Gtk2::VBox->new(FALSE,5);
 55 $vbox->set_size_request (500, 150);
 56 
 57 #get the model
 58 my $store = &create_model;
 59 	
 60 	#create a treeview with the model.
 61 	my $treeview = Gtk2::TreeView->new_with_model($store);
 62 	
 63 		#------------------------------------------------------------------
 64 		#create a treeview column and set its title
 65 		my $tv_clmn_pix_text = Gtk2::TreeViewColumn->new;
 66 		$tv_clmn_pix_text->set_title("Pix and Markup");
 67 			#pixbuf renderer
 68 			my $ren_stock = Gtk2::CellRendererPixbuf->new();
 69 		#pack it into the column
 70 		$tv_clmn_pix_text->pack_start ($ren_stock, FALSE);
 71 		#set its atributes
 72 		$tv_clmn_pix_text->set_attributes($ren_stock,
 73 		'stock-id' => C_STOCK,
 74 		'cell-background'=> C_BACKGROUND,
 75 		);
 76 			#text renderer
 77 			my $ren_text = Gtk2::CellRendererText->new();
 78 		#pack it into the column	
 79 		$tv_clmn_pix_text->pack_start ($ren_text, FALSE);
 80 		#set its atributes		
 81 		$tv_clmn_pix_text->set_attributes($ren_text,
 82 		'markup' => C_MARKUP,
 83 		'cell-background' => C_BACKGROUND,
 84 		);
 85 	#append this column to the treeview
 86 	$treeview->append_column($tv_clmn_pix_text);
 87 	
 88 		#------------------------------------------------------------------
 89 		#create a treeview column and set its title
 90 		my $tv_clmn_toggle_text = Gtk2::TreeViewColumn->new;
 91 		$tv_clmn_toggle_text->set_title("Toggle and Markup");
 92 			#toggle renderer
 93 			my $ren_toggle = Gtk2::CellRendererToggle->new();
 94 			$ren_toggle->signal_connect('toggled' => \&toggled,$store);
 95 		#pack it into the column	
 96 		$tv_clmn_toggle_text->pack_start ($ren_toggle, FALSE);
 97 		#set its atributes
 98 		$tv_clmn_toggle_text->set_attributes($ren_toggle,
 99 		'active' => C_TOGGLE,
100 		);
101 			#text renderer
102 			my $ren_tgl_text = Gtk2::CellRendererText->new();
103 		#pack it into the column	
104 		$tv_clmn_toggle_text->pack_start ($ren_tgl_text, FALSE);
105 		#set its atributes		
106 		$tv_clmn_toggle_text->set_attributes($ren_tgl_text,
107 		'markup' => C_MARKUP,
108 		);
109 	#append this column to the treeview	
110 	$treeview->append_column($tv_clmn_toggle_text);	
111 		
112 	#------------------------------------------------------------------		
113 $vbox->pack_start($treeview,TRUE,TRUE,0);
114 $vbox->show_all();
115 return $vbox;
116 }
117 
118 
119 sub create_model {
120   # create list store
121   my $list_store = Gtk2::ListStore->new(qw/Glib::String Glib::String Glib::String Glib::Boolean/);
122 
123   # add data to the list store
124   foreach my $d (@data) {
125       my $iter = $list_store->append;
126       $list_store->set ($iter,
127       		   C_MARKUP, $d->{markup},
128 		   C_BACKGROUND, $d->{background},
129 		   C_STOCK, $d->{stock},
130 		   C_TOGGLE, $d->{toggle},
131       );
132   }
133 
134   return $list_store;
135 }
136 
137 sub toggled {
138   my ($cell, $path_str, $model) = @_;
139   
140 my $path = Gtk2::TreePath->new_from_string ($path_str);
141  
142 	# get toggled iter
143   	my $iter = $model->get_iter ($path);
144   	my ($fixed) = $model->get ($iter, C_TOGGLE);
145 
146   # do something with the value
147   $fixed =!$fixed;
148 
149 # set new value
150 $model->set ($iter, C_TOGGLE, $fixed);
151 }

14.3.3.3. The Discussion

  • We start off practicing good programming practice by declaring the constants representing each of the columns in the model

    #Declare our columns
    use constant C_MARKUP		=> 0;
    use constant C_BACKGROUND	=> 1;
    use constant C_STOCK		=> 2;
    use constant C_TOGGLE		=> 3;
    This makes things easier when you read the code, and in future when maintaining code, it will lighten your burden.

  • Next, the contents of the model is created. In your program you can use various sources to create contents. You may get it from an XML file or from the return of a SQL select statement. In this sample we hard coded it in the form of an array of hashes.

    At this stage, it is not yet inserted into the Gtk2::ListStore.

  • We call the create_model sub to create and populate a Gtk2::ListStore. We then return a reference to this Gtk2::ListStore, and use it as the model for the newly created Gtk2::TreeView.

    #get the model
    my $store = &create_model;
    	
    	#create a treeview with the model.
    	my $treeview = Gtk2::TreeView->new_with_model($store);

  • Adding the columns to the Gtk2::TreeView follows a basic pattern of:

    • Create a Gtk2::TreeViewColumn, set its title. This will be the container of the cell renderers.

    • Create a cell renderer. You can choose from predefined ones, or create your own.

    • Pack it into the Gtk2::TreeViewColumn.

    • Add the attributes to the Gtk2::TreeViewColumn. This will set the defined property of the cell renderer to the value of the specified column number in the model.

      When we want a value to be the default, we can leave it undef. This we did for the values of the "background" property.

    • After you packed all the required cell rederers into the Gtk2::TreeViewColumn, add the Gtk2::TreeViewColumn to the Gtk2::TreeView using the append_column method of the Gtk2::TreeView.

  • We connect the "toggled" signal of the Gtk2::CellRendererToggle to a sub that will change the underlying model of the Gtk2::TreeView. It follows the simple procedure of getting the current value from the model, inverting it, and writing it back to the model.

    This will then reflect on the Gtk2::CellRendererToggle displaying that cell. If we neglect to do this, clicking on the renderer's check box will not cause a change of its state.

    sub toggled {
      my ($cell, $path_str, $model) = @_;
      
    my $path = Gtk2::TreePath->new_from_string ($path_str);
     
    	# get toggled iter
      	my $iter = $model->get_iter ($path);
      	my ($fixed) = $model->get ($iter, C_TOGGLE);
    
      # do something with the value
      $fixed =!$fixed;
    
    # set new value
    $model->set ($iter, C_TOGGLE, $fixed);
    }