菜单构件

有两种创建菜单的方法:一个容易的,一种难的。它们各有各的用处,不过一般你可以使用套件(Itemfactory)(容易的方法)。“难”的方法是直接使用各调用来创建所有的菜单。容易的方法是使用 gtk_item_factory 调用。这要简单得多,但每种方法各有优点和缺点。

套件要容易使用得多,加新的菜单也方便些,虽然用手工方法写一些封装(wrapper)函数来创建菜单能对可用性大有帮助。使用套件,不能在菜单上增加图片或 '/' 字符。

手工创建菜单

按照现实教学中的惯例,我们将先介绍难的方法。

创建菜单栏和子菜单时要用到三种构件:

菜单项构件有两个不同的用处,这情况有一点复杂。既有组装到菜单里的构件,也有组装到菜单栏中,当被选中时激活菜单的构件。

让我们看一下用来创建菜单和菜单栏的函数。第一个函数用来创建一个新的菜单栏。

GtkWidget *gtk_menu_bar_new( void );

这个相当自我解释的函数创建一个新的菜单栏。你用 gtk_container_add() 组装它到一个窗口,或盒组装(box_pack)函数来将它组装到一个盒子中 - 就像按钮一样。

GtkWidget *gtk_menu_new( void );

这个函数返回指向一个新菜单的指针。它从不会真正显示(用 gtk_widget_show()),它只是一个菜单项的容器。我希望你看了后面的示例后会弄清楚一些。

接下来的三个调用用来创建被组装到菜单(和菜单栏)中的菜单项。

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 );

这些调用用来创建将显示的菜单项。记住要区别用 gtk_menu_new() 创建的“菜单”和用 gtk_menu_item_new() 函数创建的“菜单项”。有了相关联动作的菜单项将是一个真实的按钮,而菜单将是一个包含菜单项的容器。

gtk_menu_item_new_with_label() 和 gtk_menu_item_new() 函数正如你读了按钮部分后料想的一样。其一创建一个已经有一个标签组装进来了的新的菜单项,另一个仅仅创建一个空白的菜单项。

在创建一个菜单项后你要将它放到一个菜单里。用函数 gtk_menu_append 就行了。为了截取何时这个项被用户选中,我们要用平常的方法连接到activate信号。所以,如果我们要创建一个标准的File菜单,包括OpenSaveQuit选项,代码将像这样:

    file_menu = gtk_menu_new ();    /* 不必显示菜单 */

    /* 创建菜单项 */
    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");

    /* 将它们加到菜单中 */
    gtk_menu_append (GTK_MENU (file_menu), open_item);
    gtk_menu_append (GTK_MENU (file_menu), save_item);
    gtk_menu_append (GTK_MENU (file_menu), quit_item);

    /* 将回调函数绑定到activate信号 */
    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");

    /* 我们可以绑定Quit菜单项到我们的退出函数 */
    g_signal_connect_swapped (G_OBJECT (quit_item), "activate",
                              G_CALLBACK (destroy),
                              (gpointer) "file.quit");

    /* 一定要显示菜单项 */
    gtk_widget_show (open_item);
    gtk_widget_show (save_item);
    gtk_widget_show (quit_item);

这时我们有了我们的菜单。现在我们要创建一个菜单栏,并为File条目(entry)创建一个菜单项,我们的菜单就加在这个上。代码看起来像这样:

    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);

现在我们要把菜单和file_item关联起来。用这个函数可以做到:

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

那么,我们的示例接下来就是

    gtk_menu_item_set_submenu (GTK_MENU_ITEM (file_item), file_menu);

所有剩下要做的就是将菜单加到菜单栏,用这个函数完成:

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

在我们的情况下就像这样了:

    gtk_menu_bar_append (GTK_MENU_BAR (menu_bar), file_item);

如果我们想让菜单在菜单栏上右对齐,例如帮助菜单就经常是这样,我们可以在绑定它到菜单栏之前使用下面的函数(本例中又是对file_item使用)。

void gtk_menu_item_right_justify( GtkMenuItem *menu_item );

这里是一个对创建一个附带了菜单的菜单栏所需步骤的概要:

创建一个弹出菜单几乎也一样。不同的是菜单不会被菜单栏“自动”弹出,而是在button-press事件(例如)里调用函数 gtk_menu_popup() 时明确地弹出。有这些步骤: