ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/cvsroot/docs/pws2004/gtk2.pod
Revision: 1.4
Committed: Sun Apr 25 02:56:31 2004 UTC (22 years, 5 months ago) by root
Branch: MAIN
Changes since 1.3: +28 -5 lines
Log Message:
*** empty log message ***

File Contents

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