ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/cvsroot/docs/pws2004/gtk2.pod
Revision: 1.19
Committed: Mon Jun 28 17:12:45 2004 UTC (22 years, 3 months ago) by root
Branch: MAIN
CVS Tags: HEAD
Changes since 1.18: +2 -2 lines
Log Message:
*** empty log message ***

File Contents

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