R-08-t.doc

(315 KB) Pobierz
Szablon dla tlumaczy

8. Programowanie graficznych interfejsów użytkownika (GUI) z pomocą GNOME-GTK+

Środowisko modelowych obiektów sieciowych GNOME (GNU Network Object Model Enviroment) to rozkwitająca gałąź projektu rozwoju darmowego oprogramowania GNU (ang. GNU free software project). Celem projektu GNOME jest zbudowanie wszechstronnego i łatwego w obsłudze środowiska pulpitowego dla użytkownika oraz wydajnych i skutecznych komponent aplikacyjnych dla programistów. Biblioteki GNOME i GTK+ (na których elementy graficzne GNOME głównie się opierają) poprzez ścisłe połączenie narzędzi pulpitu z wydajną i elastyczną konstrukcją oprogramowania, uatrakcyjniają bogactwem możliwości opracowywanie w Linuksie profesjonalnych aplikacji GUI (ang. Graphic User Interface), czyli graficznych interfejsów użytkownika.

Zestawy narzędzi graficznych, takie jak Tk, Qt, Motif i inne, są obecne od dawna dla ukrycia przed programistą GUI interfejsu programowania aplikacji API (ang. Application Programming Interface) systemu X Window. Jakie są zatem, dokładnie, zalety bibliotek GNOME i GTK+?

q       Z licencją GPL (General Public Licence) biblioteki GNOME i GTK+ są, były i zawsze będą całkowicie darmowym oprogramowaniem. Podstawową ich zaletą w stosunku np. do KDE (ang. K Desktop Environment środowisko pulpitowe K) jest to, że w odróżnieniu od KDE, w swojej wewnętrznej strukturze nie wykorzystują żadnego własnościowego, choćby tylko w części, oprogramowania.

q       Mając na względzie łatwość przenoszenia, są one napisane w języku C, implementując wyrafinowany system obiektów i typów by dostarczyć zorientowanej obiektowo, całościowej konstrukcji. Taka konstrukcja zachęca do połączeń językowych. Do programowania z GNOME-GTK+ można już używać C, C++, Python, Guile i Perl.

q       Podstawowym elementem strukturalnym w nowym i nadchodzącym wydaniach GNOME jest Bonobo. Ta technologia umożliwia implementowanie możliwych do wbudowania komponentów wielokrotnego użycia, podobnych do ActiveX i Java Beans. To pozwoli, na przykład, na wbudowanie komponentu graficznego czy też edytora tekstu do programu arkusza kalkulacyjnego.

Pulpit GNOME jest jednocześnie przyjazny w użyciu i niezwykle łatwo dostosowuje się do indywidualnych potrzeb. Menu są wstępnie skonfigurowane do intuicyjnie najwłaściwszego układu oraz posiadają dobrze zaprojektowane i atrakcyjne ikony. GNOME jest niezależny od menedżera okien, ale dostarcza „wskazówek” dla kompatybilnych menedżerów okien, aby poprawnie oddziaływały z takimi charakterystykami GNOME jak, na przykład, panel.

Zakładając podstawową wiedzę o GNOME-GTK+, w tym rozdziale omówimy fundamentalne zagadnienia dotyczące GNOME-GTK+. Podsumujemy znane tematy i omówimy w zarysie pojęcia zaawansowane. Celem jest osiągnięcie poziomu, na którym będzie można w komfortowy sposób zrealizować z pomocą GNOME-GTK+ interfejs GUI dla aplikacji „Filmoteka DVD” (DVD Store). Będziemy pracować wyłącznie w języku C, co, jak zobaczymy, pasuje zaskakująco dobrze do zorientowanej obiektowo struktury GNOME-GTK+.

Wszyscy, dla których GNOME-GTK+ jest całkowitą nowością, mogą najpierw zapoznać się ze źródłami o charakterze wprowadzającym, które są podane na końcu tego rozdziału.

Omówimy:

q       biblioteki GTK+ i GNOME

q       glib — bibliotekę narzędziową C

q       GTK+ — podstawowy zestaw narzędzi

q       podstawy GNOME

q       drzewo kodu źródłowego GNOME

q       zapis konfiguracji

q       analizę składniową wiersza poleceń

q       zarządzanie sesją

q       źródła dodatkowej informacji o GNOME-GTK+

Biblioteki GTK+ i GNOME

W tym i następnym podrozdziale zajmować się będziemy prawie wyłącznie następującymi bibliotekami:

q       glib

q       GTK+ (wraz z GDK)

q       GNOME

glib

glib dostarcza szkieletu konstrukcyjnego dla większości struktur bibliotek GTK+ i GNOME. Jest to wszechstronna biblioteka, oferująca wszelakie akcesoria obsługi dla programistów języka C, włączając w to: funkcje pamięci, przechowywanie danych i funkcje sortujące. Zawiera również wiele ulepszonych wariantów standardowych funkcji systemowych oraz funkcji bibliotecznych C. Spenetrujemy to szczegółowo w kolejnym podrozdziale, gdzie wyjaśnimy, co rozumie się przez „ulepszone warianty” (ang. improved alternatives).

GTK+

GTK+ (ang. GIMP ToolKit), czyli zestaw narzędzi GIMP (ang. GNU Image Manipulation Program — uniwersalny program do przetwarzania obrazków) jest zestawem narzędzi GUI używanym przez GNOME, udostępniającym warstwę abstrakcji pomiędzy programistą a odnośnym systemem okien (system X Window, czy też Win32). Dzięki temu programowanie aplikacji GUI jest mniej bolesne. Zwolennicy zestawu GTK+ wskazują na jego wspaniały system układu pojemników (zobacz podrozdział Pojemniki w dalszym części tego rozdziału) do projektowania okien, jak też przejrzysty system łączenia zdarzeń generowanych przez użytkownika z kodem.

W systemie X Window, zdarzenia nazywa się sygnałami. Takie sygnały różnią się całkowicie od sygnałów niskiego poziomu w UNIX-ie, a więc nie należy ich mylić ze sobą.

GDK

GDK (GIMP Drawing Kit) jest zestawem narzędzi do rysowania, który udostępnia cienką warstwę pomiędzy aplikacjami a elementarnymi procedurami Xlib do rysowania. W czasie opracowywania oprogramowania przy użyciu GTK+, w istocie używa się otoczki wokół GDK, który z kolei stanowi otoczkę wokół systemu X. Oznacza to, że biblioteka GDK jest niezbędnym składnikiem w opracowywaniu aplikacji dla Linuksa, z wykorzystaniem narzędzi GTK+ i GNOME.

Istnieją jeszcze inne, bardzo rozbudowane, biblioteki związane z GNOME. Ich opis stanowczo wykracza poza zakres tej książki. Jednak z uwagi na to, że w środowisku użytkowników GNOME powszechnie się ich używa i do nich odwołuje, grzechem byłoby o nich nie wspomnieć. Są to:

q       Imlib

q       ORBit

q       libGnorba

Imlib

Imlib jest rozbudowaną biblioteką do obsługi grafiki, zdolną do operowania dużą liczbą formatów graficznych, jak np. JPG i PNG. GNOME używa wersji GDK tej biblioteki. W przyszłości, biblioteka Imlib będzie zastąpiona przez doskonalszą bibliotekę gdk_pixbuf.

ORBit

ORBit jest nieodpłatnie udostępnianą implementacją CORBA 2.2 ORB, zaprojektowaną z myślą o  szybkości i prostocie. ORBit także obsługuje język C, a zatem jest właściwym wyborem obiektowego pośrednika zapytań ORB dla GNOME. W rozdziale 20 i 21 będzie można więcej przeczytać o CORBA.

libGnorba

libGnorba zaopatruje GNOME w łącza (ang. links) z ORBit, włącznie z mechanizmami aktywacji obiektów i systemem zabezpieczeń.

Biblioteka glib

glib jest biblioteką narzędzi C ogólnego przeznaczenia, która dostarcza solidnych elementów niskiego poziomu, o zasadniczym znaczeniu dla operacji przenoszenia oprogramowania pomiędzy różnymi typami systemów UNIX i Windows. Biblioteka glib wnosi standardowy zestaw funkcji narzędziowych i typów danych do wykorzystania przez  programistów wszystkich platform. Dzięki temu nie trzeba wyważać otwartych drzwi i skrócić zarówno czas opracowania aplikacji, jak też zużycie pamięci. Co więcej, biblioteka może zwiększyć stabilność opracowywanego kodu, bo nie trzeba poznawać nowych standardów dla każdej platformy, na której się programuje. I jest cudownie użyteczna — może nawet zabłysnąć przy zwykłym opracowywaniu aplikacji dla Linuksa.

Zestaw funkcji udostępnianych przez glib wywiera imponujące wrażenie, niezależnie od przyjętych standardów. Szczegółowe ich omówienie wykracza znacznie poza ramy tego rozdziału. Na szczęście, podobnie jak każdy typowy projekt GNU, biblioteka glib jest bardzo dobrze opisana, zarówno na swojej witrynie WWW, www.gtk.org, jak też i w pliku nagłówkowym glib.h. Nawet jeśli ktoś nie należy do wielbicieli czytania plików nagłówkowych, powinien docenić skarbnicę wiedzy tam zawartą. Nierzadko też okazuje się, że szybciej można odnaleźć potrzebną informację w pliku nagłówkowym, niż wskutek przeglądania plików pomocy czy stron WWW.

GNOME i GTK+ same znacząco polegają na typach, funkcjach i makrodefinicjach uruchomieniowych udostępnionych przez glib. Tak więc, należyte opanowanie wiedzy na temat glib powinno być kamieniem węgielnym każdego kursu programowania w GNOME-GTK+.

W tym podrozdziale zostaną scharakteryzowane:

q       typy biblioteki glib,

q       makrodefinicje,

q       procedury obsługi pamięci (ang. memory routines),

q       funkcje obsługi łańcuchów,

q       listy.

Typy

Jeden ważny, acz często zaniedbywany, aspekt języka C to zależność rozmiaru pewnych elementarnych typów od platformy systemowej. Na przykład, int zwykle zajmie 32 bity pamięci, ale niektóre komputery mogą zarezerwować dla int mniej lub więcej. Oczywiście, istnieją względnie proste metody programowania, które pozwalają wykluczyć tego rodzaju problemy, niemniej jednak pomyłki się zdarzają.

Dlatego też, aby uczynić nasze życie łatwiejszym, glib definiuje własny zbiór elementarnych typów o gwarantowanej długości, na dodatek z nowymi typami wskaźnikowymi (ang. pointer types) boolean, string i void. I tak na przykład, gint16 jest typem całkowitym ze znakiem o długości 16 bitów, a guint16 jest jego odpowiednikiem bez znaku.

 

typ zdefiniowany w glib

Opis

gint8, gint16, gint32, gint64

liczba całkowita o gwarantowanej długości, ze znakiem

guint8, guint16, guint32, guint64

liczba całkowita o gwarantowanej długości, bez znaku

gboolean

typ boolowski, TRUE i FALSE także zdefiniowane w glib

gint

odpowiednik int

gshort

odpowiednik short

gchar

odpowiednik char

gfloat

odpowiednik float

gdouble

odpowiednik double

gpointer

odpowiednik void *

 

Zauważmy, że gint64 i guint64 istnieją jedynie wtedy, gdy platforma systemowa może je wspomóc. Jeśli tak, to glib zdefiniuje G_HAVE_GINT64.

Typy gint, gshort, gchar, gfloat i gdouble są otoczkami istniejących typów języka C i są włączone jedynie dla zachowania zgodności. Biorąc pod uwagę ich identyczną naturę, można zapytać jakie korzyści płyną z użycia gint w miejsce int, czy też gchar zamiast char. Faktem jest, że technicznie rzecz biorąc, nie ma żadnej różnicy. Jednak rozważając to w kategoriach stylu dobrego programowania zachowamy zgodność, a tej zasadzie jak najczęściej powinno pozostawać się wiernym. Użycie jednolitego stylu kodowania i zachowanie zgodności jest szczególnie istotne przy pisaniu kodu dla wielu platform systemowych. Tak więc, choć skompilowany kod nie odczuje różnicy spowodowanej zastąpieniem int przez gint, to taka zamiana może jednak pomóc programiście w bardziej subtelny sposób.

Makrodefinicje

Biblioteka glib definiuje kilka makrodefinicji pomocnych w ogólnym programowaniu i usuwaniu błędów (ang. debugging). Większość z nich będzie zapewne znana programistom języka C. Dla uzupełnienia typu gboolean załączono makrodefinicje TRUE oraz FALSE. NULL jest wstępnie zdefiniowane jako pusty wskaźnik (ang. void pointer): (void *)0 w ANSI C.

Istnieje także kilka prostych makrodefinicji dla ułatwienia żonglowania liczbami. Wszystko po to, by przyspieszyć kodowanie i zwiększyć czytelność kodu.

 

Makrodefinicja

Opis

FALSE

#define FALSE (0)

TRUE

#define TRUE (!FALSE)

NULL

#define NULL ((void *) 0)

ABS(x)

zwraca wartość bezwzględną x

MIN(a,b)

zwraca mniejszą z liczb a i b

MAX(a,b)

zwraca większą z liczb a i b

CLAMP(x, mniejszy, wiekszy)

zwraca x jeśli x jest pomiędzy mniejszy i wiekszy; zwraca mniejszy, jeśli x<mniejszy oraz wiekszy, jeśli x>wiekszy.

 

W zależności od procesora komputera, makrodefinicja G_BYTE_ORDER przyjmuje wartość G_LITTLE_ENDIAN, G_BIG_ENDIAN lub G_PDP_ENDIAN (odpowiednio, kolejność bajtów 4321, 1234 i 3412).

Makrodefinicje diagnostyczne

Biblioteka glib dostarcza zbioru makrodefinicji (ang. macro), które mogą być użyte do sprawdzenia założeń poczynionych w kodzie. Dzięki nim błędy w programach mogą być szybciej wyłapane. Trzeba rozmieścić te makrodefinicje w trybie sprawdzania kodu (ang. code check conditions), a następnie je zweryfikować (ang. make assertions). W razie niepowodzenia weryfikacji warunku, makrodefinicje wydrukują ostrzeżenie na konsoli. Mogą wymusić natychmiastowy powrót do funkcji wywołującej a nawet wymusić zakończenie aplikacji.

Makrodefinicje dzielą się na dwa typy: te, które są powszechnie używane do sprawdzania poprawności argumentów dostarczonych przez funkcję wywołującą. oraz na te, używane do sprawdzenia warunków w obrębie funkcji.

Sprawdzenie poprawności argumentów jest często pierwszą czynnością przy rozpoczęciu funkcji. Jest to, tak zwane, sprawdzenia warunków koniecznych (ang. precondition checks). Dwie takie makrodefinicje g_return_val_if_fail(warunek, zwrocona_wart) oraz g_return_if_fail(warunek) drukują ostrzeżenie jeśli (warunek!=TRUE) i powracają z funkcji. Podczas gdy pierwsza z tych funkcji zwraca zwrocona_wart i jako taka musi być użyta dla funkcji, które nie są deklarowane w pustym kontekście (ang. void), druga funkcja jest używana w funkcjach, które nie przekazują wartości (ang. void functions).

Nie trzeba długo szukać, aby znaleźć przykłady w kodach źródłowych GNOME — oto wycinek z implementacji panelu w GNOME:

 

void

panel_clean_applet(AppletInfo *info)

{

     g_return_if_fail(info != NULL);

 

     if(info->widget) {

          if(info->type == APPLET_STATUS) {

               status_applet_put_offscreen(info-data);

          }

          gtk_widget_destroy(info->widget);

     }

}

 

Bez g_return_if_fail, gdyby info przekazano NULL, funkcja panel_clean_applet wpadłaby w tarapaty. W obecności makrodefinicji weryfikującej warunek, g_return_if_fail zwraca komunikat o błędzie:

 

** CRITICAL **: file panel.c: line 227 (panel_clean_applet):

                assertion 'info != NULL' failed.

 

który...

Zgłoś jeśli naruszono regulamin