Problem
You would like to display a context-sensitive popup menu when there is a right mouse click in a GtkTreeView as shown below:
Solution
- When there is a right mouse click, we first find out the row and column from x,y position of the mouse with GtkTreeview::get_path_at_pos().
- Based on the row and column, we set up a context-sensitive menu. The setting up of popup menu is very similar to that as described in How to set up menu and radio menu - Part 1?
- We then popup the menu with GtkMenu::popup().
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 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 116 117 118 120 121 123 124 125 126 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 155 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 184 185 186 | <?php $window = new GtkWindow(); $window->set_size_request(400, 200); $window->connect_simple('destroy', array('Gtk','main_quit')); $window->add($vbox = new GtkVBox()); // display title $title = new GtkLabel("Display popup menu with right mouse click"); $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); // the 2D table $data = array( array('row0', 'item 42', 2, 3.1), array('row1', 'item 36', 20, 6.21), array('row2', 'item 21', 8, 9.36), array('row3', 'item 10', 11, 12.4), array('row4', 'item 7', 5, 15.5), array('row5', 'item 4', 17, 18.6), array('row6', 'item 3', 20, 21.73)); 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 GtkListStore(GObject::TYPE_STRING, GObject::TYPE_STRING, GObject::TYPE_LONG, GObject::TYPE_DOUBLE); } else { $model = new GtkListStore(Gtk::TYPE_STRING, Gtk::TYPE_STRING, Gtk::TYPE_LONG, Gtk::TYPE_DOUBLE); } $field_header = array('Row #', 'Description', 'Qty', 'Price'); $field_justification = array(0.0, 0.0, 0.5, 1.0); // Creates the view to display the list store $view = new GtkTreeView($model); $scrolled_win->add($view); $view->connect('button-press-event', 'on_button'); // note 1 // Creates the columns for ($col=0; $col<count($field_header); ++$col) { $cell_renderer = new GtkCellRendererText(); $cell_renderer->set_property("xalign", $field_justification[$col]); $column = new GtkTreeViewColumn($field_header[$col], $cell_renderer, 'text', $col); $column->set_alignment($field_justification[$col]); $column->set_sort_column_id($col); // set the header font and color $label = new GtkLabel($field_header[$col]); $label->modify_font(new PangoFontDescription("Arial Bold")); $label->modify_fg(Gtk::STATE_NORMAL, GdkColor::parse("#0000FF")); $column->set_widget($label); $label->show(); // setup self-defined function to display alternate row color $column->set_cell_data_func($cell_renderer, "format_col", $col); $view->append_column($column); } // pupulates the data for ($row=0; $row<count($data); ++$row) { $values = array(); for ($col=0; $col<count($data[$row]); ++$col) { $values[] = $data[$row][$col]; } $model->append($values); } // setup selection $selection = $view->get_selection(); $selection->connect('changed', 'on_selection'); } function format_col($column, $cell, $model, $iter, $col_num) { $path = $model->get_path($iter); $row_num = $path[0]; if ($col_num==3) { $amt = $model->get_value($iter, 3); $cell->set_property('text', '$'.number_format($amt,2)); } $row_color = ($row_num%2==1) ? '#dddddd' : '#ffffff'; $cell->set_property('cell-background', $row_color); } // the function that is called when user selects a row function on_selection($selection) { list($model, $iter) = $selection->get_selected(); $desc = $model->get_value($iter, 1); $qty = $model->get_value($iter, 2); $price = $model->get_value($iter, 3); print "You have selected $desc: $qty ($price)\n"; } function on_button($view, $event) { if ($event->button==1) return false; // note 2 if ($event->button==2) return true; // do nothing if ($event->button==3) { // it's the right mouse button! // get the row and column $path_array = $view->get_path_at_pos($event->x, $event->y); $path = $path_array[0][0]; $col = $path_array[1]; $col_title = $col->get_title(); popup_menu($path, $col_title, $event); // displays the popup menu return true; } } function popup_menu($path, $col_title, $event) { global $menu; // define the context-sensitive menu $menu_definition = array('Reserve this item', '<hr>', 'Show Item Details', 'Show Sales Transactions', 'Show Out-of-stock Items'); if ($col_title=='Description') { $menu_definition = array_merge( $menu_definition, array('<hr>', 'Edit Item Description')); } elseif ($col_title=='Qty') { $menu_definition = array_merge($menu_definition, array('<hr>', 'Show Qty by Stock Location', 'Set Safety Stock Level')); } elseif ($col_title=='Price') { $menu_definition = array_merge($menu_definition, array('<hr>', 'Edit Price', 'Show Price Movement')); } $menu = show_popup_menu($menu_definition); // show the popup menu } // show popup menu function show_popup_menu($menu_definition) { $menu = new GtkMenu(); foreach($menu_definition as $menuitem_definition) { if ($menuitem_definition=='<hr>') { $menu->append(new GtkSeparatorMenuItem()); } else { $menu_item = new GtkMenuItem($menuitem_definition); $menu->append($menu_item); $menu_item->connect('activate', 'on_popup_menu_select'); } } $menu->show_all(); $menu->popup(); } // process popup menu item selection function on_popup_menu_select($menu_item) { $item = $menu_item->child->get_label(); echo "popup menu selected: $item\n"; } ?> |
Output
As shown above.Explanation
The above sample code is based on How to display a 2D array in GtkTreeView - Part 5 - get user selection?.
What's new here:
- If you have tried the code in How to display a 2D array in GtkTreeView - Part 5 - get user selection?, you will find that selecting a row in GtkTreeView is possible using left, right or middle mouse button. We added this
$view->connect('button-press-event')
so that we can program it such that selection can only be done using left mouse button. The right mouse button will active the popup menu. - When user select with left button, we simply return a
false
. This effectively returns the control to php-gtk for the default action, which is to select and highlight the particular row.
Read more...