Problem
You would like to capture key press, say left and right arrow, only when the treeview is in focus, i.e. when the user's mouse is somewhere inside the treeview as shown below:
Solution
This might look simple. But when you tried it out, it's not that striaghtforward.
- If you set up
$treeview->connect('key-press-event', 'on_keypress')
, you will find that you still receive key-press-events even when your cursor is outside treeview. - $treeview->is_focus() only works when the user clicks somewhere inside the treeview. If user clicks somewhere outside the treeview, and then move the mouse inside the treeview,
$treeview->in_focus()
will return afalse
.
The solution is to make use of the technique as explained in the article How to display tooltips in GtkTreeView - Part 2?
- Use GtkWidget::motion-notify-event() to know when the mouse enters the treeview.
- Use GtkWidget::leave-notify-event() to know when the mouse leaves the treeview.
- Use GtkWidget::get_pointer() to know if the mouse is in the column header region.
Sample Code
Note: If you have installed php-gtk2 using Gnope Installer on Windows, and if running the sample code below gives you warning that the Symbolic names for keys (e.g. Gdk::KEY_Return) is not defined, you might want to update your php-gtk2 with the latest php-gtk2.dll available here. Simply download the php-gtk2.dll and replace the copy in the folder php-gtk2xt. The latest compilation has put in the Symbolic names for keys listed here.
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 93 94 95 96 97 98 99 100 103 104 105 106 107 108 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 136 139 142 144 147 148 149 150 151 152 154 155 156 157 159 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 | <?php $window = new GtkWindow(); $window->set_size_request(400, 300); $window->connect_simple('destroy', array('Gtk','main_quit')); $window->add($vbox = new GtkVBox()); // display title $title = new GtkLabel("Capturing key-press-event in GtkTreeView\n"); $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( 'The following is active only when cursor is inside treeview'), 0, 0); $vbox->pack_start(new GtkLabel('Return - display detail'), 0, 0); $vbox->pack_start(new GtkLabel('Left Arrow - prev page'), 0, 0); $vbox->pack_start(new GtkLabel('Right Arrow - next page'), 0, 0); $vbox->pack_start(new GtkLabel('Alt Left Arrow - first page'), 0, 0); $vbox->pack_start(new GtkLabel('Alt Right Arrow - last page'), 0, 0); $vbox->pack_start(new GtkLabel(), 0, 0); // the 2D table $data = array( array('row0', 'item 19', 2, 3.1), array('row1', 'item 16', 20, 6.21), array('row2', 'item 13', 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)); $view_in_focus = 0; // note 1 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); // 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 event handlers to let us know if mouse is in treeview $view->connect('motion-notify-event', 'on_motion'); // note 2 $view->connect('leave-notify-event', 'on_leave'); // note 2 // setup selection $selection = $view->get_selection(); $selection->connect('changed', 'on_selection'); $view->connect('key-press-event', 'on_key_press', $selection); // note 3 } // set alternate row color function format_col($column, $cell, $model, $iter, $col_num) { $path = $model->get_path($iter); // get the current path $row_num = $path[0]; // get the row number 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); } // process user selection function on_selection($selection) { list($model, $iter) = $selection->get_selected(); if ($iter==NULL) return; $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_motion($view, $event) { // note 4 global $view_in_focus; // check if mouse is in column headers $scroll_win_pos = $view->get_pointer(); // note 4 if ($scroll_win_pos[1]<=25) { // in column header? $view_in_focus = 0; } else { $view_in_focus = 1; } return true; } function on_leave($view, $event) { // note 5 global $view_in_focus; $view_in_focus = 0; } function on_key_press($widget, $event, $selection) { global $view_in_focus; if (!$view_in_focus) return; // note 6 switch($event->keyval) { case Gdk::KEY_Return: list($model, $iter) = $selection->get_selected(); if ($iter==NULL) { echo "no selection!\n"; } else { echo "key press. Return: open detail\n"; } return true; break; case Gdk::KEY_Left: if($event->state==0) { echo "key press: Left Arrow - prev page\n"; return true; } elseif ($event->state & Gdk::MOD1_MASK){ echo "key press. Alt Left Arrow: first page\n"; return true; } return false; break; case Gdk::KEY_Right: if($event->state==0) { echo "key press: Right Arrow - next page\n"; return true; } elseif ($event->state & Gdk::MOD1_MASK){ echo "key press. Alt Right Arrow: last page\n"; return true; } return false; break; default: return false; } } ?> |
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:
- A global variable to know if treeview is in focus.
- Check if treeview is in focus.
- Receive key-press-event.
- Check if mouse is in header region. Please refer to How to display tooltips in GtkTreeView - Part 2? for details.
- Treeview is now out of focus.
- Process key press only when treeview is in focus.
Read more...