用户经常使用菜单向计算机发出命令。它是这样的:
现在让我们分析一下上面的菜单。对象有两种类型。

由于菜单项之间的链接,菜单的结构很复杂。
GMenuModel是一个表示菜单的抽象对象。GMenu是GMenuModel的一个简单实现,也是GMenuModel的一个子对象。
GObject – GMenuModel – GMenu
因为GMenuModel是一个抽象对象,它是不可实例化的。因此,它没有任何函数来创建它的实例。如果要创建一个菜单,使用g_menu_new创建一个GMenu实例。GMenu继承了GMenuModel的所有函数。
GMenuItem是一个直接派生自GObject的对象。GMenuItem和Gmenu(或者GMenuModel)没有父子关系。
GObject – GMenuModel – GMenu
GObject – GMenuItem
GMenuItem有属性。其中一个属性是label。例如,在第一个图中有一个菜单项(menu item)具有“Edit”标签。“Cut”、“Copy”、“Paste”和“Select All”也是菜单项的标签。其他属性将在后面解释。
一些菜单项有一个链接到另一个GMenu。有两种类型的链接,submenu 和 section。
GMenuItem可以被插入、添加或添加到GMenu中。当它被插入时,所有的属性和链接值都会被复制并存储在菜单中。GMenuItem本身并没有真正插入。因此,在插入之后,GMenuItem是无用的,它应该被释放。appending或prepending也是如此。
下面的代码展示了如何将GMenuItem追加到GMenu。
GMenu *menu = g_menu_new ();
GMenuItem *menu_item_quit = g_menu_item_new ("Quit", "app.quit");
g_menu_append_item (menu, menu_item_quit);
g_object_unref (menu_item_quit);
菜单项的一个属性是一个action。这个属性指向一个action对象。
有两个action对象,GSimpleAction和GPropertyAction。通常使用GSimpleAction。它与菜单项一起使用。本节只描述GSimpleAction。
当单击菜单项时,对应于菜单项的操作(action)将被激活。然后这个动作会发出一个激活信号。
下面的代码是一个示例。
static void
quit_activated(GSimpleAction *action, GVariant *parameter, gpointer app) { ... ... ...}GSimpleAction *act_quit = g_simple_action_new ("quit", NULL);
g_action_map_add_action (G_ACTION_MAP (app), G_ACTION (act_quit));
g_signal_connect (act_quit, "activate", G_CALLBACK (quit_activated), app);
GMenuItem *menu_item_quit = g_menu_item_new ("Quit", "app.quit");
如果点击菜单,则激活相应的动作“quit”,并发出“activate”信号。然后,调用处理程序quit_activated。
菜单栏和菜单都是传统风格的。菜单按钮最近经常被用来代替菜单栏,但旧的风格仍然被广泛使用。
应用程序只有一个菜单栏。如果一个应用程序有两个或多个具有菜单栏的窗口,则菜单栏是完全相同的。因为应用程序中的每个窗口都指向同一个菜单栏实例。
应用程序的菜单栏一旦设置好,通常不会改变。因此,在startup处理程序中设置它是合适的。因为它只在主应用程序实例中被调用一次。
我认为这对读者阐明应用程序的行为是有好处的。
因此,“activate”或“open”处理程序可以被调用两次或多次。另一方面,“startup”处理程序只会被调用一次。因此,设置菜单栏应该在“startup”处理程序中完成。
static void
app_startup (GApplication *app) {
... ... ...gtk_application_set_menubar (GTK_APPLICATION (app), G_MENU_MODEL (menubar));
... ... ...
}
下面是一个简单的菜单menu和操作action的例子。源文件menu1.c位于src/menu目录下。
1 #include 2 3 static void4 quit_activated(GSimpleAction *action, GVariant *parameter, GApplication *application) {5 g_application_quit (application);6 }7 8 static void9 app_activate (GApplication *application) {
10 GtkApplication *app = GTK_APPLICATION (application);
11 GtkWidget *win = gtk_application_window_new (GTK_APPLICATION (app));
12 gtk_window_set_title (GTK_WINDOW (win), "menu1");
13 gtk_window_set_default_size (GTK_WINDOW (win), 400, 300);
14
15 gtk_application_window_set_show_menubar (GTK_APPLICATION_WINDOW (win), TRUE);
16 gtk_window_present (GTK_WINDOW (win));
17 }
18
19 static void
20 app_startup (GApplication *application) {
21 GtkApplication *app = GTK_APPLICATION (application);
22
23 GSimpleAction *act_quit = g_simple_action_new ("quit", NULL);
24 g_action_map_add_action (G_ACTION_MAP (app), G_ACTION (act_quit));
25 g_signal_connect (act_quit, "activate", G_CALLBACK (quit_activated), application);
26
27 GMenu *menubar = g_menu_new ();
28 GMenuItem *menu_item_menu = g_menu_item_new ("Menu", NULL);
29 GMenu *menu = g_menu_new ();
30 GMenuItem *menu_item_quit = g_menu_item_new ("Quit", "app.quit");
31 g_menu_append_item (menu, menu_item_quit);
32 g_object_unref (menu_item_quit);
33 g_menu_item_set_submenu (menu_item_menu, G_MENU_MODEL (menu));
34 g_menu_append_item (menubar, menu_item_menu);
35 g_object_unref (menu_item_menu);
36
37 gtk_application_set_menubar (GTK_APPLICATION (app), G_MENU_MODEL (menubar));
38 }
39
40 #define APPLICATION_ID "com.github.ToshioCP.menu1"
41
42 int
43 main (int argc, char **argv) {
44 GtkApplication *app;
45 int stat;
46
47 app = gtk_application_new (APPLICATION_ID, G_APPLICATION_DEFAULT_FLAGS);
48 g_signal_connect (app, "startup", G_CALLBACK (app_startup), NULL);
49 g_signal_connect (app, "activate", G_CALLBACK (app_activate), NULL);
50
51 stat =g_application_run (G_APPLICATION (app), argc, argv);
52 g_object_unref (app);
53 return stat;
54 }
55
"app.quit"进行使用。
将当前目录更改为src/menu。使用comp编译menu1.c。
$ comp menu1
$ ./a.out
然后,出现一个窗口。点击菜单栏上的“Menu”,就会出现一个菜单。点击“退出”菜单,应用程序退出。

让我们试着运行应用程序两次。在shell命令行中使用&,应用程序将并发运行。
然后,出现了两个窗口。
两个窗口都有菜单栏。它们完全一样。这两个窗口属于主实例。
如果单击“Quit”菜单,应用程序(主实例)将退出。
第二次运行创建了一个新窗口。然而,这取决于activate处理程序。如果在startup处理程序中创建窗口,activate处理程序只是显示窗口,那么在第二次运行时不会创建新窗口。例如,tfe(文本文件编辑器)不会创建第二个窗口。它只是创建了一个新的notebook页面。因为它的activate处理程序不创建任何窗口,而只是创建一个新的notebook页面。
在桌面应用程序上经常发生第二次或更多的执行。如果双击图标两次或两次以上,应用程序将运行多次。因此,你需要仔细考虑startup和activate (open)处理程序。