ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/cvsroot/docs/pws2004/gtk2.pod
Revision: 1.6
Committed: Mon May 24 00:01:12 2004 UTC (22 years, 4 months ago) by root
Branch: MAIN
Changes since 1.5: +64 -10 lines
Log Message:
*** empty log message ***

File Contents

# User Rev Content
1 root 1.5 =encoding utf8
2    
3 root 1.1 =head1 Gtk+2 - ein erweiterbares GUI-Toolkit
4    
5     =head2 Abstract
6    
7 root 1.3 Gtk+2 (das {{G}}IMP {{T}}ool{{K}}it, Version 2) unterlief bei der
8     Entwicklung zu Version 2 tiefgreifende Änderungen. Das Typsystem wurde
9     stark abstrahiert, so daß Schnittstellen zu anderen Sprachen sich im
10     wesentlichen auf das Bereitstellen des Objektsystems beschränken.
11    
12     In diesem Dokument wird das Toolkit Gtk2 kurz vorgestellt, wobei Erfahrung
13     mit GUI-Programmierung vorausgesetzt wird. Im wesentlichen wird es jedoch
14     darum gehen, einige besondere Techniken vorzustellen sowie das Toolkit von
15     Perl aus selbst zu erweitern.
16 root 1.1
17 root 1.6 =head1 Gtk2 und Glib, eine Übersicht
18 root 1.1
19 root 1.3 =head2 Übersicht über die G-Module
20 root 1.1
21 root 1.3 Es gibt eine Menge Bibliotheken, deren Namen mit G anfängt und im
22     Dunstkreis von Gtk+ stehen. Vielleicht wäre es sinnvoll gewesen, eine neue
23     G-Hierarchie in Perl zu begründen, so muß man sich mit einer teilweise
24     nicht sehr logischen Namensgebung zurechtzufinden.
25    
26     =over 4
27    
28     =item Glib
29    
30     Glib ist die Schnittstelle zur C<libglib> (sowie zu C<libgobject>,
31     C<libgmodule> und C<libgthread>). Es bildet die Grundlage für das Objekt-
32     und Typ- und Signalsystem, bietet Hilfsfunktionen zum Umwandeln von
33     Dateinamen, Logging usf.
34    
35     Eine I<sehr> sauber geschriebene Bilbiothek, die auf GObject aufsetzt,
36     läßt sich praktisch ohne zusätzlichen Schnittstellencode nutzen: sobald
37     die entsprechenden Typen registriert wurden (geschieht meist in einer
38     Init-Funktion) kann man Objekte instantiieren und benutzen.
39    
40     =item Gtk2
41    
42     Dieses Modul ist eine Sammelstelle für diverse Bilbiotheken: neben
43     C<libgtk+> auch C<libgdk>, C<libgdk_pixbuf> und C<libpango>.
44    
45     Sie reicht für fast alle Anwendungen aus.
46    
47     =item Gtk2::GLExt, Gtk2::GladeXML, Gtk2::TrayIcon und Gtk2::Spell
48    
49     Bieten Integration von OpenGL, GladeXML, EggTryIcon und Spell-checking für
50     Text-Widgets.
51    
52     =item Gnome2
53    
54     Schnittstelle zur C<libgnome> und vielem mehr. Muss man nicht
55     benutzen, kann mir aber vorstellen, das sie für die Erstellung von
56     Gnome-Applikationen ganz nützlich sind :)
57    
58     =item Gnome2::Canvas, Gnome2::GConf, Gnome2::PanelApplet, Gnome2::Print,
59     Gnome2::Rsvg, Gnome2::VFS, Gnome2::Vte, Gnome2::Wnck.
60    
61 root 1.6 Jede Menge Gnome-Zeugs.
62 root 1.3
63     =back
64 root 1.1
65 root 1.6 =head2 Die Widgets von Gtk2 sind GObjects
66 root 1.1
67 root 1.3 Wie jedes andere Toolkit auch, bietet Gtk2 eine Menge vorgefertigter
68     I<Widgets>: I<Buttons>, I<Labels>, I<Frames> und andere "einfache"
69     Widgets, aber auch komplexe, wie das I<Text>- (komplett in Unicode,
70     einbettbare Objekte) oder das I<TreeView>- (Listen und Bäume im
71     MVC-Modell) Widget.
72    
73     =begin latex
74    
75     \begin{figure}[h]\includegraphics{gtk2-textwidget.png}\label{Das Text-Widget}\end{figure}
76    
77     =end latex
78    
79 root 1.6 Alle diese Widgets sind sogenannte I<GObjects> (davon abgeleitet sind
80     in Gtk2 dann sogenannte I<Widgets>, GUI-Objekte), und haben folgende
81     Features:
82 root 1.4
83     =over 4
84    
85     =item Eine Klasse
86    
87 root 1.6 Jedes GObject ist eine Instanz einer Klasse (C<GObjectClass>), eine
88     Datenstruktur, die Informationen über Methoden u.ä. speichert.
89    
90     Eine C<GObjectClass> ist allerdings nur ein Spezialfall eines
91     C<GType>s: Die Glib bildet ein komplettes Typsystem mit Klassen,
92     Aufzählungen, Flags, einfachen Datentypen wie Integer oder
93     Fließkommazahlen oder auch C-structs an. All dies ist zur Laufzeit in
94     einer Form verfügbar, in der sich auch neue - zur Compielzeit nicht
95     bekannte - Datentypen verwenden lassen.
96    
97     Schnittstellen für andere Sprachen werden dadurch einfach, da man
98     "lediglich" die Konzepte "Datentyp", "Konverter", "Klasse", "Methode",
99     "Bitset" usw. umsetzen muß. Konkrete Instanzen dieser Typen funktionieren
100     zur Laufzeit automatisch.
101    
102     Bei einer gut geschriebenen C-Bibliothek, die auf Glib bzw. GObject
103     aufsetzt, muß man eigetnlich nur die Initialisierungsfunktion aufrufen,
104     die die Datentypen registriert, und kann dann sofort von Perl darauf
105     zugreifen - ohne eine einzige XS-Funktion geschrieben zu haben.
106 root 1.4
107     =item Methoden
108    
109     Jedes GObjekt hat mindestens Methoden zum Erzeugen (C<constructor>)
110 root 1.6 und Zerstören (C<finalize>), Setzen und Lesen von Properties und eine
111 root 1.4 Spezialität von GObject - C<dispose>. Letzteres ist eine Art Anfrage an
112     ein Objekt, sich freiwillig aufzulösen.
113    
114 root 1.6 Gtk2 fügt noch einige weitere hinzu, wie die C<destroy>-Methode, die aktiv
115     versucht, ein Objekt zu zerstören: In GUI-Programmen ist es manchmal
116     schwer, alle Referenzen im richtigen Moment aufzulösen, da sie häufig
117     zirkulär sind. Manche Objekte "leben" auch ganz eigenständig, z.B. wird
118     ein Toplevel-Fenster im allgemeinen vom Benutzer "referenziert", was sich
119     aber nicht notwendigerweise im Referenz-Zähler niederschlägt.
120    
121     Um solche Objekte loszuwerden, kann man sie bitten, sich zu
122     I<destroyen>. Dabei gibt es alle Referenzen auf andere Objekte frei und
123     bittet diese, sich ebenfalls zu destroyen. Dadurch werden zirkuläre
124     Referenzen effektiv aufgebrochen.
125    
126     Methoden kann man in Perl nicht direkt implementieren, da
127    
128 root 1.4 =item Signale
129    
130 root 1.6 Signale ähneln Methoden, Callbacks oder sogenannten "Delegates". Wie
131     Methoden sind sie fest an eine Klasse gebunden und rufen (in C) eine
132     Methode der Klasse auf, sobald sie ausgelöst werden.
133    
134     Ein Signal kann von jedem ausgelöst werden, insbesondere lösen aber
135     Ereignisse (Events) in Gtk2 Signale aus. Der Signal-Handler eines Objektes
136     verarbeitet das Ereignis (und beendet die Signalauslieferung) oder tut
137     nichts, woraufhin Gtk2 ein anderes Objekt als Empfänger sucht.
138    
139     Zusätzlich kann man vor oder nach dem eigentlichen Signal-Handler
140     des Objektes weitere Callbacks einklinken. Z.B. löst das Text-Widget
141     beim Mausklick rechts ein C<populate-menu>-Signal aus, das
142     normalerweise ein Popup-Menü generiert. Das kann man verändern oder
143     ganz überschreiben. Und wenn man Mausklicks abfangen möchte, kann man
144     das C<button-press-event>-Signal überschreiben und so Mausklicks vom
145     Text-Widget fernhalten.
146    
147 root 1.4 =item Properties (Eigenschaften)
148    
149 root 1.6 Properties sind von der jeweiligen Klasse definierte Eigenschaften, die
150     das Objektverhalten beeinflussen.
151    
152     =item Schlüssel-Wert-Paare
153    
154 root 1.4 =back
155 root 1.3
156 root 1.6 =head2 Informationen über Klassen zur Laufzeit abfragen
157 root 1.1
158 root 1.4 =head2 Leben und sterben lassen: Wie man seine Objekte wieder loskriegt
159    
160 root 1.6 =head3 Die einfache Methode
161 root 1.1
162 root 1.4 =head2 Beispiel: Session-Management
163 root 1.1
164 root 1.4 =head2 Beispiel: Glade
165 root 1.1
166     =head1 Teil 2 - Gtk+ als solide Grundlage für Eigenentwicklungen
167    
168     =head2 Perl-Objekte vs. Glib-Objekte
169 root 1.3
170     =head2 Objekte aus anderen Sprachen nutzen
171 root 1.1
172     mit einem objektorientiertem Design. Gtk+ selbst ist in C geschrieben,
173     es existieren jedoch Bindings für C++, Perl, Python und einige andere
174     Sprachen. Das Perl-Interface ist noch nicht vollkommen ausgereift,
175     ist aber schon hervorragend benutzbar und wird immer mehr eingesetzt
176     (z.B. für Administrationsfrontends in Debian GNU/Linux). Die Vorteile
177     von Gtk+ gegenüber Tk und anderen Toolkits ist die hervorragende
178     Integration{{}}: Perl-Widgets können von anderen Sprachen benutzt werden (z.B.
179     von C) und natürlich umgekehrt. Eigene Widgets können sehr einfach erzeugt
180     werden (im Gegensatz zu Tk), und die Gtk+-Bibliothek ist frei (im Sinne
181     der LGPL) -- auch auf anderen Betriebssystemen als UNIX.
182    
183     H1: Gtk
184    
185     C<Gtk> ist das Perl-Modul, das die Schnittstelle zur Gtk+-Bibliothek
186     bildet. Da die meisten Menschen "Gtk" sagen, wenn sie Gtk+ meinen, wird
187     die Perl-Schnittstelle meistens explizit "Gtk-Perl" genannt (genauso, wie
188     das Gimp-Modul meistens Gimp-Perl genannt wird).
189    
190     Zur Zeit bietet das Gtk-Modul auch Bindungen für Gnome und einige
191     andere Bibliotheken an, möglicherweise (das ist nicht sicher) werden
192     diese Module aber aufgetrennt werden: Gtk+ war ursprünglich das
193     {{G}}imp-{{T}}ool{{K}}it, und sowohl Gtk+ als auch Gimp sind {{kein}} Teil
194     des Gnome-Projektes und können deshalb ohne Gnome verwendet werden.
195    
196     H2: Ein einfaches Programm
197    
198     Hier ist ein ganz einfaches Gtk-Programm. Nichtsdestotrotz öffnet es schon ein Fenster:
199    
200     !block perl
201     use Gtk;
202    
203     Gtk->init;
204    
205     $main = new Gtk::Window;
206    
207     $main->show;
208     Gtk->main;
209     !endblock
210    
211     C<use Gtk;> sollte klar sein. Eine Eigenheit von Gtk+ ist es, daß es
212     zuerst explizit initialisiert werden muß (in einem Gnome-Programm würde
213     statt {{C:Gtk->init}} ein {{C:Gnome->init}} stehen), sonst gibt es jede Menge
214     Fehler.
215    
216     Der Aufruf C<new Gtk::Window> ist {{ein}} Weg, ein neues Fenster zu
217     erzeugen. Neue Gtk-{{Widgets}} sind Anfangs aber noch unsichtbar. Damit
218     sie angezeigt werden, muß zuerst die C<show>-Methode aufgerufen werden (es
219     gibt auch das entsprechende C<hide>).
220    
221     Das letzte, was unser Programm macht, ist, in die Hauptschleife von Gtk+
222     zu springen. Die Hauptschleife zeigt das Fenster und und -- wartet auf
223     Ereignisse{{}}:
224    
225     !import "hello1"; title="Das erste Fenster"
226    
227     Das Fenster ist natürlich leer und es wurden auch keine Reaktionen auf
228     Ereignisse. Die einzige Möglichkeit, das Programm zu beenden, ist es, es
229     zu "killen" (entweder C<xkill> oder z.B. C<SIGINT>).
230    
231     H2: Das Signalsystem von Gtk+
232    
233     Gtk+ setzt intern auf einer Bibliothek namens C<Gdk> (GNU Drawing ToolKit) auf, die
234     eine Schnittstelle auf niedriger Ebene zum jeweiligen Fenstersystem (X, Win32, BeOS...)
235     bildet. Diese Schnittstelle erzeugt Ereignisobjekte und reicht sie an Gtk+ weiter.
236    
237     Gtk+ verteilt diese Ereignisse an seine Widgets, indem es diesen Signale
238     schickt. Ein Signal ist z.B. eine Mausklick (C<clicked>) oder das
239     anklicken des "Fenster-Schließen"-Knopfes (C<delete_event>). Gtk+ kennt
240     aber auch eigene Signal, z.B. wenn ein Objekt zerstört wird (C<destroy>),
241     was einem Destruktor entspricht.
242    
243     Jeder Signal-Handler kann das Signal konsumieren, an andere Widgets
244     weiterreichen oder einfach ignorieren (wodurch es z.B. an das Vaterwidget
245     gelangt).
246    
247     Um eine Aktion an ein Signal zu binden, kann man die C<signal_connect>-Methode aufrufen:
248    
249     !block perl
250     $main = new Gtk::Window;
251    
252     $main->signal_connect(delete_event => sub { Gtk->main_quit });
253     !endblock
254    
255     Nun kann man den Schließknopf des Fensters betätigen, und das ausgelöste
256     Signal (C<delete_event>) führt zu einem Aufruf von {{C:Gtk->main_quit}}. Das
257     Beendet die Hauptschleife und damit das Programm.
258    
259     H2: Der erste Button
260    
261     Nun zu etwas mehr Aktion. Ein "Hello-World!"-Button muß her. Dies ist ganz einfach:
262    
263     !block perl
264     $button = new Gtk::Button "Hello, World!";
265     $main->add($button);
266    
267     $button->show;
268     !endblock
269    
270     Das einzig neue (neben der Erkenntnis, daß es auch C<Gtk::Button>s
271     gibt), ist der Aufruf von C<$main->add>. C<Gtk::Window> {{ist ein}}
272     C<Gtk::Container>, und erbt von diesem einige Methoden (unter anderem
273     C<add>).
274    
275     Das Fenster sieht nun so aus (nicht schön, aber es wird):
276    
277     !import "hello2"; title="Das Fenster -- mit Button!"
278    
279     Nun besetzen wir noch das C<clicked>-Ereignis mit einem überflüssigen Signal-Handler:
280    
281     !block perl
282     $button->signal_connect(clicked => sub { print "I was here!\n" });
283     !endblock
284    
285     H2: Vereinfachungen
286    
287     Das ganze Programm kann man (wenn man will) noch etwas einfacher
288     haben. Zuersteinmal: mir geht dieses dauernde {{C:$xxx->show}} auf
289     die Nerven. Weil es anderen wohl auch so ging, gibt es die Methode
290     C<show_all>. Sie ruft C<show> für das Widget und, rekursiv, für alle seine
291     Kinder auf. Man kann also alle (naja, zwei) C<show>-Aufrufe durch ein
292     einzelnes {{C:$main->show_all}} ersetzen.
293    
294     Die zweite Vereinfachung ist eher Geschmackssache: Man kann die Erzeugung
295     des Widgets und alle Initialisierungen (z.B. Signale) in einem Aufruf
296     erledigen:
297    
298     !block perl
299     use Gtk;
300    
301     init Gtk;
302    
303     $main = new Gtk::Widget "Gtk::Window",
304     -signal::delete_event => sub { Gtk->main_quit };
305    
306     add $main (new Gtk::Widget "Gtk::Button",
307     -label => "Hello, World!",
308     -signal::clicked => sub { print "I was here!\n" });
309    
310     $main->show_all;
311    
312     Gtk->main;
313     !endblock
314    
315     H2: Verschönerungen
316    
317     Um noch ein paar Features vorzustellen sollen noch ein paar Knöpfe
318     hinzukommen. Der "Hello-World"-Knopf soll in einen Rahmen. Unter den
319     Rahmen sollen zwei Knöpfe: der erste soll den Text an- und abschalten, der
320     zweite soll das Programm beenden:
321    
322     !import "hello-layout"; title="Schematisches Layout"
323     !import "hello31"; title="Das Programm beim Start"
324     !import "hello32"; title="Nach dem abschalten der Nachricht"
325    
326     Die Technik, Widgets an- und abzuschalten wird gerne für Dialoge in
327     der Art "Advanced Options >>" verwendet, um dem Benutzer mehr Optionen
328     anzubieten.
329    
330     Gtk+ bietet viele Arten von Layout-Managern. Grundsätzlich möchte es
331     aber das Layouten des Fensters gerne selbst übernehmen. Man {{kann}}
332     die Größe und Lage von Widgets selbst bestimmen, aber Gtk+ arbeitet
333     wesentlich besser, wenn man nur Hinweise gibt. Ein solcher Hinweis kann
334     in Form der C<Gtk::VBox> und C<Gtk::HBox>-Container geschehen. Diese
335     sind Rechtecke, die mehrere Widgets enthalten können, die vertikal oder
336     horizontal ausgerichtet werden.
337    
338     Das Hauptelement des Fensters soll also eine C<Gtk::VBox> werden. Oben
339     soll eine C<Gtk::Frame> stehen, und im unteren Teil soll eine C<Gtk::HBox>
340     mit den "Bedienelementen" sein (Eine C<Gtk::Box> kann durchaus auch mehr
341     als zwei Widgets enthalten). Die VBox wird einfach erzeugt mit:
342    
343     !block perl
344     add $main (my $vbox = new Gtk::Widget "Gtk::VBox",
345     homogeneous => 0,
346     spacing => 5,
347     border_width => 5);
348     !endblock
349    
350     Eine C<Gtk::Box> ist C<homogeneous>, wenn alle Widgets die gleiche Größe
351     haben. Unsere VBox soll das {{nicht}} sein, die C<Gtk::HBox> dagegen
352     schon. Dann wird eine C<Gtk::Frame> erzeugt, in die das C<Gtk::Label> mit
353     dem "Hello, World!" gepackt wird (der Layoutvorgang wird auch "packen"
354     genannt, da die Widgets dabei in den verfügbaren Raum "eingepackt
355     werden").
356    
357     !block perl
358     # Message-Frame:
359     add $vbox (my $frame = new Gtk::Frame "A Message:");
360    
361     # Message-Label:
362     add $frame (my $label = new Gtk::Label "Hello, World!");
363     !endblock
364    
365     Die horizontale Box für die Knöpfe wird mit einem vereinfachten
366     Konstruktor (statt dem allgemeinen {{C:Gtk::Widget->new}}) erzeugt, der
367     nur zwei Argumente ("homogen" und "Abstand") akzeptiert.
368    
369     !block perl
370     add $vbox (my $hbox = new Gtk::HBox 1,5);
371     !endblock
372    
373     Das Interessanteste an dem Programm ist zweifellos der Umschaltknopf,
374     der die Nachricht an- und abschaltet. Dazu bedienen wir uns eines
375     C<Gtk::ToggleButton>s, der zwei Zustände (aktiv und inaktiv) besitzt:
376    
377     !block perl
378     add $hbox (new Gtk::Widget "Gtk::ToggleButton",
379     label => "Message Shown",
380     active => 1,
381     signal::clicked => sub {
382     $label->visible
383     ? $label->hide
384     : $label->show;
385     });
386     !endblock
387    
388     Hier ist das gesamte Programm:
389    
390     !block perl
391     use Gtk;
392    
393     init Gtk;
394    
395     $main = new Gtk::Widget "Gtk::Window",
396     -signal::delete_event => sub { Gtk->main_quit };
397    
398     add $main (my $vbox = new Gtk::Widget "Gtk::VBox",
399     homogeneous => 0,
400     spacing => 5,
401     border_width => 5);
402    
403     # Message-Frame:
404     add $vbox (my $frame = new Gtk::Frame "A Message:");
405    
406     # Message-Label:
407     add $frame (my $label = new Gtk::Label "Hello, World!");
408    
409     # Button-Bar
410     add $vbox (my $hbox = new Gtk::HBox 1,5);
411    
412     # Toggle-Button
413     add $hbox (new Gtk::Widget "Gtk::ToggleButton",
414     label => "Message Shown",
415     active => 1,
416     signal::clicked => sub {
417     $label->visible
418     ? $label->hide
419     : $label->show;
420     });
421    
422     # Close Button
423     add $hbox (new Gtk::Widget "Gtk::Button",
424     label => "OK",
425     signal::clicked => sub { main_quit Gtk });
426    
427     $main->show_all;
428    
429     Gtk->main;
430     !endblock
431    
432     H1: Eine Widget-Demo
433    
434     Als Abschluß folgt noch ein Screenshot, bei dem ich mich bemüht habe,
435     die wichtigsten (schon verfügbaren) Widgets alle auf einen Bildschirm
436     zu bekommen (das Gtk-Perl-Demoprogramm, C<Gtk/samples/test.pl> war sehr
437     hilfreich ;)
438    
439     Natürlich kann man jederzeit auch eigene Widgets programmieren...
440    
441     !import "screenshot"; title="Der mega-unübersichtliche Screenshot"
442    
443    
444    
445    
446