20.9.1 Problem
20.9.2 Solution
Create a GtkMenu. Create
individual GtkMenuItem objects for each menu
item you want to display and add each menu item to the GtkMenu with append( ). Then, create a root menu
GtkMenuItem with the label that should appear in the menu bar (e.g.,
"File" or "Options"). Add the menu to the root menu with set_submenu(
). Create a GtkMenuBar and add the root menu to the menu
bar with append( ). Finally, add the menu bar to the window:
// create the window
$window = &new GtkWindow();
// create a menu
$menu = &new GtkMenu();
// create a menu item and add it to the menu
$menu_item_1 = &new GtkMenuItem('Open');
$menu->append($menu_item_1);
// create another menu item and add it to the menu
$menu_item_2 = &new GtkMenuItem('Close');
$menu->append($menu_item_2);
// create yet another menu item and add it to the menu
$menu_item_2 = &new GtkMenuItem('Save');
$menu->append($menu_item_2);
// create a root menu and add the existing menu to it
$root_menu = &new GtkMenuItem('File');
$root_menu->set_submenu($menu);
// create a menu bar and add the root menu to it
$menu_bar = &new GtkMenuBar();
$menu_bar->append($root_menu);
// add the menu bar to the window
$window->add($menu_bar);
// display the window
$window->show_all();
// necessary so that the program exits properly
function shutdown() { gtk::main_quit(); }
$window->connect('destroy','shutdown');
// start GTK's signal handling loop
gtk::main();
20.9.3 Discussion
A menu involves a hierarchy of quite a
few objects. The GtkWindow (or another container) holds the
GtkMenuBar. The GtkMenuBar holds a GtkMenuItem for
each top-level menu in the menu bar (e.g., "File," "Options," or "Help"). Each
top-level GtkMenuItem has a GtkMenu as a submenu. That submenu
contains each GtkMenuItem that should appear under the top-level menu.
As with any GTK widget, a GtkMenuItem object can have
callbacks that handle signals.
When a menu item is selected, it triggers the activate signal. To take action when a menu item is selected,
connect its activate signal to a callback. Here's a version of the
button-and-label time display from Section 20.8 with two menu items: "Update," which updates the time in the label, and
"Quit," which quits the program:
// create the window $window = &new GtkWindow(); // create a container for the label and the button $container = &new GtkVBox(); // create a menu $menu = &new GtkMenu(); // create a menu item and add it to the menu $menu_item_1 = &new GtkMenuItem('Update'); $menu->append($menu_item_1); // create another menu item and add it to the menu $menu_item_2 = &new GtkMenuItem('Quit'); $menu->append($menu_item_2); // create a root menu and add the existing menu to it $root_menu = &new GtkMenuItem('File'); $root_menu->set_submenu($menu); // create a menu bar and add the root menu to it $menu_bar = &new GtkMenuBar(); $menu_bar->append($root_menu); // add the menu to the container $container->add($menu_bar); // create a label showing the time $label = &new GtkLabel(strftime('%c')); // add the label to the container $container->pack_start($label); // create a button $button = &new GtkButton('Update Time'); /* set the update_time() function as the callback for the "clicked" signal and pass $label to the callback */ $button->connect('clicked','update_time',$label); function update_time($b,$lb) { $lb->set_text(strftime('%c')); } // add the button to the container $container->pack_start($button); // when the Update menu item is selected, call update_time() $menu_item_1->connect('activate','update_time',$label); // when the Quit menu item is selected, quit $menu_item_2->connect('activate','shutdown'); // add the container to the window $window->add($container); // display the window $window->show_all(); // necessary so that the program exits properly function shutdown() { gtk::main_quit(); } $window->connect('destroy','shutdown'); // start GTK's signal handling loop gtk::main();
Callbacks are connected to the menu items with their
connect( ) methods. The callbacks are connected to the
activate signals towards the end of the code because the call to
$menu_item_1->connect( ) passes $label to update_time(
) . For $label to
be successfully passed to update_time( ) while the program is running,
connect( ) has to be called after $label is instantiated.