Chapter 38. CTree Widget

Table of Contents
38.1. Creating a CTree
38.2. Adding and Removing Nodes
38.3. Setting CTree Attributes
38.4. A CTree Example

Inheritance Hierarchy

Object
   +--- Widget
         +--- Container
               +--- Clist
                   +--- CTree
         

The CTree widget is derived from the CList widget. It is designed to display hierarchically-organised data. The tree is displayed vertically, and branches of the tree can be clapsed and expanded as required by the user.

38.1. Creating a CTree

A CTree, being derived from CList, can have multiple columns. These columns optionally have titles that are displayed along the top of the CTree widget. Hence there are two functions for creating a new CTree widget:

$ctree = new Gtk::CTree( $columns, $tree_column );

$ctree = new_with_titles Gtk::CTree( $tree_column, @titles );

The $columns argument specifies the number of columns that the CTree will contain. The $tree_column argumnet specifies which of those columns is to contain the tree. Columns are numbered starting from 0.

With the second funtion above, the @titles argument contains a list of strings that contain the captions for the column headings. The number of columns is determined from the number of strings in the list. A typical code fragment using the new_with_titles() function would be:

$ctree = new_with_titles Gtk::CTree( 0, "Location", "Description" );

This would create a new CTree with two columns entitled "Location" and "Description", with the first column containing the tree.

38.2. Adding and Removing Nodes

The items in a CTree are termed nodes. Nodes are inserted into a CTree in such a way as to create a hierarchy (although the order of insertion is not critical). The following function is used to insert a node:

$ctree->insert_node( $parent,
                     $sibling,
                     $text,
                     $spacing,
                     $pixmap_closed,
                     $mask_closed,
                     $pixmap_opened,
                     $mask_opened,
                     $is_leaf,
                     $expanded );

This function looks a little daunting, but that is merely due to the power of the CTreee widget. Not all of the parameters above are required.

The CTree widget allows you to specify pixmaps to display in each node. For branch nodes, you can specify different pixmaps for when the branch is collapsed or expanded. This gives a nice visual feedback to the user, but it is optional so you don't have to specify pixmaps.

Lets have a quick look at all of the parameters:

$parent

The parent node of the one we are inserting. May be undef for a root-level (i.e. initial) node

$sibling

A sibling of the node we are inserting. May be undef if there are no siblings.

$text

The textual contents of each column in the tree for this node. This must have an entry for each column, even if it is an empty string. You may be wondering how a scalar holds the text for each column. The answer is pretty simple. The scalar actually holds an anonymouse list containing each of the text labels. For example, if you have a two column tree, you should use something like this:

$text = [ "column 1", "column 2" ];

$spacing

Specifies the padding between the nodes pixmap and text elements, if a pixmap is provided.

$pixmap_closed

A pixmap to display for a collapsed branch node and for a leaf node.

$mask_closed

A bitmap mask for the above pixmap.

$pixmap_opened

A pixmap to display for an expanded branch node.

$mask_opened

A bitmap mask for the above pixmap.

$is_leaf

Indicates whether this is a leaf or branch node.

$expanded

Indicates whether a branch node is initially expanded or collapsed.

An object of type GtkCTreeNode is returned by the insert_node() function. This object is used to reference the node when manipulating it. The node is also supplied by many of the CTree signals to identify which node the signal pertains to.

To remove a node for a CTree, the following function is provided:

$ctree->remove_node( $node );

38.3. Setting CTree Attributes

There are a number of functions that set options that pertain to a CTree instance as a whole (rather than to a particular node). The first group set padding attributes that effect how the widget is drawn:

$ctree->set_indent( $indent );

$ctree->set_spacing( $spacing );

The function set_indent() sets how far a new branch is indented in relation to it's parent. The default is 20.

The function set_spacing() sets how far a node is horizontally padded from the vertical line that is drawn linking the nodes of each branch. The default is 5.

The next two functions affect the style of the lines and expander that are drawn to represent the tree structure. An expander is a graphical component that the user can select to expand and collapse a branch of the tree.

$ctree->set_line_style( $line_style );

$ctree->set_expander_style( $expander_style );

The function set_line_style() is used to select the style of line that is drawn between nodes of the tree. The parameter line_style can be one of:

'none'
'solid'
'dotted'
'tabbed'

The function set_expander_style() is used to select the style of branch expander, and the parameter expander_style can be one of:

'none'
'square'
'triangle'
'circular'

38.4. A CTree Example

A CTree Example Source

      
#!/usr/bin/perl -w

use 
Gtk
;
use 
strict
;

set_locale Gtk;
init Gtk;


my
 $false = 0;

my
 $true = 1;


my
 $window;

my
 $scrolled_window;

my
 $ctree;


my
 $closed;

my
 $closed_mask;

my
 $opened;

my
 $opened_mask;

my
 $leaf;

my
 $leaf_mask;


my
 @closed_xpm = ( "16 16 6 1",
		   "       c None s None",
		   ".      c black",
		   "X      c red",
		   "o      c yellow",
		   "O      c #808080",
		   "#      c white",
		   "                ",
		   "       ..       ",
		   "     ..XX.      ",
		   "   ..XXXXX.     ",
		   " ..XXXXXXXX.    ",
		   ".ooXXXXXXXXX.   ",
		   "..ooXXXXXXXXX.  ",
		   ".X.ooXXXXXXXXX. ",
		   ".XX.ooXXXXXX..  ",
		   " .XX.ooXXX..#O  ",
		   "  .XX.oo..##OO. ",
		   "   .XX..##OO..  ",
		   "    .X.#OO..    ",
		   "     ..O..      ",
		   "      ..        ",
		   "                ");

my
 @open_xpm = ( "16 16 4 1",
		 "       c None s None",
		 ".      c black",
		 "X      c #808080",
		 "o      c white",
		 "                ",
		 "  ..            ",
		 " .Xo.    ...    ",
		 " .Xoo. ..oo.    ",
		 " .Xooo.Xooo...  ",
		 " .Xooo.oooo.X.  ",
		 " .Xooo.Xooo.X.  ",
		 " .Xooo.oooo.X.  ",
		 " .Xooo.Xooo.X.  ",
		 " .Xooo.oooo.X.  ",
		 "  .Xoo.Xoo..X.  ",
		 "   .Xo.o..ooX.  ",
		 "    .X..XXXXX.  ",
		 "    ..X.......  ",
		 "     ..         ",
		 "                ");

my
 @leaf_xpm = ( "16 16 4 1",
		 "       c None s None",
		 ".      c black",
		 "X      c white",
		 "o      c #808080",
		 "                ",
		 "   .......      ",
		 "   .XXXXX..     ",
		 "   .XoooX.X.    ",
		 "   .XXXXX....   ",
		 "   .XooooXoo.o  ",
		 "   .XXXXXXXX.o  ",
		 "   .XooooooX.o  ",
		 "   .XXXXXXXX.o  ",
		 "   .XooooooX.o  ",
		 "   .XXXXXXXX.o  ",
		 "   .XooooooX.o  ",
		 "   .XXXXXXXX.o  ",
		 "   ..........o  ",
		 "    oooooooooo  ",
		 "                ");


# Create Window
$window = new Gtk::Window( "toplevel" );
$window->set_usize( 300, 200 );
$window->set_title( "CTree Example" );
$window->signal_connect( "destroy", 
sub
 { Gtk->
exit
( 0 ); } );
$window->border_width( 5 );
$window->realize();

# Create Scrolled Window
$scrolled_window = new Gtk::ScrolledWindow( undef, undef );
$window->add( $scrolled_window );
$scrolled_window->set_policy( 'automatic', 'always' );
$scrolled_window->show();

# Set up Pixmaps
($closed, $closed_mask) = initialize_pixmap( @closed_xpm );
($opened, $opened_mask) = initialize_pixmap( @open_xpm );
($leaf, $leaf_mask) = initialize_pixmap( @leaf_xpm );

# Create CTree
$ctree = create_tree();
$ctree->signal_connect( 'select_row', \&selection_made );
$scrolled_window->add( $ctree );
$ctree->show();

$window->show();
main Gtk;

exit
 0;



### Subroutines


# Since I am hard-coding the values of the tree, I've decided to
# include all that code inside this function.  Once the tree is built,
# it is returned.


sub
 
create_tree

{
   
my
 $tree = new_with_titles Gtk::CTree( 0, "Column 1", "Column 2" );
   $tree->set_column_width( 0, 150 );

   
my
 $root = insert_node( $tree, undef, ["root", "a"], $false );
   
my
 $node = insert_node( $tree, $root, ["branch", "b1"], $false );

   insert_node( $tree, $node, ["leaf", "c11"], $true );
   insert_node( $tree, $node, ["leaf", "c12"], $true );
   insert_node( $tree, $node, ["leaf", "c13"], $true );

   insert_node( $tree, $root, ["leaf", "b2"], $true );

   $node = insert_node( $tree, $root, ["branch", "b3"], $false );
   $node = insert_node( $tree, $node, ["branch", "c31"], $false );

   insert_node( $tree, $node, ["leaf", "d311"], $true );
   insert_node( $tree, $node, ["leaf", "d312"], $true );
   insert_node( $tree, $node, ["leaf", "d313"], $true );
   insert_node( $tree, $node, ["leaf", "d314"], $true );

   
return
 $tree;
}


# Given the tree, parent node (undef for root node), text, and whether
# the node is to be a leaf node, add the node to the tree.


sub
 
insert_node

{
   
my
 ( $tree, $parent, $text, $is_leaf ) = @_;

   
my
 @args;

   
if
 ( $is_leaf )
   {
      @args = ( $leaf, $leaf_mask,
		undef, undef,
		$true, $false );
   }
   
else

   {
      @args = ( $closed, $closed_mask,
		$opened, $opened_mask,
		$false, $true );
   }

   
return
 ( $tree->insert_node( $parent, undef, $text, 5, @args ) );
}


# Callback run when the mouse is clicked inside the CTree.  It does
# nothing more than printing out the text label at the row and column
# in the tree.


sub
 
selection_made

{
   
my
 ( $ctree, $row, $column ) = @_;

   
my
 $node = $ctree->node_nth( $row );
   
my
 $text = $ctree->node_get_text( $node, $column );

   # I think this should work, but I get a segmentation fault
   #my $text = $ctree->get_text( $row, $column );

   
print
( "($row, $column) => $text\n" );
}


# Given a pre-defined xpm, return the pixmap and the mask associated
# with it.


sub
 
initialize_pixmap

{
   
my
 @xpm = @_;

   
my
 $pixmap;
   
my
 $mask;
   
my
 $style = $window->get_style()->bg( 'normal' );

   ($pixmap, $mask) = Gtk::Gdk::Pixmap->create_from_xpm_d( $window->window,
							   $style,
							   @xpm );

   
return
 ( $pixmap, $mask );
}


# END EXAMPLE PROGRAM
      
   

CTree Example Screenshot