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
- The original treemodel is set up using the technique as outlined in How to display a tree structure from array?.
- In addition to the base GtkTreemodel, we set up another GtkListStore to store the leaves.
- When the user switch from tree view to leaves view, we iterate through the base treemodel to extract all the leaves using the method as described in How to iterate through a GtkTreeStore?
- Once we have all the leaves in the liststore, we just swap the model from the treemodel to the leaves model using GtkTreeview::set_model().
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:
- The base tree model.
- The list store for the leaves.
- Loop through the entire tree model to extract just the leaves.
- Test if the node is a leave.
- Add the leave to the list store.
- Display the list store in the treeview!
- 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.
Read more...