245. How to show leaves only for a treemodel?

Problem

This is in response to Edgarwilde's post titled "treeview leafs only"

Suppose you have set up a tree model as shown below:

And now you would like to allow users to have another view that shows only the leaves of the tree model as shown below:


Solution


Sample Code

1   
2   
3   
4   
5   
6   
7   
8   
9   
10   
11   
12   
13   
14   
15   
16   
17   
18   
19   
20   
21   
22   
23   
24   
25   
26   
27   
28   
29   
30   
31   
32   
33   
34   
35   
36   
37   
38   
39   
40   
41   
42   
43   
44   
45   
46   
47   
48   
49   
50   
51   
52   
53   
54   
55   
56   
57   
58   
59   
60   
61   
62   
63   
64   
65   
66   
67   
68   
69   
70   
71   
77   
78   
79   
80   
81   
82   
83   
84   
85   
87   
88   
89   
90   
91   
92   
93   
94   
95   
96   
97   
98   
99   
100   
101   
102   
103   
105   
106   
107   
108   
109   
110   
111   
112   
113   
114   
115   
116   
117   
118   
119   
120   
121   
122   
123   
124   
125   
126   
128   
129   
130   
131   
132   
133   
135   
136   
137   
138   
<?php

$window = new GtkWindow();
$window->set_title($argv[0]);
$window->set_size_request(400, 240);
$window->connect_simple('destroy', array('Gtk','main_quit'));
$window->add($vbox = new GtkVBox());

// display title
$title = new GtkLabel("Show Leaves only for a TreeModel");
$title->modify_font(new PangoFontDescription("Times New Roman Italic 10"));
$title->modify_fg(Gtk::STATE_NORMAL, GdkColor::parse("#0000ff"));
$title->set_size_request(-1, 40);
$vbox->pack_start($title, 0, 0);
$vbox->pack_start(new GtkLabel(), 0, 0);

$vbox->pack_start($hbox = new GtkHBox(), 0);
$hbox->pack_start($button = new GtkButton('Show Leaves Only'), 0);
$tree_mode = 1;
$button->connect('clicked', 'on_click');

$data = array(
    array ('id' => '101', 'parent' => '0', 'data' => 'a'),
    array ('id' => '102', 'parent' => '101', 'data' => 'a1'),
    array ('id' => '103', 'parent' => '102', 'data' => 'a11'),
    array ('id' => '104', 'parent' => '102', 'data' => 'a12'),
    array ('id' => '105', 'parent' => '101', 'data' => 'a2'),
    array ('id' => '201', 'parent' => '0', 'data' => 'b'),
    array ('id' => '202', 'parent' => '201', 'data' => 'b1'),
    array ('id' => '203', 'parent' => '202', 'data' => 'b11')
);

display_table($vbox, $data);

$window->show_all();
Gtk::main();

function display_table($vbox, $data) {

    // Set up a scroll window
    $scrolled_win = new GtkScrolledWindow();
    $scrolled_win->set_policy( Gtk::POLICY_AUTOMATIC,
        Gtk::POLICY_AUTOMATIC);
    $vbox->pack_start($scrolled_win);

    // Creates the list store
    global $model, $model_leaves;
    if (defined("GObject::TYPE_STRING")) {
        $model = new GtkTreeStore(GObject::TYPE_LONG, 
            GObject::TYPE_STRING, GObject::TYPE_STRING); // note 1
        $model_leaves = new GtkListStore(GObject::TYPE_LONG, 
            GObject::TYPE_STRING, GObject::TYPE_STRING); // note 2
    } else {
        $model = new GtkTreeStore(Gtk::TYPE_LONG, 
            Gtk::TYPE_STRING, Gtk::TYPE_STRING); // note 1
        $model_leaves = new GtkListStore(Gtk::TYPE_LONG, 
            Gtk::TYPE_STRING, Gtk::TYPE_STRING); // note 2
    }
    $field_header = array('id', 'title', 'data');

    // Set up the view
    global $view;
    $view = new GtkTreeView($model);
    $scrolled_win->add($view);

    // Creates the columns
    for ($col=0; $col<count($field_header); ++$col) {
        $cell_renderer = new GtkCellRendererText();
        $column = new GtkTreeViewColumn($field_header[$col],
            $cell_renderer, 'text', $col);
        $view->append_column($column);
    }

    // pupulates the data
    $nodes = array();
    $nodes[0] = null; // root
    foreach($data as $item) {
        $id = $item['id'];
        $parent = $item['parent'];
        $data = $item['data'];
        $nodes[$id] = $model->append($nodes[$parent],
            array($id, "this is id $id", $data));
    }

    $view->expand_all();
}

function on_click($button) {
    global $tree_mode;
    if ($tree_mode) {
        $button->set_label('Show Entire Tree');
        $tree_mode = 0;
    } else {
        $button->set_label('Show Leaves Only');
        $tree_mode = 1;
    }

    global $view, $model, $model_leaves;
    if ($tree_mode) {
        $view->set_model($model);
        $view->expand_all();
        $view->get_column(0)->set_visible(1);
        $view->get_column(1)->set_visible(1);
    } else {
        $model_leaves->clear();
        get_leaves($model);
        $view->set_model($model_leaves); // note 6
        $view->get_column(0)->set_visible(0); // note 7
        $view->get_column(1)->set_visible(0); 
    }
}

function get_leaves($model) {
     $model->foreach('process'); // note 3
}

function process($model, $path, $iter) {
    global $model_leaves;
    $num_children = $model->iter_n_children($iter); // note 4
    if ($num_children==0) {
        $id = $model->get_value($iter, 0);
        $title = $model->get_value($iter, 1);
        $data = $model->get_value($iter, 2);
        $path2 = implode('-', $path);
        $model_leaves->append(array($id, $title, $data)); // note 5
    }
}

?>

Output

As shown above.

 

Explanation

The above example makes use of the code from How to display a tree structure from array? and How to iterate through a GtkTreeStore?

What's new here:

  1. The base tree model.
  2. The list store for the leaves.
  3. Loop through the entire tree model to extract just the leaves.
  4. Test if the node is a leave.
  5. Add the leave to the list store.
  6. Display the list store in the treeview!
  7. In the event that you just want to show the leaves, you can hide the first two columns. If not, just comment out these two lines.

Related Links

Add comment


Security code
Refresh