Wstęp
Glade to narzędzie, które pozwala tworzyć w wygodny sposób interfejs programu, tzw. RAD. Rapid Application Development oznacza szybkie tworzenie aplikacji. Projektowany interfejs zapisany jest w postaci pliku XML.
Kurs dotyczy wersji programu Glade 3.8.1 i wyższych.
Poniżej przykładowy kompletny interfejs w postaci pliku XML:
<?xml version="1.0"?>
<interface>
<requires lib="gtk+" version="2.16"/>
<!-- interface-naming-policy project-wide -->
<object class="GtkWindow" id="window1">
<property name="visible">True</property>
<property name="title" translatable="yes">Okno</property>
<child>
<placeholder/>
</child>
</object>
</interface>
Strona domowa programu Glade
http://glade.gnome.org. Stamtąd również dla systemów operacyjnych Windows należy pobrać
paczkę jeżeli masz już zainstalowaną bibliotekę Gtk+ i znajduje się ona w ścieżce przeszukiwań (PATH), albo tą
paczkę, który zawiera wraz z programem kompletną bibliotekę Gtk+ wraz z bibliotekami towarzyszącymi.
W przypadku systemów Linux w zależności od dystrybucji należy za pomocą menadżera pakietów zainstalować pakiet Glade, lub pobrać
kod źródłowy i samodzielnie skompilować program Glade.
Po uruchomieniu programu Glade pojawi się okno:
Poeksperymentuj, wciskając różne ikonki obserwując co się dzieje :)
Pierwszy projekt - okno najwyższego poziomu
Aby utworzyć okno programu:
1. Wybierz ikonkę symbolizującą podstawowe okno. Pojawi się okno.
2. Ustaw tytuł okna "Kurs Glade", który będzie widoczny na belce okna.
3. Ustaw domyślne rozmiary okna.
Następnie zapisz plik jako
kurs.ui, przyjęło się że pliki tworzone Glad'em mają rozszerzenie ui. Ważne by plik był zapisany w formacie
GtkBuilder, domyślnym zapisem jest właśnie GtkBuilder. Kiedyś powszechnie używanym formatem był Libglade, jednak nie będę się nim zajmował, bo to już historia.
Mając już projekt interfejsu (co prawda tylko same okno), opiszę jak wykorzystać go w programie.
Należy utworzyć obiekt GtkBuilder funkcją:
GtkBuilder * gtk_builder_new( void );
Następnie:
guint gtk_builder_add_from_file( GtkBuilder * builder, const gchar * filename, GError ** error );
Funkcja przetwarza plik (drugi argument filename) zawierający definicje interfejsu i łączy go z bieżącą zawartością obiektu GtkBuilder (pierwszy argument builder) Trzecim argumentem jest wskaźnik na strukturę GError, która jest odpowiednio wypełniana w przypadku błędu. W przypadku błędu funkcja zwróci wartość 0.
Przykład użycia:
#include <gtk/gtk.h>
#define UI_FILE "kurs.ui"
GtkWidget * utworz_okno( void )
{
GtkWidget * okno;
GtkBuilder * builder;
GError * error = NULL;
builder = gtk_builder_new();
if( !gtk_builder_add_from_file( builder, UI_FILE, & error ) )
{
g_warning( "Nie można wczytać plilu buildera: %s", error->message );
g_error_free( error );
}
gtk_builder_connect_signals( builder, NULL );
okno = GTK_WIDGET( gtk_builder_get_object( builder, "window1" ) );
g_object_unref( builder );
return okno;
}
int
main( int argc, char * argv[] )
{
GtkWidget * okno;
gtk_set_locale();
gtk_init( & argc, & argv );
okno = utworz_okno();
gtk_widget_show( okno );
gtk_main();
return 0;
}
Po skompilowaniu i uruchomieniu pojawi się okno programu:
Program nie reaguje na sygnał zamknięcia okna, należy odpowiednio obsłużyć to zdarzenie poprzez standardowe skojarzenie sygnału
destroy z funkcją biblioteki Gtk+
gtk_main_quit w kodzie pisanego programu, albo obsłużyć z poziomu Glade'a:
We właściwościach obiektu "window1" w zakładce
Sygnały należy odszukać sygnału
destroy i w uchwycie do tego sygnału wybrać
gtk_main_quit. Teraz program po zamknięciu okna kończy działanie zwracając do systemu wartość 0 poprzez wyjście z pętli funkcji gtk_main.
Tak na marginesie w nowszych wesjach programu Glade 3.10 i wzwyż zrezygnowano z podpowiedzi użycia funkcji w formie listy rozwijanej. Sam musisz wpisać nazwę funkcji :(
Bardziej rozbudowany przykład - obsługa sygnału przycisku
Rozbudujmy interfejs użytkownika:
1. Wybierz w palecie kontrolek dotyczącej kontenerów ikonkę
Pionowa skrzynka i przeciągnij ją do stworzonego wcześniej okna. Utwórz 2 elementy. Kontrolka "Pionowa skrzynka" to po prostu GtkVBox.
2. Przeciągnij ikonkę symbolizującą zwykły przycisk w miejsce 1 elementu "Pionowej skrzynki".
3. Analogicznie zrób z ikonką zmiennego przycisku (togglebutton) dodając go w miejsce 2 elementu.
Mając utworzone przyciski należy skojarzyć je z odpowiednimi sygnałami dołączając odpowiednią funkcje zwrotną dla danego sygnału.
Wybierz obiekt
togglebutton1, w jego właściwościach w zakładce sygnały odszukaj sygnał
toggled. Następnie w kolumnie "Program obsługujący" / "uchwyt" (zależy od wersji językowej) wybierz z listy rozwijanej sugerowaną nazwę funkcji zwrotnej
on_togglebutton1_toggled.
Wykonaj podobną operację dla obiektu
button1, z tym że skojarz sygnał
clicked z funkcją
on_button1_clicked.
Zawartośc pliku kurs.ui wygląda następująco:
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<requires lib="gtk+" version="2.22"/>
<!-- interface-naming-policy project-wide -->
<object class="GtkWindow" id="window1">
<property name="can_focus">False</property>
<property name="title" translatable="yes">Kurs Glade</property>
<property name="default_width">450</property>
<property name="default_height">250</property>
<signal name="destroy" handler="gtk_main_quit" swapped="no"/>
<child>
<object class="GtkVBox" id="vbox1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<object class="GtkButton" id="button1">
<property name="label" translatable="yes">button</property>
<property name="use_action_appearance">False</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<signal name="clicked" handler="on_button1_clicked" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkToggleButton" id="togglebutton1">
<property name="label" translatable="yes">togglebutton</property>
<property name="use_action_appearance">False</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<signal name="toggled" handler="on_togglebutton1_toggled" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">1</property>
</packing>
</child>
</object>
</child>
</object>
</interface>
Poniżej przedstawię jak obsłużyć funkcję zwrotne zadeklarowane w Glade'ie. Proponuję, żeby oddzielić obsługę zdarzeń od głównego pliku programu. Utwórz dwa pliki
funkcje_zwrotne.h, gdzie będą przechowywane prototypy funkcji i
funkcje_zwrotne.c, w których będzie zawarta właściwa obsługa zdarzeń. Przyda się to zwłaszcza w dużych projektach.
Zawartość pliku funkcje_zwrotne.h:
#include <gtk/gtk.h>
void on_button1_clicked( GtkButton * button, gpointer user_data );
void on_togglebutton1_toggled( GtkToggleButton * togglebutton, gpointer user_data );
Zawartość pliku funkcje_zwrotne.c:
#include "funkcje_zwrotne.h"
void on_button1_clicked( GtkButton * button, gpointer user_data )
{
g_print( "Wcisnięto zwykły przycisk\n" );
}
void on_togglebutton1_toggled( GtkToggleButton * togglebutton, gpointer user_data )
{
g_print( "Wcisnięto zmienny przycisk\n" );
}
Uwaga! Kompiluj program z biblioteką gmodule używając opcji -lgmodule-2.0. Dodatkowo pod systemem Windows wymagane jest, żeby funkcje zwrotne były zaopatrzone w makro G_MODULE_EXPORT:
G_MODULE_EXPORT void on_button1_clicked( GtkButton * button, gpointer user_data );
W przypadku używania kompilatora g++, należy poinformować go o sposobie nazywania funkcji używając makr G_BEGIN_DECLS i G_END_DECLS. Przykład:
G_BEGIN_DECLS
G_MODULE_EXPORT void on_checkbutton_toggled( GtkToggleButton * togglebutton, gpointer user_data ); G_MODULE_EXPORT void on_radiobutton_toggled( GtkToggleButton * togglebutton, gpointer user_data );
G_END_DECLS
|
Główny plik u mnie (czyli main.c) jest bardzo podobny do poprzedniego, została dodana tylko linia
#include "funkcje_zwrotne.h"
:
#include <gtk/gtk.h>
#include "funkcje_zwrotne.h"
#define UI_FILE "kurs.ui"
GtkWidget * utworz_okno( void )
{
GtkWidget * okno;
GtkBuilder * builder;
GError * error = NULL;
builder = gtk_builder_new();
if( !gtk_builder_add_from_file( builder, UI_FILE, & error ) )
{
g_warning( "Nie można wczytać plilu buildera: %s", error->message );
g_error_free( error );
}
gtk_builder_connect_signals( builder, NULL );
okno = GTK_WIDGET( gtk_builder_get_object( builder, "window1" ) );
g_object_unref( builder );
return okno;
}
int
main( int argc, char * argv[] )
{
GtkWidget * okno;
gtk_set_locale();
gtk_init( & argc, & argv );
okno = utworz_okno();
gtk_widget_show( okno );
gtk_main();
return 0;
}
Program po naciśnięciu przycisku wyświetli w konsoli odpowiedni komunikat. Jeżeli będziesz zwiększał rozmiary okna zauważysz rozszerzanie się przycisków. Aby zmienić zachowanie się przycisków wraz z rozszerzaniem rozmiarów okna zmień we właściwościach danego przycisku w zakładce
Pakowanie np. rozszerzanie na
Nie.
Poeksperymentuj z opcjami w zakładce
Pakowanie zapisując zmiany i następnie uruchamiając program. Pamiętaj raz skompilowany działający program nie wymaga ponownej kompilacji. Ponownej kompilacji wymagałby tylko i wyłącznie program dla, którego została dodana obsługa nowych funkcji zwrotnych sygnałów.