14.4. Making use of Gtk2::TreeSelection.

14.4.1. Introduction

One of the most basic features of a list or tree view is that rows can be selected or unselected. Selections are handled using the Gtk2::TreeSelection object of a Gtk2::TreeView. Every Gtk2::TreeView automatically has a Gtk2::TreeSelection associated with it, and you can get it using Gtk2::TreeView's get_selection method. Selections are handled completely on the tree view side, which means that the model knows nothing about which rows are selected or not.

There is no particular reason why selection handling could not have been implemented with functions that access the tree view widget directly, but for reasons of API cleanliness and code clarity the Gtk+ developers decided to create this special Gtk2::TreeSelection object that then internally deals with the tree view widget. You will never need to create a tree selection object, it will be created for you automatically when you create a new tree view. You only need to use the get_selection method to get a pointer to the Gtk2::TreeSelection object.

This lesson will show you how to determine the value of a selection. We will start off with a simple demo program on selections. We will then discuss the pieces of code that is important to us.

14.4.2. A Sample Program

Table 14-4. Gtk2 object classes used

Gtk2 Class Name
Gtk2::Window
Gtk2::VBox
Gtk2::HSeparator
Gtk2::Button
Gtk2::Label
Gtk2::ComboBox
Gtk2::TreeStore
Gtk2::TreeView
Gtk2::TreeViewColumn
Gtk2::CellRendererText
Gtk2::TreeSelection

14.4.2.1. The Screenshot

Figure 14-3. Finding a selection

14.4.2.2. The Code

The program can be found here: 'Finding a selection'

  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 $vbox->pack_start(Gtk2::Label->new("Selection Mode:"),FALSE,FALSE,5);
 29 
 30 	#------------------
 31 	#get a list of Gtk2::SelectionModes and fill a combo box with it
 32 	my $cmb_box = Gtk2::ComboBox->new_text;
 33 	 
 34 	foreach my $s_type (Glib::Type->list_values ('Gtk2::SelectionMode')){
 35 	
 36 		$cmb_box->append_text($s_type->{'nick'});
 37 	}
 38 	
 39 	$cmb_box->set_active(0);
 40 	#------------------
 41 	
 42 $vbox->pack_start($cmb_box,FALSE,FALSE,0);
 43 
 44 $vbox->pack_start(Gtk2::HSeparator->new(),FALSE,FALSE,0);
 45 		
 46 	#this is one of the provided base Gtk2::TreeModel classes.
 47 	my $tree_store = Gtk2::TreeStore->new(qw/Glib::String/);
 48 
 49 	#fill it with arbitry data
 50 	foreach (1..3) {
 51 	
 52 		my $parent_nr = $_;
 53 		#the iter is a pointer in the treestore. We
 54 		#use to add data.
 55                 my $iter = $tree_store->append(undef);
 56 		$tree_store->set ($iter,0 => "Parent $parent_nr");
 57 		
 58                  foreach (1..3){
 59 		 	#here we append child iters to the parent iter
 60 			#and add data to those chils iters.
 61                       my $iter_child = $tree_store->append($iter);
 62 		      $tree_store->set ($iter_child,0 => "Child $_ of Parent $parent_nr");
 63 		}
 64 	}
 65 	
 66 	#this will create a treeview, specify $tree_store as its model
 67 	my $tree_view = Gtk2::TreeView->new($tree_store);
 68 	
 69 		#create a Gtk2::TreeViewColumn to add to $tree_view
 70 		my $tree_column = Gtk2::TreeViewColumn->new();
 71 		$tree_column->set_title ("Select Something");
 72 			
 73 			my $renderer = Gtk2::CellRendererText->new;
 74 			
 75 		$tree_column->pack_start ($renderer, FALSE);
 76 		$tree_column->add_attribute($renderer, text => 0);
 77 	
 78 	#add $tree_column to the treeview
 79 	$tree_view->append_column ($tree_column);
 80 	
 81 	$vbox->set_size_request (300, 300);
 82 	
 83 	
 84 	#---------------------------------------------------
 85 	#get the Gtk2::TreeSelection of $tree_view
 86 	my $treeselection = $tree_view->get_selection;
 87 	#set its initial mode
 88 	$treeselection->set_mode($cmb_box->get_active_text);
 89 	
 90 	#connect the combo box's changed signal so that it will
 91 	#change the mode of the Gtk2::TreeSelection on each change.
 92 	$cmb_box->signal_connect('changed' => sub {
 93 	
 94 		$treeselection->set_mode($cmb_box->get_active_text);
 95 	});
 96 	#-----------------------------------------------------
 97 	
 98 $vbox->pack_start($tree_view,TRUE,TRUE,0);
 99 $vbox->pack_start(Gtk2::HSeparator->new(),FALSE,FALSE,0);
100 
101 	my $btn_show_sel = Gtk2::Button->new("_Show Selected");
102 	$btn_show_sel->signal_connect("clicked" => sub {
103 	
104 		my $treeselection = $tree_view->get_selection;
105 		
106 		$treeselection->selected_foreach (sub{ 
107 			#this sub wil receive the following:
108 			my ($model,$path,$iter) =@_;
109 			
110 			#we want data at the model's column 0  
111 			#where the iter is pointing
112 			my $value = $model->get($iter,0);
113 			print $value."\n";
114 			
115 			});	
116 	});
117 		
118 $vbox->pack_end($btn_show_sel,FALSE,FALSE,0);
119 
120 $vbox->show_all();
121 return $vbox;
122 }

14.4.2.3. The Discussion

  • The Gtk2::TreeSelection belonging to a Gtk2::TreeView can be used to define selection modes. To define its selection mode, we use its "set_mode" method. In our program we extract a list of possible values for the selection mode, by making use of Glib::Type's "list_values" method. We then use this and populate a Gtk2::ComboBox. This will enable us to change the selection mode.

    #------------------
    #get a list of Gtk2::SelectionModes and fill a combo box with it
    my $cmb_box = Gtk2::ComboBox->new_text;
    	 
    foreach my $s_type (Glib::Type->list_values ('Gtk2::SelectionMode')){
    	
    	$cmb_box->append_text($s_type->{'nick'});
    }
    	
    $cmb_box->set_active(0);
    #------------------

    Tip

    To find out more about the values returned by "list_values", consult the chapter on Gtk2::MessageDialog, Chapter 8 -> "Types of messages" for more info.

  • We set an initial selection mode and then we connect the Gtk2::ComboBox's "changed" signal to a sub that will change the selection mode of the Gtk2::TreeView accordingly (by making use of it's Gtk2::TreeSelection's "set_mode" method) to the selected text value of the Gtk2::ComboBox.

    #---------------------------------------------------
    #get the Gtk2::TreeSelection of $tree_view
    my $treeselection = $tree_view->get_selection;
    #set its initial mode
    $treeselection->set_mode($cmb_box->get_active_text);
    	
    #connect the combo box's changed signal so that it will
    #change the mode of the Gtk2::TreeSelection on each change.
    $cmb_box->signal_connect('changed' => sub {
    	
    	$treeselection->set_mode($cmb_box->get_active_text);
    });
    #-----------------------------------------------------

  • To get a selection from a Gtk2::TreeView we have a few methods at our disposal.

    • If the select mode is such that only one item can be selected, we can use the "get_selected" method. This will return a Gtk2::TreeIter, pointing to the selected row in the model.

    • For one and more selectable items, we can use the "selected_foreach" method. This is used to loop the selected items, calling a subroutine for each. We use this one in our program, since we can have a select mode where one or more items is selectable.

      my $treeselection = $tree_view->get_selection;
      		
      $treeselection->selected_foreach (sub{ 
      	#this sub wil receive the following:
      	my ($model,$path,$iter) =@_;
      			
      	#we want data at the model's column 0  
      	#where the iter is pointing
      	my $value = $model->get($iter,0);
      	print $value."\n";
      			
      	});	

    • The "get_selected_rows" method will return a list of Gtk2::TreePaths pointing to each selected row. This can then be further used to get the selected values from the model. We get the Gtk2::TreeIter by using the model's "get_iter" method, and passing it the Gtk2::TreePath as argument.

Tip

When you used Pango markup in a renderer, the returned value will be in the markup form. This can be annoying when you actually need to get the value WITHOUT the markup. To get only the value, make use of Perl's shinning feature caller regular expressions.

$markup =~ s/<[^>]*>//g 
will filter out all the tags, leaving you with a "clean" value.