Ten post został opublikowany 13 lat temu. Informacje mogą być przestarzałe, poglądy autora mogły ewoluować lub post może być nieaktualny w jakiś inny sposób. Weź to pod uwagę podczas czytania tego posta.
8. Menu i toolbary
8.1. Menu programu
Ten rozdział opisuje tworzenie menu programu oraz paska narzędziowego.
Menu jest wykorzystywane w wielu programach. Wykorzystuje się je, aby ułatwić dostęp do niektórych funkcji lub nie zaśmiecać głównego okna programu. W każdym razie menu jest to rzecz bardzo przydatna i warto wiedzieć, jak je utworzyć. Pasek menu tworzy się funkcją:
GtkWidget*gtk_menu_bar_new(void);
Jednak co nam z takiego paska, jak nic na nim nie ma. Menu do naszego paska można utworzyć funkcją:
GtkWidget*gtk_menu_new(void);
Wciąż jednak z wykorzystaniem tych dwóch funkcji nie stworzymy funkcjonalnego menu. Potrzebna jest jeszcze jedna z poniższych funkcji:
Czym one się różnią? Obie tworzą element menu z etykietą podaną w argumencie. Druga z nich pozwala jednak dodać mnemonikę, czyli literę, która pozwala na szybki dostęp do poszczególnych elementów menu z wykorzystaniem klawiatury. Dla przykładu — otwórz jakąś aplikację wykorzystującą paski menu, np. menedżer plików (Eksplorator Windows, Nautilus, Dolphin…) i wciśnij lewy Alt. Mnemoniki w menu programu powinny być teraz podkreślone. Dla menu “Plik” zazwyczaj jest to litera P. Wciśnij teraz tę literę trzymając wciąż Alt. Menu powinno się otworzyć. I po to właśnie są mnemoniki.
Warto również zaznaczyć, że mnemoniki można wykorzystać nie tylko przy tworzeniu menu. Wiele z omówionych wcześniej kontrolek, jak np. przyciski obsługuje mnemoniki. Zazwyczaj aby utworzyć jakąś kontrolkę z etykietą i z mnemoniką, wystarczy zmienić with_label na with_mnemonic w wywołaniu funkcji tworzącej daną kontrolkę.
No tak — mamy już utworzony pasek menu, mamy utworzone menu oraz jego elementy, czego więc brakuje? No tak — połączenia tych elementów w jedną całość. Od tego bowiem jest funkcja:
Czym jednak w tej funkcji jest GtkMenuShell? Otóż widżety GtkMenuBar i GtkMenu dziedziczą właśnie GtkMenuShell — tak więc tej funkcji należy przekazać referencję do paska menu lub do samego menu.
Ostatnią funkcją, jaką należy wykorzystać, aby stworzyć działające menu programu jest:
Warto również wiedzieć, czy użytkownik kliknął w jakiś element menu. Można użyć do tego zdarzenia, które nazywa się activate.
Aby zrozumieć, jak utworzyć menu programu, można przeanalizować poniższy kod źródłowy.
#include<gtk/gtk.h>intmain(intargc,char*argv[]){
GtkWidget *okno;
GtkWidget *vbox;
GtkWidget *pasek;
GtkWidget *menu;
GtkWidget *plik;
GtkWidget *wyjdz;
GtkWidget *etykieta1;gtk_init(&argc,&argv);
okno =gtk_window_new(GTK_WINDOW_TOPLEVEL);gtk_window_set_position(GTK_WINDOW(okno), GTK_WIN_POS_CENTER);gtk_window_set_default_size(GTK_WINDOW(okno),250,200);gtk_window_set_title(GTK_WINDOW(okno),"Kurs GTK+");
vbox =gtk_vbox_new(FALSE,0);gtk_container_add(GTK_CONTAINER(okno), vbox);
etykieta1 =gtk_label_new("Lorem ipsum dolor sit amet, consectetur adipiscing elit. \
Maecenas sit amet magna in mi tincidunt iaculis sit amet quis augue. Curabitur libero est, \
vehicula vel consequat a, cursus sit amet risus. Nulla id eros arcu, sit amet dictum eros. \
Cras mollis, leo et dignissim bibendum, purus sapien interdum enim, ut.");gtk_label_set_line_wrap(GTK_LABEL(etykieta1),TRUE);
pasek =gtk_menu_bar_new();
menu =gtk_menu_new();
plik =gtk_menu_item_new_with_mnemonic("_Plik");
wyjdz =gtk_menu_item_new_with_mnemonic("_Wyjdź");gtk_menu_item_set_submenu(GTK_MENU_ITEM(plik), menu);gtk_menu_shell_append(GTK_MENU_SHELL(menu), wyjdz);gtk_menu_shell_append(GTK_MENU_SHELL(pasek), plik);gtk_box_pack_start(GTK_BOX(vbox), pasek,FALSE,FALSE,0);gtk_box_pack_start(GTK_BOX(vbox), etykieta1,FALSE,FALSE,3);g_signal_connect(G_OBJECT(okno),"destroy",G_CALLBACK(gtk_main_quit),NULL);g_signal_connect(G_OBJECT(wyjdz),"activate",G_CALLBACK(gtk_main_quit),NULL);gtk_widget_show_all(okno);gtk_main();return0;}
Działanie powyższego kodu jest następujące:
8.2. Stock items
Stock items to zbiór predefiniowanych etykiet, często połączonych z ikonami oraz czasami akceleratorami (o akceleratorach za chwilę), które można wykorzystać, by w łatwy sposób dodać do programu ikony, nie zwiększając jednocześnie jego wielkości lub etykiety automatycznie dostosowujące się do języka systemu użytkownika. Listę stock items można znaleźć na stronie dokumentacji GTK+.
Aby utworzyć nowy element menu korzystając ze stocku, należy posłużyć się funkcją:
W pierwszym argumencie należy przekazać identyfikator stock itemu, a w drugim grupę akceleratorów. Tymczasowo można w drugim argumencie przekazać NULL, gdyż o akceleratorach — jak już pisałem — będzie za chwilę, natomiast w identyfikator przekazywany w pierwszym argumencie można zdobyć korzystając z powyższego linku prowadzącego do dokumentacji GTK+.
GTK+ posiada własne ustawienia wspólne dla wszystkich aplikacji napisanych z jego wykorzystaniem. Może zdarzyć się tak, że w ustawieniach tych będzie wyłączone pokazywanie obrazków w menu. Wtedy należy to wymusić funkcją:
W pierwszym argumencie należy przekazać referencję do widżetu typu GtkImageMenuItem (nasz element menu utworzony ze stocku się do nich zalicza), a w drugim TRUE, jeżeli chcesz, aby ikonka była zawsze pokazywana oraz FALSE w przeciwnym wypadku. Po wywołaniu funkcji gtk_image_menu_item_new_from_stock() możesz więc dopisać:
Akceleratory to skróty klawiszowe, pokazywane obok elementów menu. Aby z nich korzystać, należy utworzyć grupę akceleratorów. Robi się to funkcją:
GtkAccelGroup*gtk_accel_group_new(void);
Która nie przyjmuje żadnych argumentów, zwraca natomiast wskaźnik do obiektu typu GtkAccelGroup. Aby połączyć widżet z akceleratorem, należy wykorzystać funkcję:
W pierwszym argumencie należy podać referencję do widżetu, do którego ma zostać podłączony akcelerator, w drugim nazwę zdarzenia, które ma zostać wysłane przy wywołaniu akceleratora, w następnym wskaźnik do grupy akceleratorów, w następnym wymagany klawisz, w kolejnym modyfikator (czyli dodatkowy wymagany klawisz, taki jak Ctrl, Alt, czy Shift — ich lista dostępna jest w dokumentacji GDK), a w ostatnim — flagi, których lista również jest dostępna na stronie dokumentacji GTK+. Do większości zastosowań wystarcza tylko GTK_ACCEL_VISIBLE — ustawia on widoczność akceleratora.
Aby akceleratory działały poprawnie, potrzebna jest jeszcze jedna funkcja. Jest nią:
Aby program po dodaniu obsługi akceleratorów się skompilował, należy jeszcze dołączyć plik gdk/gdkkeysyms.h.
Poniższy kod źródłowy ma za zadanie utworzyć okno, menu, oraz element z etykietą “Zakończ” pobraną ze stocku, oraz ze skrótem klawiaturowym Ctrl+Q.
#include<gtk/gtk.h>#include<gdk/gdkkeysyms.h>intmain(intargc,char*argv[]){
GtkWidget *okno;
GtkWidget *vbox;
GtkWidget *pasek;
GtkWidget *menu;
GtkWidget *plik;
GtkWidget *wyjdz;
GtkWidget *etykieta1;
GtkAccelGroup *grupa_akcel;gtk_init(&argc,&argv);
okno =gtk_window_new(GTK_WINDOW_TOPLEVEL);gtk_window_set_position(GTK_WINDOW(okno), GTK_WIN_POS_CENTER);gtk_window_set_default_size(GTK_WINDOW(okno),250,200);gtk_window_set_title(GTK_WINDOW(okno),"Kurs GTK+");
vbox =gtk_vbox_new(FALSE,0);gtk_container_add(GTK_CONTAINER(okno), vbox);
etykieta1 =gtk_label_new("Lorem ipsum dolor sit amet, consectetur adipiscing elit. \
Maecenas sit amet magna in mi tincidunt iaculis sit amet quis augue. Curabitur libero est, \
vehicula vel consequat a, cursus sit amet risus. Nulla id eros arcu, sit amet dictum eros. \
Cras mollis, leo et dignissim bibendum, purus sapien interdum enim, ut.");gtk_label_set_line_wrap(GTK_LABEL(etykieta1),TRUE);
pasek =gtk_menu_bar_new();
menu =gtk_menu_new();
grupa_akcel =gtk_accel_group_new();gtk_window_add_accel_group(GTK_WINDOW(okno), grupa_akcel);
plik =gtk_menu_item_new_with_mnemonic("_Plik");
wyjdz =gtk_image_menu_item_new_from_stock(GTK_STOCK_QUIT,NULL);gtk_image_menu_item_set_always_show_image(GTK_IMAGE_MENU_ITEM(wyjdz),true);gtk_widget_add_accelerator(wyjdz,"activate", grupa_akcel, GDK_q, GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE);gtk_menu_item_set_submenu(GTK_MENU_ITEM(plik), menu);gtk_menu_shell_append(GTK_MENU_SHELL(menu), wyjdz);gtk_menu_shell_append(GTK_MENU_SHELL(pasek), plik);gtk_box_pack_start(GTK_BOX(vbox), pasek,FALSE,FALSE,0);gtk_box_pack_start(GTK_BOX(vbox), etykieta1,FALSE,FALSE,3);g_signal_connect(G_OBJECT(okno),"destroy",G_CALLBACK(gtk_main_quit),NULL);g_signal_connect(G_OBJECT(wyjdz),"activate",G_CALLBACK(gtk_main_quit),NULL);gtk_widget_show_all(okno);gtk_main();return0;}
Po skompilowaniu i uruchomieniu tak powstałego programu ujrzysz:
Po wciśnięciu kombinacji Ctrl+Q program powinien zakończyć działanie.
8.4. Separatory
Separatory przydają się, aby oddzielić kilka grup elementów menu. Tworzy się je funkcją:
GtkWidget*gtk_separator_menu_item_new(void);
Przyłącza się go do menu identycznie, jak w przypadku każdego innego elementu.
Poniższy kod źródłowy tworzy menu z elementami “Otwórz” i “Zakończ” oraz separatorem pomiędzy nimi:
#include<gtk/gtk.h>#include<gdk/gdkkeysyms.h>intmain(intargc,char*argv[]){
GtkWidget *okno;
GtkWidget *vbox;
GtkWidget *pasek;
GtkWidget *menu;
GtkWidget *plik;
GtkWidget *otworz;
GtkWidget *separator;
GtkWidget *wyjdz;
GtkWidget *etykieta1;
GtkAccelGroup *grupa_akcel;gtk_init(&argc,&argv);
okno =gtk_window_new(GTK_WINDOW_TOPLEVEL);gtk_window_set_position(GTK_WINDOW(okno), GTK_WIN_POS_CENTER);gtk_window_set_default_size(GTK_WINDOW(okno),250,200);gtk_window_set_title(GTK_WINDOW(okno),"Kurs GTK+");
vbox =gtk_vbox_new(FALSE,0);gtk_container_add(GTK_CONTAINER(okno), vbox);
etykieta1 =gtk_label_new("Lorem ipsum dolor sit amet, consectetur adipiscing elit. \
Maecenas sit amet magna in mi tincidunt iaculis sit amet quis augue. Curabitur libero est, \
vehicula vel consequat a, cursus sit amet risus. Nulla id eros arcu, sit amet dictum eros. \
Cras mollis, leo et dignissim bibendum, purus sapien interdum enim, ut.");gtk_label_set_line_wrap(GTK_LABEL(etykieta1),TRUE);
pasek =gtk_menu_bar_new();
menu =gtk_menu_new();
grupa_akcel =gtk_accel_group_new();gtk_window_add_accel_group(GTK_WINDOW(okno), grupa_akcel);
plik =gtk_menu_item_new_with_mnemonic("_Plik");
otworz =gtk_image_menu_item_new_from_stock(GTK_STOCK_OPEN,NULL);
separator =gtk_separator_menu_item_new();
wyjdz =gtk_image_menu_item_new_from_stock(GTK_STOCK_QUIT,NULL);gtk_image_menu_item_set_always_show_image(GTK_IMAGE_MENU_ITEM(otworz),true);gtk_image_menu_item_set_always_show_image(GTK_IMAGE_MENU_ITEM(wyjdz),true);gtk_widget_add_accelerator(otworz,"activate", grupa_akcel, GDK_o, GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE);gtk_widget_add_accelerator(wyjdz,"activate", grupa_akcel, GDK_q, GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE);gtk_menu_item_set_submenu(GTK_MENU_ITEM(plik), menu);gtk_menu_shell_append(GTK_MENU_SHELL(menu), otworz);gtk_menu_shell_append(GTK_MENU_SHELL(menu), separator);gtk_menu_shell_append(GTK_MENU_SHELL(menu), wyjdz);gtk_menu_shell_append(GTK_MENU_SHELL(pasek), plik);gtk_box_pack_start(GTK_BOX(vbox), pasek,FALSE,FALSE,0);gtk_box_pack_start(GTK_BOX(vbox), etykieta1,FALSE,FALSE,3);g_signal_connect(G_OBJECT(okno),"destroy",G_CALLBACK(gtk_main_quit),NULL);g_signal_connect(G_OBJECT(wyjdz),"activate",G_CALLBACK(gtk_main_quit),NULL);gtk_widget_show_all(okno);gtk_main();return0;}
Jego działanie jest następujące:
8.5. Paski narzędziowe
Pasków narzędziowych się używa, aby przyspieszyć pracę z programem, dając użytkownikowi natychmiastowy dostęp do funkcji takich jak np. otwieranie, zapisywanie, drukowanie, czy chociażby cofanie oraz ponawianie. Pasek narzędziowy tworzy się funkcją:
GtkWidget*gtk_toolbar_new(void);
Warto ustawić mu styl. W tym celu należy posłużyć się funkcją:
W pierwszym argumencie przyjmuje ona referencję do paska narzędziowego, w drugim referencję do elementu, który ma zostać dodany, a w ostatnim żądaną pozycję. Aby umieścić element na końcu, można przekazać w ostatnim argumencie liczbę -1.
Poniższy kod źródłowy może pomóc zrozumieć, jak utworzyć pasek narzędziowy.