### Tutorial

« Menus | Using an Item Factory »

## Manual Menu Creation

In the true tradition of teaching, we'll show you the hard way first. There are three widgets that go into making a menubar and submenus:

- a menu item - which is what the user wants to select, e.g., "Save"
- a menu - which acts as a container for the menu items, and
- a menubar - which is a container for each of the individual menus.

This is slightly complicated by the fact that menu item widgets are used for two different things. They are both the widgets that are packed into the menu, and the widget that is packed into the menubar, which, when selected, activates the menu.
Let's look at the constructors that are used to create menus and menubars. This first constructor is used to create a new menubar.

`MenuBar();`

You can either use Gtk::Container::add() to add the new menubar to a window, or the Gtk::Box packing methods to pack it into a box - the same as buttons.
There are two constructors that create a new menu:

`Menu(); Menu(const Gtk::AccelGroup& accel_group);`

The accel_group argument is the accelerator group which holds the global accelerators for this menu. The first constructor creates the accelerator group for you and can be retrieved by calling:

`Gtk::AccelGroup* get_accel_group() const;`

The next three constructors are used to create menu items that are packed into the menu (and menubar).

`MenuItem(); explicit MenuItem(const String& label, bool use_underline = false); MenuItem(const String& label, Gtk::Menu& submenu, bool use_underline = false);`

The label argument is the menu item text, submenu is a menu to associate with this menu item and use_underline, if true specifies that label should be parsed for the mnemonic character. The first constructor creates an empty menu item, the second constructor creates a menu item with a label already packed into it and the last constructor creates a menu item that displays another menu when activated.
Remember to differentiate between a "menu" and a "menu item". A menu item is like a button with an associated action, whereas a menu is a container holding menu items.
Once you've created a menu item you have to put it into a menu. This is done using one of the Gtk::MenuShell methods - append, prepend or insert. In order to capture when the item is selected by the user, we need to connect a signal handler to the item's activate signal. The append, prepend and insert methods will do this connection for you if you pass the method a valid slot. So, if we wanted to create a standard File menu, with the options Open, Save, and Quit, the code would look something like this:

`Gtk::Menu *file_menu = new Gtk::Menu; // Create menu items Gtk::MenuItem *item = new Gtk::Menu("Open"); file_menu->append(item, slot(this, &MyClass::on_file_open)); item = new Gtk::Menu("Save"); file_menu->append(item, slot(this, &MyClass::on_file_save)); item = new Gtk::Menu("Quit"); file_menu->append(item, slot(this, &MyClass::on_file_quit)); // Show all the menu items file_menu->show_all();`

At this point we have our menu. Now we need to create a menubar and a menu item for the File entry, to which we add our menu. The code looks like this:

`Gtk::MenuBar *menubar = new Gtk::MenuBar window->add(*menubar); Gtk::MenuItem *file_item = new Gtk::MenuItem("File", *file_menu); menubar->append(*file_item); file_item->show(); menubar->show();`

If we wanted the menu right justified on the menubar, such as help menus often are, we can use the following Gtk::MenuItem method on our menu item before attaching it to the menubar.

`void set_right_justified(bool right_justified);`

Here is a summary of the steps needed to create a menu bar with menus attached:

- Construct a new menu.
- Construct multiple menu items and use Gtk::MenuShell::append() to add each of these new items to the menu.
- Construct a menu item that will be the root of the menu, the text appearing here will be on the menubar itself.
- Pass a reference to the menu to the root menu item constructor (the one created in the above step).
- Construct a new menubar. This step only needs to be done once when creating a series of menus on one menu bar.
- Use Gtk::MenuShell::append() to put the root menu onto the menubar.

Creating a popup menu is nearly the same. The difference is that the menu is not posted "automatically" by a menubar, but explicitly by calling the function Gtk::Menu::popup() from a button-press event. The button-press event handler has the prototype:

`bool MyClass::event_handler(GdkEventButton *event);`

To connect a button_press event handler and use the event argument to find out where to pop up the menu, Take these steps:
Connect to an event handler with the following extended prototype.

`bool MyClass::event_handler(GdkEventButton *event, Gtk::Menu *menu);`

Use bind to bind a pointer to the menu to your event handler.

`bind(slot(this, &MyClass:event_handler), menu);`

where menu is the bound menu pointer. Remember, bound data is always passed as the last argument to the bound method, in this case event_handler.
In the event handler, if the event is a mouse button press, treat the event as a button event (which it is) and use it as shown in the sample code to pass information to Gtk::Menu::popup().

`bool MyClass::event_handler(GdkEventButton *event, Gtk::Menu *menu) { menu->popup(event->button, event->time); // return true to indicate event has been handled return true; }`

That should just about do it. Let's take a look at an example to help clarify.
The header file for MenuWindow is menu.h. Menu Window displays a simple window with a menubar across the top. When you click a mouse button down anywhere inside its client area the menubar's File menu pops up at the current pointer position.

`#include<inti/main.h>
#include <inti/core.h>
#include <inti/gtk/menu.h>
using namespace Inti;
class MenuWindow : public Gtk::Window
{
MenuWindow(const MenuWindow&);
MenuWindow& operator=(const MenuWindow&);
protected:
bool on_button_press(GdkEventButton *event, Gtk::Menu *menu);
public:
MenuWindow();
virtual ~MenuWindow();
void menu_item_selected(const char *parent, const char *item);
void on_file_new();
void on_file_open();
void on_file_save();
void on_file_save_as();
void on_file_quit();
void on_options_preferences();
void on_help_about();
};`

and the source file is menu.cc:

`#include"menu.h"
#include <inti/gtk/accelgroup.h>
#include <inti/gtk/eventbox.h>
#include <inti/gtk/label.h>
#include <inti/gtk/menubar.h>
#include <inti/gtk/menuitem.h>
#include <inti/gtk/separatormenuitem.h>
#include <inti/bind.h>
MenuWindow::MenuWindow()
{
set_title("Menu Window");
set_size_request(300, 200);
// Boxes don't receive button events so use an eventbox. The eventbox is added first
// and then all the other widgets added to it.
Gtk::EventBox *eventbox = new Gtk::EventBox;
add(*eventbox);
// Set the events the eventbox is to receive. These can be any number of or'd (|) values
// from the Gdk::EventMask enumeration.
eventbox->set_events(Gdk::BUTTON_PRESS_MASK);
// Add the packing box to eventbox
Gtk::VBox *vbox = new Gtk::VBox(false, 1);
vbox->set_border_width(1);
eventbox->add(*vbox);
// Create the menubar. Menus can be created by using the append, prepend or insert methods
// in menushell.h to add menu items.
Gtk::MenuBar *menubar = new Gtk::MenuBar;
Gtk::AccelGroup *accel_group = add_accel_group();
// Create the File menu
Gtk::Menu *menu = new Gtk::Menu(*accel_group);
menu->append(*(new Gtk::MenuItem("_New", true)), "<control>N", slot(this, &MenuWindow::on_file_new));
menu->append(*(new Gtk::MenuItem("_Open", true)), "<control>O", slot(this, &MenuWindow::on_file_open));
menu->append(*(new Gtk::MenuItem("_Save", true)), "<control>S", slot(this, &MenuWindow::on_file_save));
menu->append(*(new Gtk::MenuItem("Save _As", true)), slot(this, &MenuWindow::on_file_save_as));
menu->append(*(new Gtk::SeparatorMenuItem));
menu->append(*(new Gtk::MenuItem("_Quit", true)), "<control>Q", slot(this, &MenuWindow::on_file_quit));
menubar->append(*(new Gtk::MenuItem("_File", *menu, true)));
// Bind the file menu to the button_press event and use it as the popup menu.
eventbox->sig_button_press_event().connect(bind(slot(this, &MenuWindow::on_button_press), menu));
// Create Options menu
menu = new Gtk::Menu;
menu->append(*(new Gtk::MenuItem("_Preferences", true)), slot(this, &MenuWindow::on_options_preferences));
menubar->append(*(new Gtk::MenuItem("_Options", *menu, true)));
// Create Help menu
menu = new Gtk::Menu;
menu->append(*(new Gtk::MenuItem("About")), slot(this, &MenuWindow::on_help_about));
Gtk::MenuItem *menu_item = new Gtk::MenuItem("_Help", *menu, true);
menu_item->set_right_justified(true);
menubar->append(*menu_item);
// Pack the menubar into the vbox
vbox->pack_start(*menubar, false);
// Add a label that tells the user to click the mouse button inside the client area.
Gtk::Label *label = new Gtk::Label("Click mouse button here...");
vbox->pack_start(*label);
// Being lazy, just show everything with one call.
show_all();
}
MenuWindow::~MenuWindow()
{
}
bool
MenuWindow::on_button_press(GdkEventButton *event, Gtk::Menu *menu)
{
menu->popup(event->button, event->time);
return true;
}
void
MenuWindow::menu_item_selected(const char *parent, const char *item)
{
g_message("Menu: activated the \"%s\" menu item: \"%s\"", parent, item);
}
void
MenuWindow::on_file_new()
{
menu_item_selected("File", "New");
}
void
MenuWindow::on_file_open()
{
menu_item_selected("File", "Open");
}
void
MenuWindow::on_file_save()
{
menu_item_selected("File", "Save");
}
void
MenuWindow::on_file_save_as()
{
menu_item_selected("File", "Save As");
}
void
MenuWindow::on_file_quit()
{
dispose();
}
void
MenuWindow::on_options_preferences()
{
menu_item_selected("Options", "Preferences");
}
void
MenuWindow::on_help_about()
{
menu_item_selected("Help", "About");
}
INTI_MAIN(MenuWindow)`

The INTI_MAIN macro is a convenience macro that writes a simple main function, its only argument is the name of the main window class. The macro is defined in `<inti/main.h>` as

`#define INTI_MAIN(MainWidget)\ int main (int argc, char *argv[])\ {\ Inti::Main::init(&argc, &argv);\ MainWidget main_widget;\ main_widget.sig_destroy().connect(slot(&Inti::Main::quit));\ main_widget.show();\ Inti::Main::run();\ return 0;\ }`

There is a second manual menu creation example in "examples/menu/stock.cc" that creates the same Menu Window as above, except that it uses stock menu items and their icons. The source code is otherwise identical.

« Menus | Index Top | Using an Item Factory »