GTK+/Glade - budowniczy interfejsu
Z Wikibooks, biblioteki wolnych podręczników.
Glade to narzędzie, które pozwala tworzyć w wygodny sposób interfejs programu, tzw. RAD. Do przedstawionego przykładu używałem Glade w wersji 3.4.3. Program ma za zadanie pokazać jak korzystać z wygenerowanego pliku *.glade (w formacie xml). W programie Glade tworzymy zwykłe okno (window1). Następnie dodajemy do niego przycisk (button1). Dla przycisku ustawiamy zdarzenie „clicked” a jako uchwyt wybieramy zaproponowaną nazwę funkcji on_button1_clicked(). Zapisujemy projekt pod nazwą test. Oto jak teraz wygląda szablon interfejsu wygenerowany przez Glade:
<?xml version="1.0" encoding="UTF-8" standalone="no"?> <!DOCTYPE glade-interface SYSTEM "glade-2.0.dtd"> <!--Generated with glade3 3.4.3 on Sat May 24 14:24:41 2008 --> <glade-interface> <widget class="GtkWindow" id="window1"> <child> <widget class="GtkButton" id="button1"> <property name="visible">True</property> <property name="can_focus">True</property> <property name="receives_default">True</property> <property name="label" translatable="yes">button</property> <property name="response_id">0</property> <signal name="clicked" handler="on_button1_clicked"/> </widget> </child> </widget> </glade-interface>
Widzimy, że zawiera on obiekt klasy GtkWidget o nazwie window1. W jego wnętrzu (jak w kontenerze) znajduje się kontrolka GtkButton o nazwie button1. Oprócz właściwości ma też zdefiniowany sygnał "clicked", który wskazuje na funkcję on_button1_clicked.
Programy pisane w GTK+ do korzystania z funkcjonalności programu Glade potrzebują struktury GladeXML. Oto kod programu, który będzie wyświetlał dialog, gdy klikniemy na przycisk.
// gcc gladetest.c -Wall -o gladetest `pkg-config gtk+-2.0 --cflags --libs` -I/usr/include/libglade-2.0 -lglade-2.0 -export-dynamic #include <gtk/gtk.h> #include <glade/glade.h> void on_button1_clicked(GtkWidget* widget, gpointer user_data) { GtkWidget *dialog = gtk_message_dialog_new (user_data, GTK_DIALOG_MODAL, GTK_MESSAGE_INFO, GTK_BUTTONS_OK, "Zdarzenie zadziałało ;)"); gtk_dialog_run (GTK_DIALOG(dialog)); gtk_widget_destroy (dialog); } int main(int argc, char *argv[]) { GtkWidget *window1, *button1; GladeXML *fileglade; gtk_init(&argc,&argv); fileglade = glade_xml_new ("/home/grzesiek/Pulpit/gtk/test.glade",NULL,NULL); window1 = glade_xml_get_widget(fileglade,"window1"); glade_xml_signal_autoconnect(fileglade); g_signal_connect (G_OBJECT(window1), "destroy", G_CALLBACK(gtk_main_quit), NULL); gtk_widget_show_all(window1); gtk_main(); return 0; }
Jeżeli chodzi o kompilacje to nowością mogą tu być opcje: -I/usr/include/libglade-2.0 -lglade-2.0 oraz -export-dynamic. Pierwsza z nich wskazuje dla kompilatora gdzie ma szukać pliku glade.h, druga jest niezbędna do prawidłowego działania łączenia autosygnałów.
int main(int argc, char *argv[]) { GtkWidget *window1; GladeXML *fileglade; gtk_init(&argc,&argv); fileglade = glade_xml_new ("/home/grzesiek/Pulpit/gtk/test.glade",NULL,NULL); window1 = glade_xml_get_widget(fileglade,"window1");
Program zaczynamy od zadeklarowania widgetu window1 oraz obiektu GladeXML. Za pomocą funkcji glade_xml_new() tworzymy obiekt GladeXML, któremu przypisujemy strukturę pliku test.glade. Wskaźnik do głównego okna pobieramy za pomocą funkcji glade_xml_get_widget(), gdzie podajemy obiekt GladeXML oraz kontrolkę, którą chcemy pobrać.
glade_xml_signal_autoconnect(fileglade); g_signal_connect (G_OBJECT(window1), "destroy", G_CALLBACK(gtk_main_quit), NULL); gtk_widget_show_all(window1); gtk_main(); return 0; }
Pobraliśmy już potrzebne nam kontrolki z pliku test.glade. Nie musimy pobierać wszystkich kontrolek, zwłaszcza gdy w Glade podczas projektowania interfejsu zdefiniowaliśmy nazwy funkcji przypisane sygnałom, które mają obsługiwać kontrolki. Dlatego nie pobieramy wskaźnika button1. Zamiast tego wywołujemy funkcję glade_xml_signal_autoconnect(), która wyszuka w pliku test.glade wszystkie sygnały i przypisze je za nas do funkcji obsługi, o ile te funkcje istnieją. Sygnał "destroy" dla window1 jest już przypisywany ręcznie a nie automatycznie. Co nie znaczy, że nie możnaby było tego zrobić za pomocą mechanizmu autołączenia sygnałów. Wystarczyłoby w Glade dla kontrolki window1 zdefiniować sygnał "destroy" i jako uchwyt przypisać mu od razu funkcje gtk_main_quit() zamiast innej - własnej, w której z kolei wywołujemy gtk_main_quit(). Można też tworzyć interfejs w Glade lub tylko jego część a sygnały łączyć samemu. Wtedy musielibyśmy pobrać kontrolkę button1 tak jak window1 i jak to było opisywane w przykładowym programie połączyć sygnał "clicked" z jakąś funkcją. Oczywiście ta funkcja musi pasować do szablonu funkcji zwrotnej.
void on_button1_clicked(GtkWidget* widget, gpointer user_data) { GtkWidget *dialog = gtk_message_dialog_new (user_data, GTK_DIALOG_MODAL, GTK_MESSAGE_INFO, GTK_BUTTONS_OK, "Zdarzenie zadziałało ;)"); gtk_dialog_run (GTK_DIALOG(dialog)); gtk_widget_destroy (dialog); }
To funkcja, która zostanie automatycznie przypisana do sygnału "clicked" dla kontrolki button1. W ciele funkcji tworzymy okienko dialogowe, którego zadaniem zazwyczaj jest informowanie użytkownika o jakiś zdarzeniach. My z kolei wykorzystujemy je tu po to, aby zobaczyć, że interfejs programu może być jednocześnie tworzony za pomocą programu Glade z automatycznym łączeniem sygnałów lub bez oraz jednocześnie niektóre elementy interfejsu nadal można/trzeba budować "ręcznie" poprzez pisanie kodu.
[edytuj] Glade + PyGTK = szybki interfejs
Połączenie budowania interfejsu programu w Glade oraz jego wykorzystanie za pomocą języka Python pozwala na bardzo szybkie budowanie aplikacji z GUI. Zbiór narzedzi PyGTK + Glade sprawuje się prawie jak C++ Builder.
#!/usr/bin/env python import pygtk pygtk.require('2.0') import gtk import gtk.glade def on_button1_clicked(ok_button): dialog = gtk.MessageDialog(window1, gtk.DIALOG_MODAL, gtk.MESSAGE_INFO, gtk.BUTTONS_OK, 'Zdarzenie zadzialalo ;)') dialog.run() dialog.destroy() fileglade = gtk.glade.XML('/home/grzesiek/Pulpit/gtk/test.glade') window1 = fileglade.get_widget('window1') sygnaly = {"on_button1_clicked":on_button1_clicked} fileglade.signal_autoconnect(sygnaly) window1.connect("delete_event", gtk.main_quit) window1.show_all() gtk.main()
To analogiczny program do przedstawionego powyżej. Korzysta z tego samego projektu test.glade. Wykorzystanie PyGTK sprawia, że pisanie jest szybsze i prostsze.

