Problem
You have set up File Save using GtkFileChooser in Part 1. However, there are two areas for improvements:
- When in File Chooser, pressing ESC should quit the dialog.
- When in File Chooser, when the user has entered the filename, pressing Enter should be equivalent to pressing the OK button.
Solution
- Set up a key-press-event to capture the ESC and Enter key.
- When Enter is pressed, we simulate a button click on the OK button with GtkButton::clicked().
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 19 20 21 22 23 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 42 43 44 48 49 50 51 52 53 54 55 57 58 59 60 61 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 82 84 85 86 87 88 94 95 96 100 101 102 104 105 106 107 108 109 110 111 112 113 114 116 117 118 119 120 121 122 123 124 125 126 127 128 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 164 165 166 167 168 169 175 176 178 180 181 182 183 184 185 187 194 195 196 198 199 203 204 205 206 207 208 210 213 214 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 236 237 238 239 240 241 242 243 | <?php $window = new GtkWindow(); $window->set_size_request(400, 150); $window->connect_simple('destroy', array('Gtk','main_quit')); $window->add($vbox = new GtkVBox()); $accel_group = new GtkAccelGroup(); $window->add_accel_group($accel_group); // define menu definition $menu_definition = array( '_File' => array('_New|N', '_Open|O', '_Close|C', '<hr>', '_Save|S', 'Save _As','<hr>', 'E_xit'), '_Edit' => array('Cu_t|X', '_Copy|C', '_Paste|V', '<hr>', 'Select _All|A', '<hr>', '_Undo|Z','_Redo|Y'), '_Test' => array('Test_1|1', 'Test_2|2', 'Test_3|3', '<hr>', array('Selection 1', 'Selection 2', 'Selection 3'), '<hr>', 'Test_4|4') ); $menu = new Menu($vbox, $menu_definition, $accel_group); // display title $title = new GtkLabel("Save a file with GtkFileChooser - Part 2"); $title->modify_font(new PangoFontDescription("Times New Roman Italic 10")); $title->modify_fg(Gtk::STATE_NORMAL, GdkColor::parse("#0000ff")); $vbox->pack_start($title); $vbox->pack_start(new GtkLabel("Press Ctrl-S to save a file")); $vbox->pack_start(new GtkLabel("Supports Esc and Enter")); $vbox->pack_start(new GtkLabel("")); $window->show_all(); Gtk::main(); // class Menu class Menu { var $prev_keyval = 0; var $prev_state = 0; var $prev_keypress = ''; function Menu($vbox, $menu_definition, $accel_group) { $this->menu_definition = $menu_definition; $menubar = new GtkMenuBar(); $vbox->pack_start($menubar, 0, 0); foreach($menu_definition as $toplevel => $sublevels) { $top_menu = new GtkMenuItem($toplevel); $menubar->append($top_menu); $menu = new GtkMenu(); $top_menu->set_submenu($menu); // let's ask php-gtk to tell us when user press the 2nd Alt key $menu->connect('key-press-event', array(&$this, 'on_menu_keypress'), $toplevel); foreach($sublevels as $submenu) { if (strpos("$submenu", '|') === false) { $accel_key = ''; } else { list($submenu, $accel_key) = explode('|', $submenu); } if (is_array($submenu)) { // set up radio menus $i=0; $radio[0] = null; foreach($submenu as $radio_item) { $radio[$i] = new GtkRadioMenuItem($radio[0], $radio_item); $radio[$i]->connect('toggled', array(&$this, "on_toggle")); $menu->append($radio[$i]); ++$i; } $radio[0]->set_active(1); // select the first item } else { if ($submenu=='<hr>') { $menu->append(new GtkSeparatorMenuItem()); } else { $submenu2 = str_replace('_', '', $submenu); $submenu2 = str_replace(' ', '_', $submenu2); $stock_image_name = 'Gtk::STOCK_'.strtoupper($submenu2); if (defined($stock_image_name)) { $menu_item = new GtkImageMenuItem(constant($stock_image_name)); } else { $menu_item = new GtkMenuItem($submenu); } if ($accel_key!='') { $menu_item->add_accelerator("activate", $accel_group, ord($accel_key), Gdk::CONTROL_MASK, 1); } $menu->append($menu_item); $menu_item->connect('activate', array(&$this, 'on_menu_select')); $this->menuitem[$toplevel][$submenu] = $menu_item; } } } } } // process radio menu selection function on_toggle($radio) { $label = $radio->child->get_label(); $active = $radio->get_active(); echo("radio menu selected: $label\n"); } // process menu item selection function on_menu_select($menu_item) { $item = $menu_item->child->get_label(); echo "menu selected: $item\n"; if (method_exists($this, $item)) $this->$item(); if ($item=='E_xit') Gtk::main_quit(); } // let user choose a file with a file chooser dialog function _Open() { $dialog = new GtkFileChooserDialog("File Save", null, Gtk::FILE_CHOOSER_ACTION_OPEN, array(Gtk::STOCK_OK, Gtk::RESPONSE_OK), null); $dialog->connect('key-press-event', array(&$this, 'on_dialog_keypress'), $dialog); $dialog->show_all(); if ($dialog->run() == Gtk::RESPONSE_OK) { $selected_file = $dialog->get_filename(); echo "selected_file = $selected_file\n"; } $dialog->destroy(); } // let user choose a file with a file chooser dialog function _Save() { $dialog = new GtkFileChooserDialog("File Save", null, Gtk::FILE_CHOOSER_ACTION_SAVE, array(Gtk::STOCK_OK, Gtk::RESPONSE_OK), null); $dialog->connect('key-press-event', array(&$this, 'on_dialog_keypress'), $dialog); // note 1 $dialog->show_all(); if ($dialog->run() == Gtk::RESPONSE_OK) { $selected_file = $dialog->get_filename(); // get the input filename echo "selected_file = $selected_file\n"; } $dialog->destroy(); } // processing of menu keypress function on_menu_keypress($menu, $event, $toplevel) { if (!$event->state & Gdk::MOD1_MASK) return false; // get the ascii equivalent of the keypress $keypress = ''; if ($event->keyval<255) { $keypress = chr($event->keyval); // ascii equivalent $keypress = strtolower($keypress); // convert to lowercase } $match = 0; // flag to see if there's a match foreach($this->menu_definition[$toplevel] as $submenu) { if (!preg_match("/.*_([a-zA-Z0-9]).*/", "$submenu", $matches)) continue; $key2 = strtolower($matches[1]); if ($keypress==$key2) { if (strpos("$submenu", '|') === false) { $accel_key = ''; } else { list($submenu, $accel_key) = explode('|', $submenu); } $menuitem = $this->menuitem[$toplevel][$submenu]; $menuitem->activate(); $menu->popdown(); $match = 1; break; } } return $match; } function on_dialog_keypress($widget, $event, $dialog) { if ($event->keyval==Gdk::KEY_Escape) { // note 2 $dialog->destroy(); return true; } if ($event->keyval==Gdk::KEY_Return) { // note 3 $button = end(end(current($dialog->get_children())->get_children())->get_children()); // note 4 $button->clicked(); // note 3 return true; } } } ?> |
Output
Explanation
The above sample code is based on How to save a file with GtkFileChooser - Part 1?.
What's new here:
- Set up the key-press-event to capture the ESC and Enter key.
- For ESC key, just destroy the dialog.
- For Enter key, we simulate a button click on the OK button with GtkButton::clicked().
- Here we try to "dig" out the ID of the OK button, starting from the $dialog. We need the ID of the OK button so that we can click on it.
Read more...