Problem
This is in response to Giovanni's post titled "a button with an image in it in a Treeview".
In Part 1, I've showed a solution using GtkListStore.
In this Part 2, I present the same solution, but using GtkTreeStore instead of GtkListStore so that the projects and activities can be shown in a treeview manner as shown below.
Note that I've also changed the millisecond timer to a seconds timer because it seems that having more than 6 concurrent millisecond timer running in a treeview seems to be a bit too taxing for the treeview. You can try it for yourself. The timer doesn't get updated often enough, even though we set the timeout at 1ms interval.
Solution
- We use exactly the same technique as outlined in Part 1.
- We make use of the technique from How to display a tree structure from array? to populate a tree model.
- Note also that I've added 2 more columns to the tree model: column 7 to store the ID of the item, and column 8 to store the ID of its parent.
Sample Code
The following image files are required by the sample code below. Please save a copy of the image files and put them in the same directory where you store the sample code.
button_start32.gif | |
button_stop32.gif | |
button_blank32.gif (note: this one looks empty, but there's a blank image there. I added a border so that you can see it.) |
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 72 73 74 75 76 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 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 121 122 124 125 126 127 128 129 130 131 132 133 134 138 139 140 145 146 147 149 150 151 152 154 155 156 158 159 160 161 162 164 165 166 168 169 170 171 172 173 174 175 176 177 178 180 181 182 183 192 193 | <?php $window = new GtkWindow(); $window->set_title($argv[0]); $window->set_size_request(400, 400); $window->connect_simple('destroy', array('Gtk','main_quit')); $window->add($vbox = new GtkVBox()); // display title $title = new GtkLabel("Start/Stop buttons in GtkTreeView\n". " Part 2 - using Tree Model"); $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); $vbox->pack_start(new GtkLabel(), 0); // the 2D table $data = array( array('Project 1', 0, 0, 0, 0, '', 0, 1, 0), array('Activity 1.1', 1, 0, 0, 0, '', 0, 2, 1), array('Activity 1.2', 1, 0, 0, 0, '', 0, 3, 1), array('Project 2', 0, 0, 0, 0, '', 0, 4, 0), array('Activity 2.1', 1, 0, 0, 0, '', 0, 5, 4), array('Activity 2.2', 1, 0, 0, 0, '', 0, 6, 4), array('Activity 2.3', 1, 0, 0, 0, '', 0, 7, 4), array('Activity 2.4', 1, 0, 0, 0, '', 0, 8, 4), ); 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 if (defined("GObject::TYPE_STRING")) { $model = new GtkTreeStore( // note 1 GObject::TYPE_STRING, // col 0: column title GObject::TYPE_BOOLEAN, // col 1: boolean - 1 to display start/stop icon GObject::TYPE_BOOLEAN, // col 2: boolean - 0=stop 1=start GObject::TYPE_DOUBLE, // col 3: start time in float GObject::TYPE_DOUBLE, // col 4: time elapsed in float GObject::TYPE_STRING, // col 5: time elapsed in string GObject::TYPE_LONG, // col 6: timeout id GObject::TYPE_LONG, // col 7: id of this item GObject::TYPE_LONG // col 8: parent id of this item ); } else { $model = new GtkTreeStore( // note 1 Gtk::TYPE_STRING, // col 0: column title Gtk::TYPE_BOOLEAN, // col 1: boolean - 1 to display start/stop icon Gtk::TYPE_BOOLEAN, // col 2: boolean - 0=stop 1=start Gtk::TYPE_DOUBLE, // col 3: start time in float Gtk::TYPE_DOUBLE, // col 4: time elapsed in float Gtk::TYPE_STRING, // col 5: time elapsed in string Gtk::TYPE_LONG, // col 6: timeout id Gtk::TYPE_LONG, // col 7: id of this item Gtk::TYPE_LONG // col 8: parent id of this item ); } // Creates the view to display the list store $view = new GtkTreeView($model); $scrolled_win->add($view); $view->connect('button-press-event', 'on_buttonpress', $model); // setup col 0 $cell_renderer = new GtkCellRendererText(); // note 2 $column = new GtkTreeViewColumn('Project/Activity', $cell_renderer, 'text', 0); $column->set_cell_data_func($cell_renderer, 'format_col', 0); $view->append_column($column); // setup col 1 (the buttons) $cell_renderer = new GtkCellRendererPixbuf(); $column = new GtkTreeViewColumn(); $column->pack_start($cell_renderer); $column->set_cell_data_func($cell_renderer, 'format_col', 1); $column->set_title('Action'); $view->append_column($column); // setup col 2 $cell_renderer = new GtkCellRendererText(); $column = new GtkTreeViewColumn('Time', $cell_renderer, 'text', 5); $column->set_cell_data_func($cell_renderer, 'format_col', 5); $view->append_column($column); // pupulates the data $nodes = array(); // note 3 $nodes[0] = null; // root for ($row=0; $row<count($data); ++$row) { $id = $data[$row][7]; $parent = $data[$row][8]; $values = array(); for ($col=0; $col<count($data[$row]); ++$col) { $values[] = $data[$row][$col]; } $nodes[$id] = $model->append($nodes[$parent], $values); } $view->expand_all(); // note 4 if (method_exists($view, 'set_enable_tree_lines')) $view->set_enable_tree_lines(1); $selection = $view->get_selection(); $selection->set_mode(Gtk::SELECTION_NONE); } // self-defined function to display alternate row color function format_col($column, $cell, $model, $iter, $col_num) { $path = $model->get_path($iter); if ($col_num==1) { if ($model[$iter][8]!=0) { // note 5 if ($model[$iter][2]==0) { $pixbuf = GdkPixbuf::new_from_file("button_start32.gif"); } else { $pixbuf = GdkPixbuf::new_from_file("button_stop32.gif"); } } else { $pixbuf = GdkPixbuf::new_from_file("button_blank32.gif"); } $cell->set_property('pixbuf', $pixbuf); } } function on_buttonpress($view, $event, $model) { if ($event->button==1 && $event->type==4) { // get the row and column $path_array = $view->get_path_at_pos($event->x, $event->y); $path = $path_array[0]; // note 6 $col = $path_array[1]; $col_title = $col->get_title(); if ($col_title!='Action') return false; // note 7 if ($model[$path][2]) { $model[$path][2] = 0; $elapsed_time = microtime(1) - $model[$path][3]; $model[$path][4] += $elapsed_time; Gtk::timeout_remove($model[$path][6]); } else { // note 7 $model[$path][2] = 1; $model[$path][3] = microtime(1); $model[$path][6] = Gtk::timeout_add(1000, 'update_time', $model, $path); // note 8 } return true; } elseif ($event->button==2) { return false; } elseif ($event->button==3) { return false; } } function update_time($model, $path) { $elapsed_time = microtime(1) - $model[$path][3]; $elapsed_time += $model[$path][4]; $model[$path][5] = date('H:i:s', $elapsed_time); return true; } ?> |
Output
As shown above.Explanation
- Note that we changed this from GtkListStore to GtkTreeStore. We also added column 7 to store the ID of the item, and column 8 to store the ID of its parent.
- Note that we have changed the "Project/Activity" to the first column so that the projects and activities are presented in a hierarchical manner.
- We make use of the technique as outlined in How to display a tree structure from array? to populate the data to the treemodel.
- Expand the entire tree.
- Display start/stop button for activities only.
- Note that for treemodel, this is not changed to
$path = $path_array[0]
- We only want to process button clicks on the start/stop buttons.
- Note that I've changed this from 1 millisecond to 1 second.
Related Links
- How to have a start stop button in GtkTreeView - Part 1 - using liststore?
- How to have a start stop button in GtkTreeView - Part 2 - using treestore?
- How to have a start stop button in GtkTreeView - Part 3 - update parent?
- How to display a tree structure from array?
- How to display a 2D array in GtkTreeView - Part 3 - with alternate row colors?
- How to display gif or jpg images in GtkTreeView - Part 1?
- How to display context sensitive popup menu with right mouse click in GtkTreeView?
- How to set up a stopwatch accurate to hundredth of a second?
Read more...