Problem
You have set up a login prompt in Part 1. However, there are a number of "annoyances":
- Pressing Enter does not automatically go to next field, or activates the "OK" button.
- Suppose the user enters an invalid username or password, the login form gets destroyed, the alert box appears, and the login form re-appears agian. Ideally the login form should only disappear after the user has keyed in the correct username and password.
We will fix (1) in this article. (2) will be fixed in Part 3.
Solution
- Use GtkWidget::key-press-event() to "intercept" the <Enter> key and make it behave the way we want it to be.
- If user has not input username or password, we can use GtkWidget::grab_focus() to put the focus on the field that is still empty.
- When user has input both username and password, we can use GtkButton::clicked() to simulate a button click on the "OK" button.
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 27 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 49 50 51 52 53 54 55 56 58 59 61 62 63 64 65 67 68 69 76 77 78 79 80 81 82 83 84 88 89 90 91 92 93 96 98 99 101 102 103 104 105 106 107 108 109 112 113 114 115 116 117 118 119 120 121 122 123 124 125 127 128 129 130 131 132 133 134 135 136 137 | <?php $login_success = login(); // calls the login function if (!$login_success) exit(0); // exit if login not successful // starts the main program only if login successful $window = new GtkWindow(); $window->set_size_request(400, 150); $window->connect_simple('destroy', array('Gtk','main_quit')); $window->add($vbox = new GtkVBox()); // display title $title = new GtkLabel("Login prompt - Part 2"); $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("User verified")); $vbox->pack_start(new GtkLabel("Main program starts...")); // the login function function login() { $count = 0; while ($count<3) { $data = get_data("Login", array("Username:", "Password:")); list($username, $password) = $data; if ($username=='user1' && $password=='phpgtk2') { return true; } else { alert("Incorrect username and password!\nHint: username=user1\npassword=phpgtk2"); } ++$count; } return false; } // display a popup dialog box to prompt for data function get_data($title, $field_labels) { $dialog = new GtkDialog($title, null, Gtk::DIALOG_MODAL); $dialog->set_position(Gtk::WIN_POS_CENTER_ALWAYS); $top_area = $dialog->vbox; $top_area->pack_start($hbox = new GtkHBox()); $stock = GtkImage::new_from_stock(Gtk::STOCK_DIALOG_QUESTION, Gtk::ICON_SIZE_DIALOG); $hbox->pack_start($stock, 0, 0); $table = new GtkTable(); $row = 0; $input = array(); foreach ($field_labels as $field_label) { $label = new GtkLabel($field_label); $label->set_alignment(0,0); $table->attach($label, 0, 1, $row, $row+1); $input[$row] = new GtkEntry(); $table->attach($input[$row], 1, 2, $row, $row+1); if (eregi("password", $field_label)) $input[$row]->set_visibility(false); ++$row; } $hbox->pack_start($table); $dialog->add_button(Gtk::STOCK_OK, Gtk::RESPONSE_OK); $buttons = $dialog->action_area->get_children(); // note 1 $button_ok = $buttons[0]; // note 1 $dialog->connect('key-press-event', 'on_key', $input, $button_ok); // note 1 $dialog->set_has_separator(false); $dialog->show_all(); $dialog->run(); $data = array(); for ($i=0; $i<count($input); ++$i) { $data[] = $input[$i]->get_text(); } $dialog->destroy(); return $data; } // process key press function on_key($widget, $event, $input, $button) { if ($event->keyval!=Gdk::KEY_Return) return false; // note 2 $username = $input[0]->get_text(); // get username $passwd = $input[1]->get_text(); // get password if ($username=='') { $input[0]->grab_focus(); // note 3 return true; // note 3 } if ($passwd=='') { $input[1]->grab_focus(); // note 4 return true; // note 4 } if ($username!='' && $passwd!='') { $button->clicked(); // note 5 } } function alert($msg) { $dialog = new GtkDialog('Alert', null, Gtk::DIALOG_MODAL); $dialog->set_position(Gtk::WIN_POS_CENTER_ALWAYS); $top_area = $dialog->vbox; $top_area->pack_start($hbox = new GtkHBox()); $stock = GtkImage::new_from_stock(Gtk::STOCK_DIALOG_WARNING, Gtk::ICON_SIZE_DIALOG); $hbox->pack_start($stock, 0, 0); $hbox->pack_start(new GtkLabel($msg)); $dialog->add_button(Gtk::STOCK_OK, Gtk::RESPONSE_OK); $dialog->set_has_separator(false); $dialog->show_all(); $dialog->run(); $dialog->destroy(); } $window->show_all(); Gtk::main(); ?> |
Output
Explanation
- Set up the event handler to capture all key-press events. Note that we need to pass along the IDs of both the input fields and the OK button. The IDs of the input fields are stored in the array
$input
. The OK button is created using php-gtk's built-in function$dialog->add_button
. Php-gtk does not directly tell us what's the ID of the button. However, we can "indirectly" get the ID of the button. First use$dialog->action_area->get_children()
to get the list of buttons created by$dialog->add_button
. We have only one OK button here. Hence$buttons[0]
is our OK button. - We only want to "intercept" the <Enter> key. So if the keypress is not <Enter>, we return a
false
, and php-gtk will take over and handle this signal with its default handler. - If user has not input username, we use grab_focus() to prompt the user for input. Remember to use
return true
to tell php-gtk that we're done processing the <Enter> key. - If user has not input password, we use grab_focus() to prompt the user for input. Remember to use
return true
to tell php-gtk that we're done processing the <Enter> key. - When user has input both username and password, we simulate a click on the OK button with GtkButton::clicked().
The net effect of the above is that:
- When user enters username and press <Enter>, the cursor will automatically move to the password field.
- When user enters the password and press <Enter>, the OK button will automatically be clicked and enters validation check of username and password.
- If any of the field is still empty, the cursor will be placed on that field.
Note
We still have not fixed the other annoyance: "Suppose the user enters an invalid username or password, the login form gets destroyed, the alert box appears, and the login form re-appears agian. Ideally the login form should only disappear after the user has keyed in the correct username and password."
We will fix this in Part 3.
Read more...