ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/cvsroot/docs/pws2004/gtk2.pod
Revision: 1.16
Committed: Fri May 28 20:46:38 2004 UTC (22 years, 4 months ago) by root
Branch: MAIN
Changes since 1.15: +2 -2 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.11 Gtk+2 (das B<G>IMP B<T>oolB<K>it, Version 2) unterlief bei der
6 root 1.3 Entwicklung zu Version 2 tiefgreifende Änderungen. Das Typsystem wurde
7 root 1.9 stark abstrahiert, so daß sich Schnittstellen zu anderen Sprachen im
8 root 1.3 wesentlichen auf das Bereitstellen des Objektsystems beschränken.
9    
10 root 1.9 In diesem Dokument wird das Toolkit gtk+2 kurz vorgestellt, wobei
11     Erfahrung mit GUI-Programmierung vorausgesetzt wird. Im Wesentlichen geht
12     es darum, einige besondere Techniken vorzustellen sowie das Toolkit von
13     Perl und C aus selbst zu erweitern.
14 root 1.1
15 root 1.6 =head1 Gtk2 und Glib, eine Übersicht
16 root 1.1
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     =item Gtk2
34    
35 root 1.11 Dieses Modul ist eine Sammelstelle für diverse Bibliotheken: neben
36 root 1.3 C<libgtk+> auch C<libgdk>, C<libgdk_pixbuf> und C<libpango>.
37    
38     Sie reicht für fast alle Anwendungen aus.
39    
40     =item Gtk2::GLExt, Gtk2::GladeXML, Gtk2::TrayIcon und Gtk2::Spell
41    
42 root 1.15 Bieten Integration von OpenGL, GladeXML, EggTrayIcon und Spell-checking für
43 root 1.3 Text-Widgets.
44    
45     =item Gnome2
46    
47 root 1.11 Schnittstelle zur C<libgnome> und vielem mehr.
48    
49     ... muß man nicht benutzen, kann mir aber vorstellen, daß sie für die
50     Erstellung von Gnome-Applikationen ganz nützlich sind :)
51 root 1.3
52     =item Gnome2::Canvas, Gnome2::GConf, Gnome2::PanelApplet, Gnome2::Print,
53     Gnome2::Rsvg, Gnome2::VFS, Gnome2::Vte, Gnome2::Wnck.
54    
55 root 1.6 Jede Menge Gnome-Zeugs.
56 root 1.3
57     =back
58 root 1.1
59 root 1.6 =head2 Die Widgets von Gtk2 sind GObjects
60 root 1.1
61 root 1.3 Wie jedes andere Toolkit auch, bietet Gtk2 eine Menge vorgefertigter
62 root 1.11 I<Widgets>: I<Buttons>, I<Labels>, I<Frames> und andere C<">einfacheC<">
63 root 1.3 Widgets, aber auch komplexe, wie das I<Text>- (komplett in Unicode,
64     einbettbare Objekte) oder das I<TreeView>- (Listen und Bäume im
65     MVC-Modell) Widget.
66    
67 root 1.11 =for html
68     <img src="gtk2-textwidget.png" />
69 root 1.3
70 root 1.11 =for comment
71     Scheisslatex ignoriert natürlich alle Daten wie Auflösung.. grr...
72 root 1.3
73 root 1.11 =for latex
74     \begin{center}\includegraphics[scale=0.4]{gtk2-textwidget.png}\end{center}
75 root 1.3
76 root 1.6 Alle diese Widgets sind sogenannte I<GObjects> (davon abgeleitet sind
77     in Gtk2 dann sogenannte I<Widgets>, GUI-Objekte), und haben folgende
78     Features:
79 root 1.4
80     =over 4
81    
82     =item Eine Klasse
83    
84 root 1.6 Jedes GObject ist eine Instanz einer Klasse (C<GObjectClass>), eine
85     Datenstruktur, die Informationen über Methoden u.ä. speichert.
86    
87     Eine C<GObjectClass> ist allerdings nur ein Spezialfall eines
88     C<GType>s: Die Glib bildet ein komplettes Typsystem mit Klassen,
89     Aufzählungen, Flags, einfachen Datentypen wie Integer oder
90     Fließkommazahlen oder auch C-structs an. All dies ist zur Laufzeit in
91 root 1.11 einer Form verfügbar, in der sich auch neue - zur Compilezeit nicht
92 root 1.6 bekannte - Datentypen verwenden lassen.
93    
94     Schnittstellen für andere Sprachen werden dadurch einfach, da man
95 root 1.11 C<">lediglichC<"> die Konzepte C<">DatentypC<">, C<">KonverterC<">, C<">KlasseC<">, C<">MethodeC<">,
96     C<">BitsetC<"> usw. umsetzen muß. Konkrete Instanzen dieser Typen funktionieren
97 root 1.6 zur Laufzeit automatisch.
98    
99     Bei einer gut geschriebenen C-Bibliothek, die auf Glib bzw. GObject
100 root 1.10 aufsetzt, muß man eigentlich nur die Initialisierungsfunktion aufrufen,
101 root 1.6 die die Datentypen registriert, und kann dann sofort von Perl darauf
102     zugreifen - ohne eine einzige XS-Funktion geschrieben zu haben.
103 root 1.4
104     =item Methoden
105    
106     Jedes GObjekt hat mindestens Methoden zum Erzeugen (C<constructor>)
107 root 1.6 und Zerstören (C<finalize>), Setzen und Lesen von Properties und eine
108 root 1.4 Spezialität von GObject - C<dispose>. Letzteres ist eine Art Anfrage an
109     ein Objekt, sich freiwillig aufzulösen.
110    
111 root 1.6 Gtk2 fügt noch einige weitere hinzu, wie die C<destroy>-Methode, die aktiv
112     versucht, ein Objekt zu zerstören: In GUI-Programmen ist es manchmal
113     schwer, alle Referenzen im richtigen Moment aufzulösen, da sie häufig
114 root 1.11 zirkulär sind. Manche Objekte C<">lebenC<"> auch ganz eigenständig, z.B. wird
115     ein Toplevel-Fenster im allgemeinen vom Benutzer C<">referenziertC<">, was sich
116 root 1.6 aber nicht notwendigerweise im Referenz-Zähler niederschlägt.
117    
118     Um solche Objekte loszuwerden, kann man sie bitten, sich zu
119     I<destroyen>. Dabei gibt es alle Referenzen auf andere Objekte frei und
120     bittet diese, sich ebenfalls zu destroyen. Dadurch werden zirkuläre
121     Referenzen effektiv aufgebrochen.
122    
123 root 1.7 Methoden kann man in Perl nicht direkt implementieren, dafür aber eigene
124     Signale, die beliebige Parameter oder Rückgabewerte besitzen können und
125     mehr oder weniger direkt von C oder anderen Sprachen aus aufgerufen werden
126     können.
127 root 1.6
128 root 1.4 =item Signale
129    
130 root 1.11 Signale ähneln Methoden, Callbacks oder sogenannten C<">DelegatesC<">. Wie
131 root 1.6 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 root 1.11 Sie werden von der Klasse festgelegt und auch von ihr benutzt.
153 root 1.7
154 root 1.6 =item Schlüssel-Wert-Paare
155    
156 root 1.11 Damit andere Benutzer mit einem Objekt Daten verknüpfen können, kann man
157     an ein GObject noch beliebige Schlüssel-Wert-Paare (sogar mit Destruktor)
158     packen, wobei sich dies von Perl aus auf Integer beschränkt, da das
159     Glib-Modul jedes GObject automatisch mit einem Perl-Hash verknüpft und
160     diesen auf Perl-Ebene zur Speicherung zur Verfügung stellt.
161 root 1.7
162 root 1.4 =back
163 root 1.3
164 root 1.9 =head2 Informationen über Typen und Klassen zur Laufzeit abfragen
165    
166     Die Typinformationen, wie Werte von Aufzählungen, Namen von Datentypen,
167     Objekt-Signale, -Properties uvm., sind alle zur Laufzeit abfragbar.
168    
169     Dadurch wird das Schreiben von Klassenbrowsern oder RAD-Tools serh
170     einfach. Aber auch beim Entwickeln von Programmen ist das nützlich, da man nicht immer
171     die Dokumentation zu Rate ziehen muss.
172    
173     Z.B. liefert C<< $obj->list_properties >> (oder
174     C<Glib::Type::list_properties> Klassenname) eine Liste von Arrayrefs mit
175     Name, Typ, Flags und Beschreibung zurück, die man sich z.B. mit folgender
176     Funktion ausgeben lassen kann:
177    
178     use Gtk2;
179    
180     sub gobj_props {
181     for ($_[0]->list_properties) {
182 root 1.11 printf "%-16s %-24s %-24s %s\n", $_->{name}, $_->{type},
183     (join ":", @{$_->{flags}}), $_->{descr};
184 root 1.9 }
185     }
186    
187     Der Aufruf C<gobj_props "Gtk2::Widget"> (oder mit einem
188     C<Gtk2::Window>-Object als Argument) liefert folgende Properties, die alle
189     Gtk2-Widgets besitzen:
190    
191     user-data gpointer readable:writable
192     Anonymous User Data Pointer
193     name Glib::String readable:writable
194     The name of the widget
195     parent Gtk2::Container readable:writable
196     The parent widget of this widget. Must be a Container widget
197     width-request Glib::Int readable:writable
198 root 1.11 Override for width request of the widget,
199     or -1 if natural request should be used
200 root 1.9 ...
201     extension-events Gtk2::Gdk::ExtensionMode readable:writable
202     The mask that decides what kind of extension events this widget gets
203     no-show-all Glib::Boolean readable:writable
204     Whether gtk_widget_show_all() should not affect this widget
205    
206     Signale lassen sich ebenso abfragen:
207    
208     sub gobj_signals($) {
209     # Signale haben Argumente und Parameter, daher Dumpvalue
210     use Dumpvalue;
211     Dumpvalue->new (bareStringify => 0)->dumpValue ($_)
212     for Glib::Type->list_signals ($_[0]);
213     }
214    
215     gobj_signals "Gtk2::Widget";
216    
217     ...
218     'signal_id' => 23
219     'signal_name' => 'button-press-event'
220     'itype' => 'Gtk2::Widget'
221     'param_types' => ARRAY(0x83b4f28)
222     0 'Gtk2::Gdk::Event'
223     'return_type' => 'Glib::Boolean'
224     'signal_flags' => [ run-last ]
225     -> 2
226     ...
227    
228     Das C<button-press-event>-Signal möchte also ein Event als einziges
229     Argument und liefert einen Wahrheitswert.
230    
231     Die Abstammung von C<Gtk2::Window> ist schnell gefunden:
232    
233     warn join " ", Glib::Type->list_ancestors ("Gtk2::Window");
234     Gtk2::Window Gtk2::Bin Gtk2::Container Gtk2::Widget
235     Gtk2::Object Glib::Object at gtk.pl line xx.
236    
237     # und list_interfaces wollte ich auch erwähnen:
238     warn join " ", Glib::Type->list_interfaces ("Gtk2::Window");
239     Gtk2::Atk::ImplementorIface at gtk.pl line xx.
240    
241     Wenn man gtk+ von C her kennt (oder eben die C-Dokumentation benutzt),
242     kann man aus dem C-Typnamen den Namen in Perl erfahren:
243    
244     warn Glib::Type->package_from_cname ("GtkWindowPosition");
245     Gtk2::WindowPosition at gtk.pl line xx.
246    
247     warn Glib::Type->package_from_cname ("GdkPixbuf");
248     Gtk2::Gdk::Pixbuf at gtk.pl line xx.
249    
250     Aufzählungen und Flags kann man ebenso hinterfragen:
251    
252     sub g_vals($) {
253     for (Glib::Type->list_values ($_[0])) {
254     printf "%-30s %s\n", $_->{name}, $_->{nick};
255     }
256     }
257    
258     g_vals "Gtk2::Gdk::EventMask";
259    
260     GDK_EXPOSURE_MASK exposure-mask
261     GDK_POINTER_MOTION_MASK pointer-motion-mask
262     ...
263     GDK_SCROLL_MASK scroll-mask
264     GDK_ALL_EVENTS_MASK all-events-mask
265    
266     =head3 Aufzählungen und Flags
267    
268     Natürlich kann man zur Laufzeit auch eigene Typen hinzufügen. Z.B. ein
269     neuer Flag-Typ:
270    
271     Glib::Type->register_flags (Meine::Flags =>
272     'eins', # implizit 1<<0
273     'zwei', # implizit 1<<1
274     ['drei' => 15 ], # explizit 15
275     ['vier' => 35 ], # explizit 35
276     'fuenf', # implizit 1<<4
277     );
278    
279     Diese neuen Typen sind gleichwertig zu den vorhandenen, können also von C
280     oder anderen Programmiersprachen aus benutzt werden.
281    
282     Aufzählungen und Flags sind in Perl überladen. Das ist besonders hilfreich
283     in Event-Handlern:
284    
285     $widget->signal_connect (button_press_event => sub {
286     if ($_[1]->type eq "button-press") {
287     if ($_[1]->button == 1) {
288     if ($_[1]->state == "shift-mask") {
289     # Umschalt-Klick
290     if ($_[1]->state * "shift-mask") { # oder '&'
291     # Umschalt-Klick (eventuell plus anderen Modifiern)
292     if ($_[1]->state * ["control-mask", "shift-mask"]) { # oder '&'
293     # Klick + Umschalt ODER Strg (eventuell plus anderen Modifieern)
294     if ($_[1]->state >= ["control-mask", "shift-mask"]) {
295     # Klick + Umschalt UND Strg (Übermenge)
296    
297     Oder beim Manipulieren von Event-Masken:
298    
299     $widget->set (events =>
300     $widget->get ('events') - [qw(key_press_mask button-motion-mask)]
301     );
302    
303     Auch eigene Klassen sind möglich, siehe Teil 2 :)
304 root 1.1
305 root 1.4
306     =head2 Beispiel: Session-Management
307 root 1.1
308 root 1.9 Häufig gibt es in C sogenannte I<convinience methods>
309 root 1.11 (C<">BequemlichkeitsfunktionenC<">). Sofern sie sinnvoll sind, wurden sie
310 root 1.9 bei Glib und Gtk2 umgesetzt. So gibt es z.B. eine C<set_events>- und
311     eine C<add_events>-Methode, die bei Gtk2-Widgets die Event-Maske
312 root 1.11 verändern. Doch für alle Properties kann man die generischen C<set>- und
313 root 1.9 C<get>-Methoden verwenden.
314    
315     Damit läßt sich ein einfaches Session-Management schreiben:
316    
317     use Scalar::Util;
318    
319     my %get = (
320     window_size => sub { [ ($_[0]->allocation->values)[2,3] ] },
321     column_size => sub { $_[0]->get ("width") || $_[0]->get ("fixed_width") },
322     modelsortorder => sub { [ $_[0]->get_sort_column_id ] },
323     );
324    
325     my %set = (
326     window_size => sub { $_[0]->set_default_size (@{$_[1]}) },
327     column_size => sub { $_[0]->set (fixed_width => $_[1]) },
328     modelsortorder => sub { $_[0]->set_sort_column_id (@{$_[1]}) },
329     );
330    
331     my $state = Storable::retrieve "session.dat"; # Alte Session-Daten laden
332     my %widget;
333    
334     sub state {
335     my ($widget, $class, %attr) = @_;
336    
337     while (my ($k, $v) = each %attr) {
338     $v = $state->{$class}{$k}
339     if exists $state->{$class} && exists $state->{$class}{$k};
340    
341     $set{$k} ? $set{$k}->($widget, $v) : $widget->set ($k => $v);
342     }
343    
344     $widget{$widget} = [$widget, $class, \%attr];
345     Scalar::Util::weaken $widget{$widget}[0];
346     }
347    
348 root 1.11 Naja, I<gaanz> so einfach ist es nicht: Man kann damit schon recht viel
349 root 1.9 anfangen, und es sind zugegebenermaßen mehr als drei Zeilen.
350    
351     Was macht der Code? Es gibt Eigenschaften, die man über eine Session
352     hinweg retten möchte, aber keine Properties sind. Für diese Eigenschaften
353     (z.B. C<window_size>) definiere ich eigene C<set>- und C<get>-Funktionen.
354    
355 root 1.11 Die eigentliche Schnittstelle ist die C<state>-Funktion. Sie wird so benutzt:
356 root 1.9
357     my $window = new Gtk2::Window;
358     state $window, "game::window", window_size => [600, 500];
359    
360     my $hpane = new Gtk2::HPaned;
361     state $hpane, "game::hpane", position => 500;
362    
363     Diese beiden Widgets werden in einem (nicht sehr fiktiven) Go-Programm
364     benutzt um ein Spiel darzustellen. Der erste Aufruf von C<state>
365     sagt: Beim Widget vom Typ C<game::window> (ein willkürlicher Name) soll
366     die Property C<window_size> von einer Session in die nächste Übertragen
367     werden. Falls keine Sessiondaten existieren, nimm als Default C<[600,
368     500]>. Der zweite Aufruf macht das gleiche für die C<Position>-Property
369     des C<Gtk2::HPaned>-Widgets.
370    
371 root 1.11 Beides zusammen sorgt dafür, daß neue Spielfenster in der gleichen
372 root 1.9 Größe erscheinen wie bei der letzten Benutzung und daß die horizontale
373     Unterteiling (links Spielbrett, rechts Chat-Bereich) ebenfalls erhalten
374     bleibt.
375    
376     In der Realität benutze ich eine etwas erweiterte C<state>-Funktion mit
377     einem C<$instance>-Argument: manche Benutzer möchten z.B. verschiedene
378     Chat-Räume in verschieden großen Fenstern darstellen. Das zusätzliche
379 root 1.11 Argument dient der Unterscheidung: wird ein neuer Raum betreten, werden
380     die Werte des Raum-Typs benutzt; wird ein bekannter Raum betreten, werden
381 root 1.9 dessen bekannte Werte benutzt.
382    
383     Die Funktion liest übrigens nur Werte aus den Sessiondaten C<$state> aus,
384     aber irgendwie müssen sie auch dort abgelegt werden. Dies geschieht in
385     meinen Programmen meistens durch Benutzeraufforderung: der Benutzer stellt
386     sein gewünschtes Layout zusammen und drückt dann C<Layout Speichern> o.ä.,
387     worauf dann folgende Funktion aufgerufen wird.
388    
389     sub save_state {
390     for (grep $_, values %widget) {
391     my ($widget, $class, $attr) = @$_;
392    
393     next unless $widget; # widget schon tot...
394     $widget->realize if $widget->can ("realize");
395    
396     while (my ($k, $v) = each %$attr) {
397    
398     $state->{$class}{$k} =
399     $get{$k} ? $get{$k}->($widget) : $widget->get ($k);
400     }
401     }
402    
403     Storable::nstore $state, "session.dat";
404     }
405    
406     Sie geht alle Widgets durch, die mit C<state> behandelt wurden, prüft, ob
407     sie noch existieren, sorgt (mit C<realize>) dafür, daß die Eigenschaften
408     auch mit sinnvollen Werten gefüllt sind, und speichert dann die
409     entsprechenden Eigenschaften in C<$state>.
410    
411 root 1.12 =head2 Beispiel: Rapid Application Development mit Glade -- mein Weg
412 root 1.9
413 root 1.11 Ich will es nicht verschweigen: Ich I<HASSE> (hoffentlich ist das deutlich
414     genug) GUI-Programmierung. Nichts ist langweiliger bzw. nerviger,
415     als Dialogboxen zusammenzustöpseln oder Widgets in der Hierarchie zu
416     verschieben.
417 root 1.9
418     Glücklicherweise gibt es RAD-Tools, mit denen man sich seine Applikation
419     zusammenklicken kann. Was mich an RAD-Tools allerdings stört ist ihre
420     Starrheit: meistens wollen sie gleich den Quelltext schreiben, inklusive
421     des Hauptprogramms. Und häufig ist es schwierig, generelle Klassen zu
422     definieren, z.B. ein Chat-Room-Widget, von dem es zur Laufzeit beliebig
423     viele geben kann.
424    
425 root 1.12 Auch I<Glade> -- ein (das!) Gtk+ und Gtk+2 RAD-Tool -- stellt hier keine
426 root 1.11 Ausnahme dar. Zum Glück kann man Glade auch etwas anders zum Entwickeln
427     benutzen, und diesen anderen Weg (ich kenne niemanden, der Glade so
428     benutzt), möchte ich hier beschreiben.
429 root 1.9
430     Zuallererst ist es notwendig, die Widget oder die UI in Glade zu
431     erstellen und als GladeXML-Datei zu speichern. Z.B. habe ich für
432     ein Bilder-Anzeige-Programm (Gtk2::CV, reiner Beta-Code) einen
433 root 1.11 Ausdrucken-Dialog erstellt:
434    
435     =for html
436     <img src="gtk2-cv.png" />
437 root 1.9
438     =for latex
439 root 1.11 \begin{center}\includegraphics{gtk2-cv.png}\end{center}
440 root 1.9
441     Die Beschreibung ist in der XML-Datei C<cv.glade> gespeichert. Darin habe
442     ich den einzelnen Widgets Namen gegeben, z.B. heißt das Dialogfenster
443     C<PrintDialog>, das Option-Menü zum Auswählen der Papiergröße C<papersize>
444     usw.
445    
446     Den ganzen Dialog kapsele ich in einem Perl-Modul namens
447     C<Gtk2::CV::PrintDialog> ab, mit insgesamt 70 Zeilen und zwei Methoden.
448     Die kürzeste davon benutzt ein anderes Modul C<Gtk2::CV::PostScript>
449     zum Ausdrucken und ist völlig uninteressant :) Die längste ist die
450     C<new>-Methode, die ein neues PrintDialog-Widget erzeugt. Zuerst der
451     Standardkopf:
452    
453     use Gtk2;
454     use Gtk2::GladeXML;
455     # uvm.
456    
457     sub new {
458     my $class = shift;
459     my $self = bless { @_ }, $class;
460    
461     Als nächstes wird die GladeXML-Datei geladen:
462    
463 root 1.11 $self->{dialog} = my $d
464     = new Gtk2::GladeXML ".../cv.glade", "PrintDialog";
465 root 1.9
466     Mit C<PrintDialog> wird ein Teilbaum aus dem Widget-Baum geladen, und zwar
467     der mit dem C<PrintDialog>-Namen. So kann man viele verschiedene Dialoge
468     in einer Datei ablegen. Das Laden ist nicht unbedingt eine schnelle
469     Angelegenheit, ist aber in den meisten Fällen flott genug, um bei jedem
470     Aufruf von neuem gemacht zu werden (und man hat sowieso keine Wahl :)
471    
472     Das Ergebnis ist I<kein> Widget, sondern ein C<Gtk2::GladeXML>-Objekt, das
473     die Methode C<get_widget> besitzt, mit der man anhand des Namens einzelne
474 root 1.11 Widgets C<">herausgreifenC<"> kann.
475 root 1.9
476     Damit fülle ich den Dialog mit Leben:
477    
478 root 1.11 $d->get_widget ("destination")->set (
479     text => $ENV{CV_PRINT_DESTINATION} || "| lpr");
480 root 1.9
481     my $menu = $d->get_widget ("papersize")->get_menu;
482     for (Gtk2::CV::PostScript->papersizes) {
483     my ($code, $name, $w, $h) = @$_;
484     $menu->append (my $item = new Gtk2::MenuItem $name);
485     $item->set_name ($code);
486     }
487     $menu->show_all;
488     $d->get_widget ("papersize")->set_history (0);
489    
490     $d->get_widget ("PrintDialog")->signal_connect (close => sub {
491     $_[0]->destroy;
492     });
493     $d->get_widget ("PrintDialog")->signal_connect (response => sub {
494     if ($_[1] eq "ok") {
495     $self->print (
496     size => (Gtk2::CV::PostScript->papersizes)
497     [$d->get_widget ("papersize")->get_history],
498     margin => $d->get_widget ("margin")->get_value,
499     ...
500     destination => $d->get_widget ("destination")->get ("text"),
501     binary => $d->get_widget ("encoding_binary")->get ("active"),
502     );
503     }
504     $_[0]->destroy;
505     });
506    
507     return $self; # Ende
508     }
509    
510     Jetzt wird klar, warum das Ding C<$d> heißt und nicht einen längeren Namen trägt.
511    
512 root 1.13 Wer das GladeXML-Modul kennt, weiß, daß es noch viel C<">einfacherC<"> geht,
513 root 1.9 z.B. mit C<signal_autoconnect_from_package>. Leider weiß man in den
514     Callbacks, die diese Methode mit den Widgets verbindet, nichts mehr über
515     das ursprüngliche C<PrintDialog>-Objekt, so daß sie mir recht nutzlos
516     erscheint, wenn man nicht alles in globalen Variablen ablegen will (was
517 root 1.11 häufig ausreicht, aber nicht gerade sauber ist).
518 root 1.9
519     Daher habe ich die Funktion C<signal_autoconnect_all> geschrieben. Sie
520     geht einen etwas anderen Weg und erlaubt es, die Signal-Callbacks als
521     Closures anzugeben. Damit wäre das Namensraum-Problem gelöst. Leider
522     muss man dazu jedem Signal-Handler einen Namen geben, und das ist so
523     umständlich, daß ich die Funktion selbst nie benutzt habe und es einfach
524 root 1.11 C<">per HandC<"> Anhand der Widget-Namen mache.
525 root 1.9
526     Dies alles heißt nicht, daß man es nicht einfacher anders besser machen
527 root 1.11 könnte. Es ist einfach C<">mein WegC<">, Glade zu benutzen. Und wenn ich noch
528 root 1.9 etwas darüber nachdenke, muß ich sagen, daß es mit Glade nicht wirklich
529     einfacher ist, Widgets umzustellen oder GUIs zu designen.
530    
531     *seufz*.
532    
533 root 1.1
534     =head1 Teil 2 - Gtk+ als solide Grundlage für Eigenentwicklungen
535    
536 root 1.11 Gtk+ eignet sich hervorragend für Eigenentwicklungen - auch
537     größere. Belegt wird dies dadurch, daß man es vollständig von Perl aus
538     erweitern kann und nicht auf einige vorgefertigte Klassen beschränkt
539     ist. Außerdem kann man Widgets aus beliebigen Sprachen miteinander
540     integrieren und sogar Teile in Perl und einer anderen Sprache schreiben,
541     was große Anwendungen einfacher macht: Zeitkritische Teile und Widgets
542     werden (z.B.) in C implementiert, während Perl bequem für die GUI-Logik
543     benutzt werden kann.
544 root 1.8
545 root 1.1 =head2 Perl-Objekte vs. Glib-Objekte
546 root 1.8
547 root 1.11 Meiner Meinung nach ist der Hauptgrund für das typisch C<">skripthafteC<">
548 root 1.10 Aussehen vieler Perl/Tk (oder Perl/Gtk oder Perl/Qt oder auch Tcl/Tk)
549     Programme die ausschließliche Verwendung von Standard-Widgets: Die
550     Programme sehen aus wie aus dem Baukasten, weil sie nur aus
551 root 1.11 Baukastenteilen bestehen. C<">RichtigeC<"> Anwendungen (wie z.B. Gimp) benutzen
552 root 1.10 aber eigene Widgets, sofern das Sinn macht.
553    
554     Viele Toolkits machen es einem sehr schwer, eigene Widgets zu
555 root 1.11 programmieren. Bei Gtk2 kann man zwischen einfachen Ableiten und C<">echtenC<">
556 root 1.10 Gtk2-Widgets wählen.
557    
558     =head3 Die Perl-Methode
559    
560 root 1.11 Die C<">Perl-MethodeC<"> besteht darin, eine neue Klasse von einem bestehenden
561 root 1.10 Widget abzuleiten. Das ist einfach und erfordert keinerlei Umdenken:
562    
563     package IntegerWidget;
564    
565     use base Gtk2::Entry;
566    
567     sub new {
568     my ($class, %prop) = @_;
569     my $self = $class->SUPER::new;
570    
571     $self->set_text ($prop{text});
572 root 1.8
573 root 1.10 $self->signal_connect (insert_text => sub {
574     my ($self, $text, $length, $position) = @_;
575     $text =~ y/0-9//cd;
576     ($text, $position);
577     });
578    
579     $self;
580     }
581    
582     ...
583    
584     $container->add (new IntegerWidget text => 50);
585    
586     Das geht mit fast jedem Toolkit. Aber ein richtig neues Widget kommt dabei
587     nicht heraus. Trotzdem ist dieses Vorgehen meistens nützlich, wenn man
588     eine große Menge an Widgets benötigt, die mehr oder weniger eine speziell
589     konfigurierte Version eines Standard-Widgets ist.
590    
591     Einige mehr oder minder wichtige Dinge kann man damit allerdings nicht
592     implementieren: Eigene Signale und Eigenschaften. Sicher kann man
593     eigene C<set_xxx>-Methoden schreiben, aber sie verhalten sich nicht wie
594     Glib-Properties (das Session-Management-Beispiel müßte speziell abgeändert
595     werden). Und Signale kann man durch Callbacks implementieren, aber der
596     Nutzer des Widgets muß dann auf C<signal_connect> verzichten und das
597     Widget verhält sich insgesamt nicht wie andere Widgets,
598    
599 root 1.11 Und schließlich kann man nur sehr schlecht selbst zeichnen und auf
600 root 1.10 Ereignisse (z.B. C<Expose>) reagieren.
601    
602     =head3 Die Glib-Methode
603    
604 root 1.11 Mit der C<">Glib-MethodeC<"> wird keine normale Perl-Klasse erstellt, sondern
605 root 1.10 eine echte Glib-Klasse (und zusätzlich eine Perl-Klasse, aber eben keine
606     ganz normale).
607    
608     Dabei hilft einem das C<Glib::Object::Subclass>-Modul, das ähnlich wie ein
609     Pragma wirkt:
610    
611     package IntegerWidget;
612    
613     use Glib::Object::Subclass
614     Gtk2::Entry,
615     signals => {
616     insert_text => sub {
617     my ($self, $text, $length, $position) = @_;
618     $text =~ y/0-9//cd;
619     $self->signal_chain_from_overridden ($self, $text, $length, $position);
620     },
621     };
622    
623     C<Gtk2:Entry> ist die Basisklasse und mit C<signals> werden vorhandene
624     Signale überschrieben bzw. neue deklariert. Überschreibt man ein
625     vorhandenes Signal (wie hier) kann man das ursprüngliche Signal mit
626     C<signal_chain_from_overridden> aufrufen, was einem C<SUPER>-Aufruf in
627     Perl entspricht.
628    
629     Das Modul setzt C<@ISA> und liefert auch gleich einige Methoden,
630     z.B. C<new>. Der Grund liegt darin, daß die C<new>-Methoden der
631     existierenden C<Gtk2>-Widgets das Klassenargument ignorieren, wie auch die
632     C-Funktionen, die sie aufrufen, kein Klassenargument besitzen. Bei der
633     Umsetzung von gtk+ in Perl dachte man, die normalen Konstruktoren seien
634     wichtiger, da sie häufiger aufgerufen werden.
635    
636     Die von C<Glib::Object::Subclass> gelieferte C<new>-Methode ruft lediglich
637     C<Glib::Object::new> auf. Das ist der generische Objekt-Konstruktor,
638     mit dem man jedes Glib-Objekt (bzw. auch davon abgeleitete) erzeugen
639     kann. Er akzeptiert C<< property => wert >>-Paare, was für dieses Beispiel
640     ausreicht, man muss also nichts weiter implementieren.
641    
642     Interessant wird es, wenn man zusätzliche Properties und Signale registriert:
643    
644     package IntegerWidget;
645    
646     use Glib::Object::Subclass
647     Gtk2::Entry,
648     signals => {
649     # neues signal, range-exception
650     range_exception => {
651 root 1.11 class_closure => sub { <default-implementierung> },
652 root 1.10 flags => [qw(run-first)],
653     param_types => [Glib::Integer],
654     },
655     # vorhandene Signale überschreiben
656     insert_text => sub {
657     ...
658     },
659     changed => sub {
660     my ($self) = @_;
661     my $text = $self->get_text;
662     $self->signal_emit (range_exception => $text)
663     if $text < $self->{min} || $text > $self->{max};
664     },
665     },
666     properties => [
667     Glib::ParamSpec->string (
668     min => "Minimum",
669     "Values smaller than this value cause a range_exception",
670     0, [qw(readable writable)]
671     ),
672     Glib::ParamSpec->string (
673     max => "Maximum",
674     "Values larger than this value cause a range_exception",
675     0, [qw(readable writable)]
676     ),
677     ],
678    
679     Hier wird ein neues Signal C<range_exception> eingeführt (das
680     standardmäßig garnichts macht). Es wird ausgelöst, wenn die eingegebene
681     Zahl kleiner oder größer als die Properties C<min> oder C<max> ist, was in
682     der C<changed>-Methode festgestellt wird.
683    
684     Wird eine Property gelesen, ruft Glib die C<GET_PROPERTY>-Funktion
685     auf. Sie ist in Grossbuchstaben geschrieben, weil sie nur
686     von Glib und nie vom eigenen Code aus aufgerufen wird,
687     ähnlich wie C<AUTOLOAD>. Genauso wird beim Verändern die
688     C<SET_PROPERTY>-Funktion aufgerufen. C<Glib::Object::Subclass> liefert zwei
689 root 1.11 Default-Implementierung, die die Werte aus C<$self->{name}> lesen bzw.
690 root 1.10 dort ablegen. Man kann diese Funktionen natürlich überschreiben:
691    
692     sub SET_PROPERTY {
693     my ($self, $pspec, $newval) = @_;
694     $self->{$pspec->get_name} = $newval;
695     # nicht so sinnvoll:
696     warn "max wurde geändert!!!" if $pspec->get_name eq "max";
697     # sehr sinnvoll:
698     $self->emit_signal ("changed");
699     }
700 root 1.3
701 root 1.11 Wenn C<min> oder C<max> geändert wird, löst diese Implementierung ein
702 root 1.10 C<changed>-Signal aus, um die neuen Grenzen zu prüfen.
703    
704     Die großgeschriebenen Funtkionen sind übrigens genau das: Funktionen. Sie
705 root 1.11 sollten niemals ihre SUPER-Implementierung aufrufen, das erledigt Glib
706 root 1.10 automatisch.
707    
708     Die beiden anderen Funktionen, die Glib aufruft sind C<INIT_INSTANCE>
709     und C<FINALIZE_INSTANCE>. Sie sollten das Objekt initialisieren bzw.
710     auflösen. I<Niemals> sollte man C<DESTROY> implementieren, da C<DESTROY>
711     intern von Glib benutzt wird und mehrmals aufgerufen werden kann.
712    
713     =head3 Referenzprobleme
714    
715     Jetzt zu einem kleinen aber feinem Problem. Was ist der Unterschied der
716     beiden folgenden INIT_INSTANCE-Funktionen?
717    
718     use Glib::Object::Subclass
719     Gtk2::Frame;
720    
721     sub INIT_INSTANCE {
722     my ($self) = @_;
723     $self->add ($self->{entry} = new Gtk2::Entry);
724     $self->{entry}->signal_connect (changed => sub {
725     warn $self->{entry}->get_text;
726     });
727     }
728    
729     sub INIT_INSTANCE {
730     my ($self) = @_;
731 root 1.1
732 root 1.10 $self->add ($self->{entry} = new Gtk2::Entry);
733     $self->{entry}->signal_connect (changed => sub {
734     warn $_[0]->get_text;
735     });
736     }
737 root 1.9
738 root 1.10 Nun, die obere Version erzeugt eine neue zirkuläre Referenz: Die Closure
739     im ersten Fall referenziert das äußere C<$self>. Wie löst man diese
740     Referenzen auf?
741    
742     Das größte Problem neuer Widgets sind zusätzliche Referenzen, die das
743     Widget daran hindern, sich aufzulösen.
744    
745     Gtk2 löst dieses Problem durch ein explizites C<destroy>-Signal: Wird es
746     ausgelöst, sollte das Objekt möglichst alle Referenzen auf andere Objekte
747     freigeben. Fällt dabei der Referenz-Zähler auf 0 ab, wird das Objekt
748     aufgelöst.
749    
750     Container lösen dabei rekursiv das C<destroy>-Signal auf die in ihnen
751     enthaltenen Objekte auf. Dabei werden normalerweise alle Referenzen
752     aufgelöst, da z.B. Signal-Handler ebenfalls entfernt werden, die
753     Selbstreferenz im obigen Beispiel ist dabei also eigentlich kein Problem.
754    
755     Viele Perl-Widgets sind aber versteckte Container, da man häufig
756     zusammengesetzte Widgets erzeugt, wie im obigen Beispiel. Dann kann es
757     passieren, das auch nach einem C<destroy> ein eingebettetes Widget eine
758     Referenz auf den Vater enthält, und der hält gleichermaßen eine Referenz
759 root 1.14 (C<< $self->{entry} >>).
760 root 1.10
761     Dies kann man umgehen, indem man bei einem C<destroy> einfach %$self löscht:
762    
763     $self->signal_connect (destroy => sub { %{$_[0]} = () });
764    
765     Das ist etwas radikal, daher gibt es zwei sauberere Lösungen. Einmal kann
766     man bei einem C<destroy> wirklich sauber aufräumen:
767    
768     $self->signal_connect (destroy => sub {
769     (delete $self->{entry})->destroy;
770     # etc. für andere Widgets
771     });
772    
773     Oder man verhindert zusätzliche Referenzen auf Perl-Seite, was natürlich
774     nur bei einfachen Referenzen geht:
775    
776     use Scalar::Util ();
777     Scalar::Util::weaken $self->{entry};
778    
779     =head3 Beispiel: ein Go-Brett
780 root 1.1
781 root 1.10 Für einen Go-Server-Client benötige ich ein Widget, das ein Go-Spielbrett
782     darstellt (das Bild zeigt es beim Auszählen der Punkte eines Spiels).
783 root 1.9
784 root 1.11 =for html
785     <img src="gtk2-kgsueme.png" />
786    
787 root 1.10 =for latex
788 root 1.11 \begin{center}\includegraphics[scale=0.3]{gtk2-kgsueme.png}\end{center}
789 root 1.1
790 root 1.11 Der Code für Board-Widget fängt so an:
791    
792     use Glib::Object::Subclass
793     Gtk2::AspectFrame,
794     properties => [
795     Glib::ParamSpec->IV (
796     "size",
797     "Board Size",
798     "The Go Board size, 2..38",
799     2, 38, 19,
800     [qw(construct-only writable readable)],
801     ),
802     Glib::ParamSpec->IV (
803     "cursor-mask",
804     "cursor mask",
805     "The mask used to show a cursor",
806     0, 1<<30, 0,
807     [qw(writable readable)],
808     ),
809     Glib::ParamSpec->IV (
810     "cursor-value",
811     "cursor value",
812     "The value used to show a cursor",
813     0, 1<<30, 0,
814     [qw(writable readable)],
815     ),
816     ],
817     signals => {
818     "button-press" => {
819     flags => [qw/run-first/],
820     return_type => undef, # void return
821     param_types => [Glib::Int, Glib::Int, Glib::Int],
822     },
823     "button-release" => {
824     flags => [qw/run-first/],
825     return_type => undef, # void return
826     param_types => [Glib::Int, Glib::Int, Glib::Int],
827     },
828     destroy => sub {
829     $_[0]->signal_chain_from_overridden;
830     %{$_[0]} = ();
831     },
832     };
833    
834     Das Brett wird also von einer C<Gtk2::AspectFrame> abgeleitet: Das Brett
835     ist zwar nicht ganz quadratisch, hat aber immer dasselbe Seitenverhältnis
836     von ca. 11:10, so daß ein AspectFrame sich anbietet.
837    
838     Als erstes werden drei Properties definiert: die Größe (C<size>), die die
839     Anzahl der Linienschnittpunkte angibt. Sie kann nur beim Erzeugen gesetzt
840     werden (Flag C<construct-only>), nicht mehr später. Dies vereinfacht den
841     Code etwas. Die beiden anderen Properties definieren das Aussehen des
842     C<">CursorsC<">: wenn man mit der Maus über das Brett fährt, kann man damit z.B.
843     einen halbdurchscheinenden Stein anzeigen.
844    
845     Dann folgen zwei neue Signale, die ausgelöst werden, wenn man
846     einen Mausknopf auf dem Brett drückt bzw. losläßt. Sie haben drei
847     Integer-Parameter: Die Nummer des Mausknopfes und die Koordinaten des
848     Klicks.
849    
850     Das C<destroy>-Signal wird überschrieben, das C<%$self> brutal löscht. Da
851     ich von C<Gtk2::AspectFrame> ableite weiß ich, daß ich kein anderes
852     Perl-Widget in der Hierarchie über mir stören kann, da Gtk2-Widgets selbst
853     den Perl-Hash C<%$self> nicht antasten.
854    
855     Danach folgen einige Konstantendefinitionen für Steine, z.B. C<MARK_B>
856     oder C<MARK_SQUARE>, die zusammenaddiert das Aussehen einer Brettposition
857     festlegen oder die relative Größe von Steinen (schwarze Steine sind etwas
858     größer) sowie Funktionen zum Laden von Bildern.
859    
860     Interessanter wird dann die C<INIT_INSTANCE>-Funktion:
861    
862     sub INIT_INSTANCE {
863     my $self = shift;
864    
865     @::black_img
866     or load_images;
867    
868     $self->double_buffered (0);
869     $self->set (border_width => 0, shadow_type => 'none',
870     obey_child => 0, ratio => TRAD_RATIO);
871     $self->set(cursor_mask => MARK_B | MARK_W,
872     cursor_value => MARK_B | MARK_GRAYED);
873    
874     $self->add ($self->{canvas} = new Gtk2::DrawingArea);
875    
876     $self->{canvas}->signal_connect (
877     configure_event => sub { $self->configure_event ($_[1]) });
878     $self->{canvas}->signal_connect (
879     motion_notify_event => sub { $self->motion });
880     $self->{canvas}->signal_connect (
881     leave_notify_event => sub { $self->cursor (0) });
882     $self->{canvas}->signal_connect (
883     button_press_event => sub { $self->button ("press", $_[1]) });
884     $self->{canvas}->signal_connect (
885     button_release_event => sub { $self->button ("release", $_[1]) });
886    
887     $self->{canvas}->set_events ([
888     @{ $self->{canvas}->get_events },
889     'leave-notify-mask',
890     'button-press-mask',
891     'button-release-mask',
892     'pointer-motion-mask',
893     'pointer-motion-hint-mask'
894     ]);
895     }
896    
897     Hier wird eine C<Gtk2::DrawingArea> eingebettet, die das eigentliche
898     Bild darstellt. Eine C<Gtk2::DrawingArea> ist eine Art leeres Widget,
899     das selbst nichts zeichnet, aber an der Größenbelegung teilnimmt und eine
900     hervorragende Grundlage für eigene Widgets ist.
901    
902     Das Go-Widget verwendet einen Trick: Die Brett-Grafik befindet sich
903     im X-Server (Windows: keine Ahnung) und wird automatisch vom Server
904     gezeichnet, das Widget muss also keine C<Expose>-Events behandeln, sondern
905     C<">nurC<"> zeichnen. Als Beispiel für ein Widget, das C<Expose>-Events selbst
906     behandelt, sei C<Gtk2::CV::Schnauzer> genannt, das ein komplettes Widget
907     inklusive Size-Allocation und Expose in Perl implementiert.
908    
909     Als nächstes die C<SET_PROPERTY>-Funktion:
910    
911     sub SET_PROPERTY {
912     my ($self, $pspec, $newval) = @_;
913    
914     $pspec = $pspec->get_name;
915    
916     $self->cursor (0) if $pspec =~ /^cursor/;
917     $self->{$pspec} = $newval;
918     $self->cursor (1) if $pspec =~ /^cursor/;
919     }
920    
921     Sie macht das gleiche wie die normale C<SET_PROPERTY>-Funktion, nur bei
922     den Cursor-Attributen wird der Cursor neugezeichnet (was die Funktion
923     C<cursor> erledigt).
924    
925     Dann folgt der Handler für das C<configure-notify-event>-Signal, das
926     erzeugt wird, wenn sich Größe oder Position des Widgets ändern:
927    
928     sub configure_event {
929     my ($self, $event) = @_;
930    
931     $self->{window} = $self->{canvas}->window;
932    
933     my $drawable = $self->{window};
934    
935     $drawable->set_back_pixmap (undef, 0);
936    
937     $self->{idle} ||= add Glib::Idle sub {
938     delete $self->{stack};
939    
940     $self->{width} = $self->{canvas}->allocation->width;
941     $self->{height} = $self->{canvas}->allocation->height;
942     $self->draw_background;
943    
944     $self->draw_board (delete $self->{board}, 0) if $self->{board};
945     $self->{window}->clear_area (0, 0, $self->{width}, $self->{height});
946    
947     delete $self->{idle}; # Handler lief
948     0; # Lösche Handler
949     };
950    
951     1;
952     }
953    
954     Sie löscht die Background-Pixmap, da sie nicht mehr gültig ist und
955     neugezeichnet wird. Da das initiale Zeichnen des Brettes clientseitig
956     geschieht und das Zeichnen und der Transfer zum Server einige Zeit in
957     Anspruch nimmt, geschieht es nicht synchron zum Signal, sondern später,
958     in einem Idle-Handler. Dieser wird aufgerufen, wenn die Hauptschleife von
959     Gtk2 alle anstehenden Ereignisse abgearbeitet hat.
960    
961     Das Gdk-Fenster, das man mit C<< $self->{canvas}->window >> erhält, kann
962     erst hier abgefragt werden und nicht schon in C<INIT_INSTANCE>, da zum
963     Zeitpunkt von C<INIT_INSTANCE> noch keine Gdk-Fenster für die Widgets
964     erzeugt wurden sondenr erst, nachdem sie das erste mal angezeigt wurden
965     (bzw. etwas früher, wenn sie I<realized> werden).
966    
967     Im Idle-Handler werden noch andere Daten invalidiert (C<< $self->{stack}
968     >> speichert die vorberechneten Steine), die neue Größe abgefragt und der
969     Bretthintergrund gezeichnet sowie die Steine gemalt und gesetzt.
970    
971     Am Ende wird dem X-Server mit C<clear_area> mitgeteilt, daß er die Grafik
972     auffrischen soll.
973    
974 root 1.16 Danach folgen einige hundert Zeilen Code, der die Grafik zeichnet (und
975     dazu im wesentlichen C<Gtk2::Gdk::Pixbuf> benutzt). Und dann:
976 root 1.11
977     sub do_button_press {
978     my ($self, $button, $x, $y) = @_;
979     }
980    
981     sub do_button_release {
982     my ($self, $button, $x, $y) = @_;
983     }
984    
985     Als der Code geschrieben wurde, gab es noch kein C<class_closure>-Feld für
986     Signale und Signale wurden immer als Perl-Methoden aufgerufen, mit einem
987     vorangestellten C<do_> (C<">weil Python das auch so machtC<"> :).
988    
989     Und abschließend noch die Methode, die die Mausklick-Signale auslöst:
990    
991     sub button {
992     my ($self, $type, $event) = @_;
993    
994     $self->motion;
995    
996     if ($self->{cursorpos}) {
997     $self->signal_emit ("button-$type", $event->button, @{ $self->{cursorpos} });
998     }
999     }
1000    
1001     C<< $self->motion >> bewegt den Cursor, falls das notwendig ist, und,
1002     falls die Maus über einer gültigen Brettposition stelt, wird ein Signal
1003     ausgelöst.
1004    
1005    
1006     Wenn man so wollte, könnte man von C/C++/XS aus jetzt ein neues Go-Brett
1007     erzeugen:
1008    
1009     GtkWidget *w = g_object_new (
1010     "Gtk2__GoBoard", # ':' wird zu '_'
1011     "size", 19
1012     );
1013    
1014 root 1.14 ... und im wesentlichen so benutzen wie jedes andere Gtk2-Widget.
1015 root 1.9
1016 root 1.1
1017 root 1.7 =head2 Objekte aus anderen Sprachen nutzen
1018 root 1.1
1019 root 1.11 Obwohl es eine aufregende Idee wäre, Python-Widgets in Perl und umgekehrt
1020     zu benutzen, ist dies eher unrealistisch: man müßte zuerst Python und
1021     Perl im selben Prozess vereinigen, was wahrscheinlich möglich ist, aber
1022     kostspielig.
1023    
1024     Deshalb beschränke ich mich auf Widgets/Objects aus C oder C++, die
1025     Vorgehensweise ist aber übertragbar auf andere Sprachen.
1026    
1027     Dazu muß man zwei Schritte durchführen: Erstens die Bibliothek oder
1028     den Code in den Prozess linken, zweitens die C<GType>s beim Glib-Modul
1029     registrieren.
1030    
1031     Am einfachsten (bzw. portabelsten) geschieht dies mit einem
1032     kleinen XS-Modul. Möchte man z.B. den C<GimpColorButton> aus der
1033 root 1.14 C<libgimpwidgets>, schreibt man ein kleines Modul (oder benutzt
1034     C<DynaLoader> und C<Inline::C>), das man gegen die C<libgimpwidgets>
1035     linkt.
1036 root 1.11
1037     In dessen BOOT-Section schreibt man:
1038    
1039     BOOT:
1040     gperl_register_object (GIMP_TYPE_COLOR_BUTTON, "Gimp::ColorButton");
1041    
1042     Damit ist die Verbindung zwischen C und Perl hergestellt, und man kann den
1043 root 1.14 C<Gimp::ColorButton> sofort benutzen:
1044 root 1.11
1045     use MeinXSModul;
1046    
1047     my $button = Gimp::ColorButton->Glib::Object::new (...);
1048    
1049     Ähnlich verfährt man mit anderen Datentypen (z.B. Flags und Aufzählungen),
1050     die man registrieren möchte:
1051    
1052     gperl_register_fundamental (GDK_TYPE_CAP_STYLE, "Gtk2::Gdk::CapStyle");
1053    
1054     Sobald sie registriert sind, kann man sie wie gewohnt von Perl aus Nutzen.
1055    
1056 root 1.9
1057 root 1.7 =head1 Verweise
1058 root 1.1
1059 root 1.7 =over 4
1060 root 1.1
1061 root 1.7 =item http://www.gtk.org/
1062 root 1.1
1063 root 1.9 Die Dokumentation zu Gtk+, Glib usw.
1064 root 1.10
1065 root 1.11 =item perldoc Glib, Glib::Object, Gtk2, Gtk2::<widgetname>
1066 root 1.10
1067     Das Gtk2-Modul hat für jedes Widget eine eine C<perldoc>-Seite, die (kurz)
1068     die Hierarchiezugehörigkeit, Methoden, Signale und Properties auflistet.
1069 root 1.1
1070 root 1.7 =item apt-get install devhelp-book-gtk2 # oder devhelp-books
1071 root 1.1
1072 root 1.11 Installiert unter Debian I<devhelp>, einen interaktiven Help-Browser und
1073 root 1.7 das Gtk2-Buch (dazu gehört auch GObject, Glib-Doku uvm.). Sehr hilfreich
1074     beim Programmieren.
1075 root 1.9
1076 root 1.11 =item Gtk2::PodViewer, Gtk2::GoBoard, Gtk2::CV::Schnauzer
1077 root 1.9
1078 root 1.11 Verschiedene Gtk2-Widgets in Perl.
1079 root 1.1
1080 root 1.7 =back
1081 root 1.11
1082    
1083     =head1 Danke
1084    
1085     ... an Zaphod, der dies hier in aller Eile probelas und furchtbar viele
1086     Fehler fand :)
1087    
1088     ... an denjenigen, der Latex (a.k.a. "the bag of dirty broken hacks")
1089     endlich mal fixt.
1090 root 1.1
1091