Chapter 12. Menu Widget

There are two ways to create menus: there's the easy way, and there's the hard way. Both have their uses, but you can usually use the Itemfactory (the easy way). The "hard" way is to create all the menus using the calls directly. The easy way is to use the gtk_item_factory calls. This is much simpler, but there are advantages and disadvantages to each approach.

The Itemfactory is much easier to use, and to add new menus to, although writing a few wrapper functions to create menus using the manual method could go a long way towards usability. With the Itemfactory, it is not possible to add images or the character '/' to the menus.

12.1. 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:

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 functions that are used to create menus and menubars. This first function is used to create a new menubar.

GtkWidget *gtk_menu_bar_new( void );

This rather self explanatory function creates a new menubar. You use gtk_container_add() to pack this into a window, or the box_pack functions to pack it into a box - the same as buttons.

GtkWidget *gtk_menu_new( void );

This function returns a pointer to a new menu; it is never actually shown (with gtk_widget_show()), it is just a container for the menu items. I hope this will become more clear when you look at the example below.

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

GtkWidget *gtk_menu_item_new( void );

GtkWidget *gtk_menu_item_new_with_label( const char *label );

GtkWidget *gtk_menu_item_new_with_mnemnonic( const char *label );

These calls are used to create the menu items that are to be displayed. Remember to differentiate between a "menu" as created with gtk_menu_new() and a "menu item" as created by the gtk_menu_item_new() functions. The menu item will be an actual button with an associated action, whereas a menu will be a container holding menu items.

The gtk_menu_item_new_with_label() and gtk_menu_item_new() functions are just as you'd expect after reading about the buttons. One creates a new menu item with a label already packed into it, and the other just creates a blank menu item.

Once you've created a menu item you have to put it into a menu. This is done using the function gtk_menu_shelll_append. In order to capture when the item is selected by the user, we need to connect to the activate signal in the usual way. So, if we wanted to create a standard File menu, with the options Open, Save, and Quit, the code would look something like:

    file_menu = gtk_menu_new ();    /* Don't need to show menus */

    /* Create the menu items */
    open_item = gtk_menu_item_new_with_label ("Open");
    save_item = gtk_menu_item_new_with_label ("Save");
    quit_item = gtk_menu_item_new_with_label ("Quit");

    /* Add them to the menu */
    gtk_menu_shell_append (GTK_MENU_SHELL (file_menu), open_item);
    gtk_menu_shell_append (GTK_MENU_SHELL (file_menu), save_item);
    gtk_menu_shell_append (GTK_MENU_SHELL (file_menu), quit_item);

    /* Attach the callback functions to the activate signal */
    g_signal_connect_swapped (G_OBJECT (open_item), "activate",
                              G_CALLBACK (menuitem_response),
                              (gpointer) "file.open");
    g_signal_connect_swapped (G_OBJECT (save_item), "activate",
                              G_CALLBACK (menuitem_response),
                              (gpointer) "file.save");

    /* We can attach the Quit menu item to our exit function */
    g_signal_connect_swapped (G_OBJECT (quit_item), "activate",
                              G_CALLBACK (destroy),
                              (gpointer) "file.quit");

    /* We do need to show menu items */
    gtk_widget_show (open_item);
    gtk_widget_show (save_item);
    gtk_widget_show (quit_item);

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:

    menu_bar = gtk_menu_bar_new ();
    gtk_container_add (GTK_CONTAINER (window), menu_bar);
    gtk_widget_show (menu_bar);

    file_item = gtk_menu_item_new_with_label ("File");
    gtk_widget_show (file_item);

Now we need to associate the menu with file_item. This is done with the function

void gtk_menu_item_set_submenu( GtkMenuItem *menu_item,
                                GtkWidget   *submenu );

So, our example would continue with

    gtk_menu_item_set_submenu (GTK_MENU_ITEM (file_item), file_menu);

All that is left to do is to add the menu to the menubar, which is accomplished using the function

void gtk_menu_bar_append( GtkMenuBar *menu_bar,
                          GtkWidget  *menu_item );

which in our case looks like this:

    gtk_menu_bar_append (GTK_MENU_BAR (menu_bar), file_item);

If we wanted the menu right justified on the menubar, such as help menus often are, we can use the following function (again on file_item in the current example) before attaching it to the menubar.

void gtk_menu_item_right_justify( GtkMenuItem *menu_item );

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

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, for example. Take these steps: