2006 04 Piszemy widget zegara w GTK [Programowanie]


dla programistów
Piszemy
widget zegara
w GTK+
Marek Sawerwain
iblioteka GTK+ jest napisana będzie przygotowanie dwóch struktur:
w ANSI C i ma przystępne API, klasy oraz obiektu kontrolki (pojęcia klasa
co sprawia, że względnie szyb- czy obiekt GTK+, a dokładniej obiekt typu
Bko można nauczyć się pisania GObject, warto traktować jako odpowiedni-
skomplikowanych programów za jej po- ki klasy i obiektu z języka C++).
mocą. Tworzenie własnych widgetów (kon- Z procedurą osadzania związana jest
trolek graficznych) w GTK+ nie jest już jed- także inicjalizacja obiektu, o ile klasa jest
nak zadaniem zbyt łatwym i wymaga bar-
dzo dobrej znajomości biblioteki, która za-
Instalacja biblioteki GTK+
zwyczaj nie jest potrzebna podczas two-
Zastosowana przez nas wersja GTK+
rzenia typowego oprogramowania. W tym
2.8.x nie jest jeszcze szeroko stosowa-
artykule przedstawię, jak utworzyć własny
na. W wielu nieco starszych dystrybucjach
widget. Będzie to zegar, którego pózniej
systemu Linux jest dostępna poprzednia
będzie można użyć do  upiększenia wła-
wersja stabilna 2.6.x. Z tego powodu jest
snej aplikacji.
całkiem prawdopodobne, iż nowa wersja
Nie będzie to zegar liczbowy, bo taki
nadal nie jest dostępna. Nie trzeba się tym
widget byłby mimo wszystko zbyt łatwy
jednak martwić, gdyż można bez więk-
do opracowania. Dokonamy implemen-
szych problemów podmienić wersję GTK+
tacji tradycyjnego zegara ze wskazów-
2.6.x na nowszą 2.8.x. Wymaga to samo-
kami. Dodatkowo, użyjemy najnowsze-
dzielnej kompilacji GTK+ ze zródeł. W tym
go elementu GTK+, czyli biblioteki Cairo,
celu należy skompilować kilka pakietów:
która jest odpowiedzialna za generowanie
GLIB, ATK, PANGO, CAIRO oraz ostatecz-
wysokiej jakości grafiki 2D. Oznacza to,
nie GTK+. Wszystkie biblioteki instalujemy
iż należy dysponować najnowszą wersją
w katalogu /usr. Ponieważ każda z biblio-
GTK+, np. 2.8.x. Z tego powodu opisany
tek posiada skrypt configure, to za każdym
w tym artykule widget nie będzie współpra-
razem wystarczą trzy linie kodu:
cować z jakąkolwiek starszą wersją GTK+.
./configure  prefix=/usr
Plan kontrolki
make
Dla widgetu nie można utworzyć typowe-
make install
go schematu blokowego, ponieważ kon-
DVD
Po uruchomieniu Linux+ Live trolka to tylko pewien niewielki fragment
aby daną bibliotekę skonfigurować, poddać
DVD możesz zapoznać się
większego programu bądz systemu. Po- kompilacji oraz instalacji. Ponieważ autorzy
z prostą aplikacją z opisywanym
mimo tego, schemat z Rysunku 1 porusza
GTK+ utrzymują zgodność binarną swojej
w artykule widgetem zegara.
wszystkie obszary istotne dla poprawnego
biblioteki wstecz, to nie powinno być pro-
funkcjonowania kontrolki.
blemów, aby GNOME i inne aplikacje
Na płycie CD/DVD
Pierwszym elementem, którym musi- GTK+ współpracowały z nowszą wersją
Na płycie CD/DVD znajdują się
my się zająć, jest osadzenie kontrolki. Cho- biblioteki, którą instalujemy  na dziko w ist-
wykorzystywane biblioteki oraz
kod zródłowy programu. ciaż za ten proces jest odpowiedzialny sam
niejącym systemie.
system GTK+, to jednak naszym zadaniem
72 kwiecień 2006
dla programistów
GTK+/Cairo
#define GTK_IS_CLOCK(obj)
(G_TYPE_CHECK_INSTANCE_TYPE
((obj), GTK_TYPE_CLOCK))
Wykorzystujemy tu inne makro, G_TYPE_
CHECK_INSTANCE_TYPE, które sprawdza,
czy obiekt to instancja odpowiedniego dla
nas typu, określonego przez zdefiniowane
przez nas makro GTK_TYPE_CLOCK. Jednak,
gdy spojrzymy ponownie na Listing 1, to
okaże się, iż makro GTK_TYPE_CLOCK ogra-
nicza się do wywołania funkcji o nazwie
gtk_clock_get_type. Jej zadaniem jest
utworzenie struktury reprezentującej typ
widgetu. Jak się za chwilę okaże, funk-
cja gtk_clock_get_type jest generowana
samoczynnie, więc nie musimy się mar-
twić jej postacią.
Kolejnym elementem są dwie struktu-
ry. _GtkClock jest odpowiedzialna za prze-
chowywanie wartości związanych z kon-
kretnym obiektem, czyli instancją klasy
GtkClock, która to jest reprezentowana
przez strukturę o nazwie _GtkClockClass.
Rysunek 1. Schemat zdarzeń, które pojawiają się w kontrolce zegara
Do obydwu struktur za pomocą type-
tworzona częściowo przez system obiek- biblioteki GTK+, każdy plik z implemen- def tworzone są nowe redefinicje, co jest
towy GTK+ -- chociaż i tak piszemy funk- tacją innych widgetów będzie posiadał ważne z powodu pewnych konwen-
cję przeznaczoną do inicjalizacji klasy, to podobną strukturę. cji, które zostały przyjęte przez autorów
ważnym zadaniem jest napisanie kon- Kod pliku nagłówkowego po zdefinio- GTK+ oraz GLib.
struktora obiektu, tzn. funkcji o nazwie np. waniu stałej __GTK_CLOCK_H__ oraz po włą- Struktura _GtkClock posiada zaledwie
gtk_clock_new. czeniu pliku gtk.h rozpoczynamy od wy- pięć pól. Pola o nazwach h, m i s będą
Oprócz klasy oraz konstruktora, nale- wołania makra G_BEGIN_DECLS i, co ważne, zawierać aktualny czas, a pole clock_
ży podłączyć obsługę dwóch zdarzeń. Pier- kończymy G_END_DECLS. Obecnie zada- update_handle zawiera uchwyt do obie-
wsze to zdarzenie expose, które jest wywo- niem tych makr jest dodanie wyrażenia ktu timer, który w równych jednosekun-
ływane, gdy system prosi o narysowa- extern  C , aby nasz projekt kompilował dowych odstępach czasu będzie uaktu-
nie kontrolki na ekranie. Drugie to zda- się poprawnie w środowisku C++. Nie alniał nasz zegar. Ostatnim polem jest
rzenie timer, które będzie generowane jest wykluczone, iż w przyszłości makra te parent, które będzie wskazywać na
cyklicznie co sekundę. Jest ono potrzebne, będą wprowadzać inne istotne definicje. widget rodzicielski naszej kontrolki
aby nasz zegar co sekundę odświeżał swój Następnie podajemy kilkanaście defi-  inaczej mówiąc, widget, który zawiera
wygląd. nicji makr, które ułatwiają używanie kon- (można powiedzieć, przechowuje) nasza
Aby wprowadzić więcej czytelności do trolki w środowisku GTK+. Przydatnym kontrolkę.
kodu, za narysowanie widgetu (w naszym makrem jest np. GTK_CLOCK, które wyko- Struktura klasy jest już znacznie bar-
przypadku to tarcza typowego zegara) nuje konwersję widgetu ogólnego typu dziej uboższa, ponieważ zawiera tylko
będzie odpowiedzialna inna funkcja o naz- (GtkWidget) na widget typu GtkClock. jedno pole, w którym przechowujemy
wie draw_clock, będąca funkcją prywatną Ważnym makrem jest również GTK_IS_ wskazanie na klasę rodzica naszego wid-
klasy GtkClock. CLOCK, gdyż pozwala ono sprawdzić, czy getu. Po definicji klasy pozostaje nam tylko
Chociaż można dodać jeszcze wiele dany obiekt jest istotnie instancją klasy wymienić funkcje publiczne. W naszym
innych przydatnych funkcji, np. dbają- GtkClock. W każdym dynamicznym sys- przypadku będzie to tylko funkcja kon-
cych o wygląd naszego zegara, to jednak, temie obiektowym tego typu funkcje są struktora gtk_clock_new. Oczywiście, jeśli
aby uprościć nasz widget, poprzestaniemy konieczne, aby cały system funkcjonował dodamy do naszej kontrolki więcej moż-
tylko na implementacji podstawowej funk- poprawnie. liwości, to w pliku nagłówkowym należy
cjonalności kontrolki. Jak widać, nie musimy definiować wymienić nowe funkcje.
tych makr wprost  wystarczy skorzy-
Plik nagłówkowy stać z gotowych funkcji, które znajdują się Implementacja widgetu
Tworzenie widgetu zaczniemy od przy- w API systemu GObject, będącego częścią Po przygotowaniu pliku nagłówkowego
gotowania pliku nagłówkowego, którego biblioteki GLib. można przystąpić do implementacji nasze-
pełny kod zródłowy znajduje się na Listin- Wymienione makro sprawdzające, czy go widgetu. Plik zródłowy, umieszczony
gu 1. Chociaż nasz widget ma charakter dany obiekt jest typu GtkClock, posiada na płycie CD/DVD, który ją zawiera, nosi
edukacyjny, to przeglądając kod zródłowy następującą definicję: nazwę gtk_clock.c. Jest on zbyt duży, aby
www.lpmagazine.org 73
dla programistów
słowa class jako nazwy argumentu stosu-
Listing 1. Plik nagłówkowy widgetu GtkClock
je się słowo klass. W ten sposób kod może
być kompilowany za pomocą kompilatora
#ifndef __GTK_CLOCK_H__ języka C++.
#define __GTK_CLOCK_H__ Druga funkcja jest jeszcze krótsza:
#include
G_BEGIN_DECLS static void gtk_clock_init
#define GTK_TYPE_CLOCK (gtk_clock_get_type ()) (GtkClock *clock) {
#define GTK_CLOCK(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), clock->clock_update_handle=g_
GTK_TYPE_CLOCK, GtkClock)) timeout_add( 1000, clock_
#define GTK_CLOCK_CLASS(obj) (G_TYPE_CHECK_CLASS_CAST ((obj), update, clock);
GTK_CLOCK, GtkClockClass)) }
#define GTK_IS_CLOCK(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj),
GTK_TYPE_CLOCK)) Wykonujemy tylko jedną czynność, a mia-
#define GTK_IS_CLOCK_CLASS(obj) (G_TYPE_CHECK_CLASS_TYPE ((obj), nowicie tworzymy nowy obiekt timer, a uch-
GTK_TYPE_CLOCK)) wyt do tego obiektu zapamiętujemy w po-
#define GTK_CLOCK_GET_CLASS (G_TYPE_INSTANCE_GET_CLASS ((obj), lu clock_update_handle. Zakładamy, iż fun-
GTK_TYPE_CLOCK, GtkClockClass)) kcja, która będzie zajmować się uaktual-
typedef struct _GtkClock GtkClock; nieniem zegara (clock_update), będzie wy-
typedef struct _GtkClockClass GtkClockClass; woływana co sekundę. Jej treść znajduje
struct _GtkClock{ się na Listingu 2.
GtkDrawingArea parent; Głównym zadaniem funkcji clock_up-
/* < private > */ date jest odczytanie aktualnego czasu przy
guint clock_update_handle; wykorzystaniu funkcji time oraz localti-
int h,m,s; me. Uzyskane informacje przepisujemy do
}; pól h, m, s obiektu clock. Pozostaje już tylko
struct _GtkClockClass{ wywołać funkcję gtk_widget_queue_draw,
GtkDrawingAreaClass parent_class; której zadaniem jest ponowne narysowania
}; widgetu, czyli wywołanie funkcji przypisa-
GtkWidget *gtk_clock_new (void); nej do zdarzenia expose.
G_END_DECLS
#endif /* __GTK_CLOCK_H__ */ Danie główne  rysowanie
zegara
go zaprezentować w całości, więc przeana- oraz gtk_clock_init. Pierwsza dokonuje Za proces rysowania naszej kontrolki odpo-
lizujemy tylko wybrane fragmenty. inicjalizacji klasy, a druga obiektu. wiedzialne są trzy funkcje. Pierwsza, która
Na początku po włączeniu niezbęd- Treść pierwszej jest następująca: jest wywoływana przez system GTK+, to
nych plików nagłówkowych time.h, math.h gtk_clock_expose. Oczywiście, aby kod
i gtk.h dołączamy nasz plik nagłówkowy static void gtk_clock_class_init naszego widgetu był bardziej przejrzy-
gtk_clock.h. Następnie, zanim przystąpi- (GtkClockClass *class) { sty, sam zegar jest rysowany przez funk-
my do implementacji, pojawia się bardzo GtkWidgetClass *widget_class; cję draw_clock. Korzystamy także z jesz-
ważna linia, w której wykorzystujemy widget_class = GTK_WIDGET_ cze jednej funkcji o nazwie my_draw_text.
makro G_DEFINE_TYPE: CLASS (class); Zgodnie ze swoją nazwą, funkcja ta  rysuje
widget_class->expose_event = tekst, co jest dość dobrym określeniem dla
G_DEFINE_TYPE gtk_clock_expose;
(GtkClock, gtk_clock, }
GTK_TYPE_DRAWING_AREA);
Pierwsza linia kodu tej funkcji to deklara-
W ten sposób tworzymy podstawowy cja zmiennej pomocniczej widget_class.
szkielet obiektu GtkClock. Jest w nim m.in. Druga linia dokonuje konwersji klasy
funkcja o nazwie gtk_clock_get_type, GtkClockClass na klasę GtkWidgetClass, a
o której była mowa w poprzednim punk- następnie do funkcji expose_event podłą-
cie, więc nie musimy jej samodzielnie czana jest funkcja, której zadaniem będzie
implementować  dokona tego za nas ma- rysowanie naszego zegara. Więcej czynno-
kro G_DEFINE_TYPE. ści nie musimy wykonywać. Warto jesz-
Najwięcej miejsca w implementacji cze zwrócić uwagę na argument funkcji
widgetu zegara poświęcamy samemu pro- gtk_clock_class_init. Możemy bezkarnie
cesowi rysowania tego zegara, ale ważne użyć słowa class, ponieważ plik gtk_clock.c
są wszystkie czynności, a szczególnie będzie kompilowany za pomocą kompila-
Rysunek 2. Widget GtkClock
funkcje o nazwach gtk_clock_class_init tora języka C. Dość często w GTK+ zamiast
74 kwiecień 2006
dla programistów
GTK+/Cairo
Godzinami głównymi (dłuższa kreska)
Listing 2. Uaktualnienie czasu w kontrolce GtkClock
będą godziny podzielne przez trzy: 12, 9,
6 oraz 3. Ustalenie długości odbywa się za
gboolean clock_update(gpointer data) { pomocą instrukcji warunkowej w liniach
time_t t; 18-27  zostaje ona zapamiętana w zmien-
struct tm* td; nej tmp. Dodatkowo, gdy rysujemy krótsze
GtkClock* c=(GtkClock*)data; linie, dla pozostałych godzin pogrubiamy
time(&t); td=localtime(&t); nieco linię.
c->h=td->tm_hour; Po ustaleniu długości, czeka nas małe
c->m=td->tm_min; wyzwanie matematyczne. Za pomocą
c->s=td->tm_sec; wspomnianej powyżej pętli for generuje-
gtk_widget_queue_draw(GTK_WIDGET(c)); my 12 godzin, a dla każdej godziny pod
return TRUE; pewnym kątem musimy narysować na
} blacie naszego zegara kreskę o odpowied-
niej ustalonej już długości.
Proces ten zaczynamy od przesunię-
sposobu pracy biblioteki Cairo. go obszaru, po którym będziemy rysować. cia kursora graficznego za pomocą funk-
Przed właściwym rysowaniem kon- Niezbędne obliczenia są przeprowadzane cji cairo_move_to o odległość promienia
trolki, w funkcji obsługującej zdarzenie w 6 i 7 linii. Istotny problem to dopasowa- pomniejszoną o wartość tmp. W pewnym
expose, musimy utworzyć obiekt typu nie wielkość promienia (zmienna radius) sensie wykorzystujemy tu układ biegu-
cairo_t. Wykonujemy to w następujący do obszaru, który został przydzielony kon- nowy (taki, w którym nie posługujemy
sposób: trolce  tym zajmuje się linia 8. się wartościami przesunięcia wzdłuż osi
Po obliczeniach rysujemy dwa okręgi, X i Y, ale mówimy, że przesuwamy się
cairo_t *cr; wykorzystując funkcję cairo_arc. Pierwszy od początku układu o ustaloną długość
cr = gdk_cairo_create (clock->window); okrąg, rysowany w linii 10, to cyferblat pod pewnym kątem), bowiem od ustalo-
naszego zegara, natomiast mniejszy okrąg nego punktu x i y przesuwamy się o dłu-
Następnie rysujemy prostokąt na obsza- w linii 13 będzie reprezentować punkt, gość radius  tmp, ale pod kątem, który
rze, który został przydzielony kontrolce: w którym zostaną zaczepione wskazów- jest dany wzorem i * M_PI / 6, czyli o
ki. Po funkcji cairo_arc, jak widać, poja- wielokrotność 30 stopni. Gdy przesunie-
cairo_rectangle wia się wywołanie funkcji cairo_stroke, my kursor pod wyznaczone współrzędne,
(cr, event->area.x, która nakazuje wykonanie ostatnich pole- to funkcją cairo_line_to rysujemy linię
event->area.y, ceń rysunkowych. oznaczającą odpowiednią godzinę.
event->area.width, Po narysowaniu okręgów rysujemy Po narysowaniu wszystkich oznaczeń
event->area.height); ramkę wokół naszego zegar. Pętla for, godzin na cyferblacie naszego zegara, w
która rozpoczyna się w linii 18, a kończy linii 40 umieszczamy tekst z komunika-
Nakazujemy także wycinanie wszystkie- w linii 37, rysuje oznaczenia godzin. tem o producencie zegarka. Oczywiście,
go, co wychodzi poza obszar, po którym
będziemy rysować. W tym celu wystarczy
posłużyć się funkcją cairo_clip (cr);.
Ostatnim zadaniem jest uaktualnienie
czasu (przez funkcję, którą już omawiali-
śmy wcześniej) oraz narysowanie samego
zegara:
clock_update(clock);
draw_clock (clock, cr);
Po narysowaniu kontrolki możemy usunąć
obiekt Cairo, ponieważ wszystkie zmiany
zostały już umieszczone na ekranie  cairo_
destroy (cr);.
Rysujemy zegar
Doszliśmy do miejsca, w którym musimy
się zająć rysowaniem zegara, czyli funk-
cją o nazwie draw_clock. Listing 3 zawiera
wybrane fragmenty tej funkcji.
Na samym początku naszym zada-
Rysunek 2. Kontrolka GtkClock oraz program Glade
niem jest wyznaczenie punktu środkowe- aby nasz widget
www.lpmagazine.org 75
dla programistów
był zegarem, musimy narysować jesz-
Listing 3. Uaktualnienie czasu w kontrolce GtkClock
cze wskazówki. Na Listingu 3 w liniach
od 43 do 49 rysujemy wskazówkę odpo-
1: static void draw_clock (GtkWidget *clock, cairo_t *cr) { wiedzialną za godzinę. Technika ryso-
2: double x, y, radius, tmp; wania jest podobna jak przy oznacze-
3: niu godzin. Na początku przesuwamy
4: int i, _h, _m, _s; się do środka, a następnie rysujemy linię
5: o odpowiedniej długości, pod kątem,
6: x = clock->allocation.x + clock->allocation.width / 2; który wyznacza nam aktualna godzina.
7: y = clock->allocation.y + clock->allocation.height / 2; Jednak, aby godziny nam się zgadzały
8: radius = MIN (clock->allocation.width / z wartościami kątów, musimy od aktual-
2, clock->allocation.height / 2)  5; nej godziny odjąć wartość trzy. Podobnie
9: dla minut oraz sekund, gdzie odejmujemy
10: cairo_arc (cr, x, y, radius, 0, 2 * M_PI); wartość 15.
11: cairo_stroke (cr);
12: Testujemy nowy widget
13: cairo_arc (cr, x, y, 4, 0, 2 * M_PI); Nasz widget jest już gotowy do użycia,
14: cairo_stroke (cr); więc warto go przetestować w aplikacji.
15: Ponieważ kompilacja zródeł widgetu prze-
16: // rysowanie ramki zegara biega w sposób normalny, więc możemy
17: utworzyć bibliotekę statyczną, która bę-
18: for (i = 0; i < 12; i++) { dzie dołączana do naszego programu. Oczy-
19: cairo_save (cr); wiście, możemy też kompilować plik gtk_
20: clock.c samodzielnie we własnej aplikacji.
21: if (i % 3 == 0) { Utworzenie widgetu i dodanie go do
22: tmp = 0.2 * radius; własnej aplikacji jest typowe dla bibliote-
23: } ki GTK+. Na początek deklarujemy zmien-
24: else { ną:
25: tmp = 0.1 * radius;
26: cairo_set_line_width (cr, 0.5 * GtkWidget *clock;
cairo_get_line_width (cr));
27: } W programie tworzymy nowy obiekt:
28:
29: cairo_move_to (cr, clock = gtk_clock_new ();
30: x + (radius - tmp) * cos (i * M_PI / 6),
31: y + (radius - tmp) * sin (i * M_PI / 6)); Pozostaje tylko dodać nowo utworzony
32: cairo_line_to (cr, widget do innego kontenera np. do okna:
33: x + radius * cos (i * M_PI / 6),
34: y + radius * sin (i * M_PI / 6)); gtk_container_add
35: cairo_stroke (cr); (GTK_CONTAINER (win), clock);
36: cairo_restore (cr);
37: } W ten sposób dodajemy dowolny inny wid-
38: cairo_stroke (cr); get GTK+ do aplikacji, ale bardziej intere-
39: sujące jest wykorzystanie programu Glade.
40: my_draw_text(cr, x,y+25, "Made by YOU!"); Program ten nie pozwala na bezpośrednie
41: cairo_stroke (cr); dodanie widgetu GtkClock, ale jego autorzy
42: zostawili furtkę, którą można wykorzystać,
43: _h=GTK_CLOCK(clock)->h-3; aby dołączyć do aplikacji dowolny widget,
44: nieznany programowi Glade.
45: cairo_move_to (cr, x, y); Rysunek 2 prezentuje dołączenie do ok-
46: cairo_line_to (cr, na nowego nieznanego widgetu. W Glade
47: x + (radius * 0.4) * cos (_h * ((2*M_PI) / 12)), tego typu widget jest reprezentowany przez
48: y + (radius * 0.4) * sin (_h * ((2*M_PI) / 12))); kontrolkę o nazwie Custom. Sposób budowy
49: cairo_stroke (cr); tego typu kontrolki leży w gestii programi-
50: sty, bowiem, jak widać na wspomnianym
51: // rysowanie pozostałych wskazówek rysunku, najważniejsze to podanie nazwy
52: } (w naszym przypadku create_my_clock)
specjalnej funkcji, która jest odpowiedzialna
za utworzenie kontrolki. Funkcja ta zosta-
76 kwiecień 2006
dla programistów
GTK+/Cairo
o tym samemu. Pomimo tego, wiele przy-
datnych kontrolek, szczególnie o charakte-
rze graficznym  znakomitym przykładem
jest nasz zegar  są dość łatwe do napisa-
nia, więc zachęcam do tworzenia własnych
widgetów.
Warto to robić, ponieważ, oprócz samej
biblioteki GTK+, wybór dodatkowych wid-
getów jest niestety bardzo skromny. Jest to
tym bardziej uzasadnione, iż API GTK+ nie
podlega już wielkim zmianom, więc napisa-
Rysunek 3. G-Inspector w działaniu Rysunek 4. Szczegóły obiektu GtkHBox
ną kontrolkę łatwo będzie zaadaptować do
nie wygenerowana samoczynnie przez pro- return gtk_clock_new(); nowej wersji GTK+.
gram Glade po wybraniu przycisku Build. }
Domyślnie zawsze jest umieszczana w pliku
callbacks.c. Nic więcej nie musimy zmieniać w kodzie,
W Internecie:
Treść tej funkcji dla naszego zegara który został wygenerowany przez Glade.
jest bardzo krótka, ponieważ nasz widget Na płycie CD/DVD znajduje się gotowy
" Strona domowa projektu GTK+:
nie wymaga określania wartości począt- projekt utworzony w Glade (łączenie ze
http://www.gtk.org/
kowych. Wystarczy, iż za pomocą gtk_ skryptem configure), który polecam wypró-
" Program GObject Builder:
clock_new utworzymy widget: bować.
http://www.5z.com/jirka/gob.html
" Program do analizy obiektów
GtkWidget* create_my_clock Podsumowanie
GObject:
(gchar *widget_name, Tworzenie widgetów to mimo wszystko
http://sourceforge.net/projects/
gchar *string1, gchar *string2, dość trudne zadanie  wystarczy przejrzeć
g-inspector/
gint int1, gint int2) { kod zródłowy GTK+, aby przekonać się
R E K L A M A
www.lpmagazine.org 77


Wyszukiwarka

Podobne podstrony:
2006 04 Karty produktów
2006 04 Get the Spin
2006 04 Klucz do wlasnej firmy
2006 04 O diagnostyce i terapii bólów krzyża
2006 04 11 Uchwała ZG OSP system szkoleniaid 456
SIMR MAT1 EGZ 2006 04 20 rozw
2006 04 Stół rehabilitacyjny HIFLY
2006 04 O profilaktyce zdrowia pracowników
2006 04 Images of the Empire Msn Messenger in Linux with Webcam Support
2006 04 Trzy kolory TLK MED u
2006 04 Medycyna oparta na faktach
2006 04 GIMP w praktyce [Grafika]
2006 04 Elektrostymulacja funkcjonalna w chorobach dzieciecych
2006 04 Kryptografia w PHP [Kryptografia]
2006 04 191732 set! verbal

więcej podobnych podstron