“菜單” (menubar)和“工具欄”(toolbars)
在這個部分的GTK+程序設計教程中,我們使用“菜單”和“工具欄”。
“菜單”( menubar)
是GUI程序中最爲常見的部分之一。各種各樣的命令和功能都可以藉以“菜單”來實現。 當我們習慣在終端(console)中啓動應用程序的時候,必須要記得很多複雜的命令和參數 ,在本章節中我們將 這一切都轉化爲可見的操作。菜單和工具欄中標準化的操作,將讓你擺脫學習新軟件所耗費的大量時間和精力。
簡單的菜單示列
在我們的第一個例子中,我們將生成一個含有文件菜單的菜單欄。文件菜單將只有一個菜單條(menu item)。如果點擊這個菜單條程序將退出。
#include <gtk/gtk.h> int main( int argc, char *argv[]) { GtkWidget *window; GtkWidget *vbox; GtkWidget *menubar; GtkWidget *filemenu; GtkWidget *file; GtkWidget *quit; gtk_init(&argc, &argv); window = gtk_window_new(GTK_WINDOW_TOPLEVEL); gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER); gtk_window_set_default_size(GTK_WINDOW(window), 250, 200); gtk_window_set_title(GTK_WINDOW(window), "menu"); vbox = gtk_vbox_new(FALSE, 0); gtk_container_add(GTK_CONTAINER(window), vbox); menubar = gtk_menu_bar_new(); filemenu = gtk_menu_new(); file = gtk_menu_item_new_with_label("File"); quit = gtk_menu_item_new_with_label("Quit"); gtk_menu_item_set_submenu(GTK_MENU_ITEM(file), filemenu); gtk_menu_shell_append(GTK_MENU_SHELL(filemenu), quit); gtk_menu_shell_append(GTK_MENU_SHELL(menubar), file); gtk_box_pack_start(GTK_BOX(vbox), menubar, FALSE, FALSE, 3); g_signal_connect_swapped(G_OBJECT(window), "destroy", G_CALLBACK(gtk_main_quit), NULL); g_signal_connect(G_OBJECT(quit), "activate", G_CALLBACK(gtk_main_quit), NULL); gtk_widget_show_all(window); gtk_main(); return 0; }
生成一個菜單欄的確會讓人有點疑惑。我們要牢記的是一個菜單欄和一個菜單都是源屬於同一個構件的,也就是菜單外殼(menu shell)
。菜單選項(menu items )
是一個只對菜單有效的子構件。他們通常用來實現子菜單。
menubar = gtk_menu_bar_new(); filemenu = gtk_menu_new();
在上面的代碼中我們生成了一個菜單欄構件(menubar)和一個菜單構件(menu)。
gtk_menu_item_set_submenu(GTK_MENU_ITEM(file), filemenu);
上面的代碼就會生成一個名爲“文件”的菜單。這也就是說其實菜單欄就是一個菜單外殼。很顯然這裏的文件菜單也是一個菜單外殼。這就是爲什麼我們把文件菜單稱爲子菜單或者說是一個子外殼。
gtk_menu_shell_append(GTK_MENU_SHELL(filemenu), quit); gtk_menu_shell_append(GTK_MENU_SHELL(menubar), file);
菜單選項由函數 gtk_menu_shell_append()
f來實現。然後一般情況下菜單選項被填加進菜單外殼裏。 在我們的這個例子中,“quit”菜單選項是被填加進“file”菜單欄裏,然後類似的是“file”菜單選項被填加進菜單中(menubar)。
g_signal_connect(G_OBJECT(quit), "activate", G_CALLBACK(gtk_main_quit), NULL);
當你單擊“quit”菜單按鈕,程序就會退出。
圖象菜單, mnemonics &accelerators
在接下來的這個例子中,我們將更進一步的去探索,在GTK+系統中我們可以應用的功能。Accelerators
是快捷鍵的意思,用來方便的用鍵盤上的組合鍵激活一個菜單選項。 Mnemonics
也是是快捷鍵用於用於GUI的基礎。他們的具體表現都爲帶有下畫線的字符。(譯者:似乎說的不清楚啊,呵呵。具體的區別還是請參見下面的具體代碼實現以及對應的程序效果圖)
#include <gtk/gtk.h> #include <gdk/gdkkeysyms.h> int main( int argc, char *argv[]) { GtkWidget *window; GtkWidget *vbox; GtkWidget *menubar; GtkWidget *filemenu; GtkWidget *file; GtkWidget *new; GtkWidget *open; GtkWidget *quit; GtkWidget *sep; GtkAccelGroup *accel_group = NULL; gtk_init(&argc, &argv); window = gtk_window_new(GTK_WINDOW_TOPLEVEL); gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER); gtk_window_set_default_size(GTK_WINDOW(window), 250, 200); gtk_window_set_title(GTK_WINDOW(window), "menu"); vbox = gtk_vbox_new(FALSE, 0); gtk_container_add(GTK_CONTAINER(window), vbox); menubar = gtk_menu_bar_new(); filemenu = gtk_menu_new(); accel_group = gtk_accel_group_new(); gtk_window_add_accel_group(GTK_WINDOW(window), accel_group); file = gtk_menu_item_new_with_mnemonic("_File"); new = gtk_image_menu_item_new_from_stock(GTK_STOCK_NEW, NULL); open = gtk_image_menu_item_new_from_stock(GTK_STOCK_OPEN, NULL); sep = gtk_separator_menu_item_new(); quit = gtk_image_menu_item_new_from_stock(GTK_STOCK_QUIT, accel_group); gtk_widget_add_accelerator(quit, "activate", accel_group, GDK_q, GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE); gtk_menu_item_set_submenu(GTK_MENU_ITEM(file), filemenu); gtk_menu_shell_append(GTK_MENU_SHELL(filemenu), new); gtk_menu_shell_append(GTK_MENU_SHELL(filemenu), open); gtk_menu_shell_append(GTK_MENU_SHELL(filemenu), sep); gtk_menu_shell_append(GTK_MENU_SHELL(filemenu), quit); gtk_menu_shell_append(GTK_MENU_SHELL(menubar), file); gtk_box_pack_start(GTK_BOX(vbox), menubar, FALSE, FALSE, 3); g_signal_connect_swapped(G_OBJECT(window), "destroy", G_CALLBACK(gtk_main_quit), NULL); g_signal_connect(G_OBJECT(quit), "activate", G_CALLBACK(gtk_main_quit), NULL); gtk_widget_show_all(window); gtk_main(); return 0; }
在上面的整個代碼程序中,向大家展示了是如何向一個菜單選項中去填加一個圖象的。當然也包括瞭如何使用accelerator 以及 mnemonics 。
accel_group = gtk_accel_group_new(); gtk_window_add_accel_group(GTK_WINDOW(window), accel_group); ... quit = gtk_image_menu_item_new_from_stock(GTK_STOCK_QUIT, accel_group); gtk_widget_add_accelerator(quit, "activate", accel_group, GDK_q, GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE);
一個 accelerator 組有好多個accelerators快捷鍵。這裏我們生成了一個“Ctrl + q” accelerators快捷鍵。
file = gtk_menu_item_new_with_mnemonic("_File");
我們需要調用函數 gtk_menu_item_new_with_mnemonic()
來生成一個mnemonic快捷鍵。你可以按下鍵盤上的“ Alt + F”就可以看到. mnemonic快捷鍵的效果。
new = gtk_image_menu_item_new_from_stock(GTK_STOCK_NEW, NULL); open = gtk_image_menu_item_new_from_stock(GTK_STOCK_OPEN, NULL);
在上面的代碼中我們生成了兩個帶有圖象的菜單選項。在所調用的函數的第二個參數中,我們設置爲NULL,這樣達到的效果是我們自動生成了accelerators快捷鍵。我們也爲菜單選項分別提供了圖象與文字。
sep = gtk_separator_menu_item_new();
菜單選項能夠被一個水平的分割線隔開。這樣的話我們就可以從邏輯上把一些菜單選項給區分開來。
選擇(Check)菜單選項 (menu item)
GtkCheckMenuItem
便是一個可以生成帶有選擇的菜單選項。
#include <gtk/gtk.h> void toggle_statusbar(GtkWidget *widget, gpointer statusbar) { if (gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(widget))) { gtk_widget_show(statusbar); } else { gtk_widget_hide(statusbar); } } int main( int argc, char *argv[]) { GtkWidget *window; GtkWidget *vbox; GtkWidget *menubar; GtkWidget *viewmenu; GtkWidget *view; GtkWidget *tog_stat; GtkWidget *statusbar; gtk_init(&argc, &argv); window = gtk_window_new(GTK_WINDOW_TOPLEVEL); gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER); gtk_window_set_default_size(GTK_WINDOW(window), 250, 200); gtk_window_set_title(GTK_WINDOW(window), "view statusbar"); vbox = gtk_vbox_new(FALSE, 0); gtk_container_add(GTK_CONTAINER(window), vbox); menubar = gtk_menu_bar_new(); viewmenu = gtk_menu_new(); view = gtk_menu_item_new_with_label("View"); tog_stat = gtk_check_menu_item_new_with_label("View Statusbar"); gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(tog_stat), TRUE); gtk_menu_item_set_submenu(GTK_MENU_ITEM(view), viewmenu); gtk_menu_shell_append(GTK_MENU_SHELL(viewmenu), tog_stat); gtk_menu_shell_append(GTK_MENU_SHELL(menubar), view); gtk_box_pack_start(GTK_BOX(vbox), menubar, FALSE, FALSE, 3); statusbar = gtk_statusbar_new(); gtk_box_pack_end(GTK_BOX(vbox), statusbar, FALSE, TRUE, 1); g_signal_connect_swapped(G_OBJECT(window), "destroy", G_CALLBACK(gtk_main_quit), NULL); g_signal_connect(G_OBJECT(tog_stat), "activate", G_CALLBACK(toggle_statusbar), statusbar); gtk_widget_show_all(window); gtk_main(); return 0; }
在我們的代碼示例中,我們展示瞭如何去製造一個帶有選擇框的菜單選項。具體的功能是:如果選擇框被選中則“狀態欄”就會顯示出來,反之則不會顯示。
tog_stat = gtk_check_menu_item_new_with_label("View Statusbar");
函數gtk_check_menu_item_new_with_label()
可以生成一個新的帶有選擇框的菜單選項。
if (gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(widget))) { gtk_widget_show(statusbar); } else { gtk_widget_hide(statusbar); }
如果選擇框被選中則“狀態欄”就會顯示出來,反之則不會顯示。
工具欄(A toolbar)
菜單欄爲我們編程時實現某種功能提供了方便與快捷。在接下來的章節中,我們將爲你展示一種在特定情況下可以更加便捷的的方法——製造一個“工具欄。”
#include <gtk/gtk.h> int main( int argc, char *argv[]) { GtkWidget *window; GtkWidget *vbox; GtkWidget *toolbar; GtkToolItem *new; GtkToolItem *open; GtkToolItem *save; GtkToolItem *sep; GtkToolItem *exit; gtk_init(&argc, &argv); window = gtk_window_new(GTK_WINDOW_TOPLEVEL); gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER); gtk_window_set_default_size(GTK_WINDOW(window), 250, 200); gtk_window_set_title(GTK_WINDOW(window), "toolbar"); vbox = gtk_vbox_new(FALSE, 0); gtk_container_add(GTK_CONTAINER(window), vbox); toolbar = gtk_toolbar_new(); gtk_toolbar_set_style(GTK_TOOLBAR(toolbar), GTK_TOOLBAR_ICONS); gtk_container_set_border_width(GTK_CONTAINER(toolbar), 2); new = gtk_tool_button_new_from_stock(GTK_STOCK_NEW); gtk_toolbar_insert(GTK_TOOLBAR(toolbar), new, -1); open = gtk_tool_button_new_from_stock(GTK_STOCK_OPEN); gtk_toolbar_insert(GTK_TOOLBAR(toolbar), open, -1); save = gtk_tool_button_new_from_stock(GTK_STOCK_SAVE); gtk_toolbar_insert(GTK_TOOLBAR(toolbar), save, -1); sep = gtk_separator_tool_item_new(); gtk_toolbar_insert(GTK_TOOLBAR(toolbar), sep, -1); exit = gtk_tool_button_new_from_stock(GTK_STOCK_QUIT); gtk_toolbar_insert(GTK_TOOLBAR(toolbar), exit, -1); gtk_box_pack_start(GTK_BOX(vbox), toolbar, FALSE, FALSE, 5); g_signal_connect(G_OBJECT(exit), "clicked", G_CALLBACK(gtk_main_quit), NULL); g_signal_connect_swapped(G_OBJECT(window), "destroy", G_CALLBACK(gtk_main_quit), NULL); gtk_widget_show_all(window); gtk_main(); return 0; }
以上的代碼中,我們製作了一個簡單的工具欄實現。
toolbar = gtk_toolbar_new(); gtk_toolbar_set_style(GTK_TOOLBAR(toolbar), GTK_TOOLBAR_ICONS)
從上面的兩行代碼中你應該可以看出來,我們生成了一個“嶄新”的工具欄:)。我們還特地使他們都用圖片來顯示,沒有包含文字。
new = gtk_tool_button_new_from_stock(GTK_STOCK_NEW); gtk_toolbar_insert(GTK_TOOLBAR(toolbar), new, -1);
從 stock中我們生成了一個新的工具欄按鈕。要想把工具欄按鈕插入到工具欄中,很簡單!只需要調用函數 gtk_toolbar_insert()
就可以搞定。
sep = gtk_separator_tool_item_new(); gtk_toolbar_insert(GTK_TOOLBAR(toolbar), sep, -1);
上面的代碼,我們生成了一個分割線把工具欄按鈕們分開(只是邏輯上的分組需要)。
功能失效(Undo redo)
在接下來的例子中,我們將展示一個神奇的功能:使工具欄中的一個按鈕功能失效(讓他變成陰影)。這在GUI設計中是一個常見的技巧。 舉個例子:當我們把一片文章單擊保存後,那個保存按鈕就會變成陰影狀,也就是功能失效了。就是來提示你:保存功能已經執行過了,不需要再執行保存功能了。
#include <gtk/gtk.h> #include <string.h> void undo_redo(GtkWidget *widget, gpointer item) { static int count = 2; const char *name = gtk_widget_get_name(widget); if ( strcmp(name, "undo") ) { count++; } else { count--; } if (count < 0) { gtk_widget_set_sensitive(widget, FALSE); gtk_widget_set_sensitive(item, TRUE); } if (count > 5) { gtk_widget_set_sensitive(widget, FALSE); gtk_widget_set_sensitive(item, TRUE); } } int main( int argc, char *argv[]) { GtkWidget *window; GtkWidget *vbox; GtkWidget *toolbar; GtkToolItem *undo; GtkToolItem *redo; GtkToolItem *sep; GtkToolItem *exit; gtk_init(&argc, &argv); window = gtk_window_new(GTK_WINDOW_TOPLEVEL); gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER); gtk_window_set_default_size(GTK_WINDOW(window), 250, 200); gtk_window_set_title(GTK_WINDOW(window), "undoredo"); vbox = gtk_vbox_new(FALSE, 0); gtk_container_add(GTK_CONTAINER(window), vbox); toolbar = gtk_toolbar_new(); gtk_toolbar_set_style(GTK_TOOLBAR(toolbar), GTK_TOOLBAR_ICONS); gtk_container_set_border_width(GTK_CONTAINER(toolbar), 2); undo = gtk_tool_button_new_from_stock(GTK_STOCK_UNDO); gtk_widget_set_name(GTK_WIDGET(undo), "undo"); gtk_toolbar_insert(GTK_TOOLBAR(toolbar), undo, -1); redo = gtk_tool_button_new_from_stock(GTK_STOCK_REDO); gtk_toolbar_insert(GTK_TOOLBAR(toolbar), redo, -1); sep = gtk_separator_tool_item_new(); gtk_toolbar_insert(GTK_TOOLBAR(toolbar), sep, -1); exit = gtk_tool_button_new_from_stock(GTK_STOCK_QUIT); gtk_toolbar_insert(GTK_TOOLBAR(toolbar), exit, -1); gtk_box_pack_start(GTK_BOX(vbox), toolbar, FALSE, FALSE, 5); g_signal_connect(G_OBJECT(undo), "clicked", G_CALLBACK(undo_redo), redo); g_signal_connect(G_OBJECT(redo), "clicked", G_CALLBACK(undo_redo), undo); g_signal_connect(G_OBJECT(exit), "clicked", G_CALLBACK(gtk_main_quit), NULL); g_signal_connect_swapped(G_OBJECT(window), "destroy", G_CALLBACK(gtk_main_quit), NULL); gtk_widget_show_all(window); gtk_main(); return 0; }
我們的例子中用到了 GTK+ stock 來實現是 “功能有效”還是“功能失效”。當你單擊幾下 按鈕後,那個按鈕就會變成陰影狀,也就是說他從“功能有效”變成了“功能失效”。
if (count < 0) { gtk_widget_set_sensitive(widget, FALSE); gtk_widget_set_sensitive(item, TRUE); } if (count > 5) { gtk_widget_set_sensitive(widget, FALSE); gtk_widget_set_sensitive(item, TRUE); }
gtk_widget_set_sensitive()
是被用來告訴計算機是否要擊活一個工具欄按鈕。