ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/cvsroot/docs/pws2004/gtk2.pod
Revision: 1.9
Committed: Thu May 27 19:51:01 2004 UTC (22 years, 4 months ago) by root
Branch: MAIN
Changes since 1.8: +380 -15 lines
Log Message:
*** empty log message ***

File Contents

# User Rev Content
1 root 1.5 =encoding utf8
2    
3 root 1.1 =head1 Gtk+2 - ein erweiterbares GUI-Toolkit
4    
5     =head2 Abstract
6    
7 root 1.3 Gtk+2 (das {{G}}IMP {{T}}ool{{K}}it, Version 2) unterlief bei der
8     Entwicklung zu Version 2 tiefgreifende Änderungen. Das Typsystem wurde
9 root 1.9 stark abstrahiert, so daß sich Schnittstellen zu anderen Sprachen im
10 root 1.3 wesentlichen auf das Bereitstellen des Objektsystems beschränken.
11    
12 root 1.9 In diesem Dokument wird das Toolkit gtk+2 kurz vorgestellt, wobei
13     Erfahrung mit GUI-Programmierung vorausgesetzt wird. Im Wesentlichen geht
14     es darum, einige besondere Techniken vorzustellen sowie das Toolkit von
15     Perl und C aus selbst zu erweitern.
16 root 1.1
17 root 1.6 =head1 Gtk2 und Glib, eine Übersicht
18 root 1.1
19 root 1.3 =head2 Übersicht über die G-Module
20 root 1.1
21 root 1.3 Es gibt eine Menge Bibliotheken, deren Namen mit G anfängt und im
22     Dunstkreis von Gtk+ stehen. Vielleicht wäre es sinnvoll gewesen, eine neue
23     G-Hierarchie in Perl zu begründen, so muß man sich mit einer teilweise
24     nicht sehr logischen Namensgebung zurechtzufinden.
25    
26     =over 4
27    
28     =item Glib
29    
30     Glib ist die Schnittstelle zur C<libglib> (sowie zu C<libgobject>,
31     C<libgmodule> und C<libgthread>). Es bildet die Grundlage für das Objekt-
32     und Typ- und Signalsystem, bietet Hilfsfunktionen zum Umwandeln von
33     Dateinamen, Logging usf.
34    
35     =item Gtk2
36    
37     Dieses Modul ist eine Sammelstelle für diverse Bilbiotheken: neben
38     C<libgtk+> auch C<libgdk>, C<libgdk_pixbuf> und C<libpango>.
39    
40     Sie reicht für fast alle Anwendungen aus.
41    
42     =item Gtk2::GLExt, Gtk2::GladeXML, Gtk2::TrayIcon und Gtk2::Spell
43    
44     Bieten Integration von OpenGL, GladeXML, EggTryIcon und Spell-checking für
45     Text-Widgets.
46    
47     =item Gnome2
48    
49     Schnittstelle zur C<libgnome> und vielem mehr. Muss man nicht
50     benutzen, kann mir aber vorstellen, das sie für die Erstellung von
51     Gnome-Applikationen ganz nützlich sind :)
52    
53     =item Gnome2::Canvas, Gnome2::GConf, Gnome2::PanelApplet, Gnome2::Print,
54     Gnome2::Rsvg, Gnome2::VFS, Gnome2::Vte, Gnome2::Wnck.
55    
56 root 1.6 Jede Menge Gnome-Zeugs.
57 root 1.3
58     =back
59 root 1.1
60 root 1.6 =head2 Die Widgets von Gtk2 sind GObjects
61 root 1.1
62 root 1.3 Wie jedes andere Toolkit auch, bietet Gtk2 eine Menge vorgefertigter
63     I<Widgets>: I<Buttons>, I<Labels>, I<Frames> und andere "einfache"
64     Widgets, aber auch komplexe, wie das I<Text>- (komplett in Unicode,
65     einbettbare Objekte) oder das I<TreeView>- (Listen und Bäume im
66     MVC-Modell) Widget.
67    
68     =begin latex
69    
70     \begin{figure}[h]\includegraphics{gtk2-textwidget.png}\label{Das Text-Widget}\end{figure}
71    
72     =end latex
73    
74 root 1.6 Alle diese Widgets sind sogenannte I<GObjects> (davon abgeleitet sind
75     in Gtk2 dann sogenannte I<Widgets>, GUI-Objekte), und haben folgende
76     Features:
77 root 1.4
78     =over 4
79    
80     =item Eine Klasse
81    
82 root 1.6 Jedes GObject ist eine Instanz einer Klasse (C<GObjectClass>), eine
83     Datenstruktur, die Informationen über Methoden u.ä. speichert.
84    
85     Eine C<GObjectClass> ist allerdings nur ein Spezialfall eines
86     C<GType>s: Die Glib bildet ein komplettes Typsystem mit Klassen,
87     Aufzählungen, Flags, einfachen Datentypen wie Integer oder
88     Fließkommazahlen oder auch C-structs an. All dies ist zur Laufzeit in
89     einer Form verfügbar, in der sich auch neue - zur Compielzeit nicht
90     bekannte - Datentypen verwenden lassen.
91    
92     Schnittstellen für andere Sprachen werden dadurch einfach, da man
93     "lediglich" die Konzepte "Datentyp", "Konverter", "Klasse", "Methode",
94     "Bitset" usw. umsetzen muß. Konkrete Instanzen dieser Typen funktionieren
95     zur Laufzeit automatisch.
96    
97     Bei einer gut geschriebenen C-Bibliothek, die auf Glib bzw. GObject
98     aufsetzt, muß man eigetnlich nur die Initialisierungsfunktion aufrufen,
99     die die Datentypen registriert, und kann dann sofort von Perl darauf
100     zugreifen - ohne eine einzige XS-Funktion geschrieben zu haben.
101 root 1.4
102     =item Methoden
103    
104     Jedes GObjekt hat mindestens Methoden zum Erzeugen (C<constructor>)
105 root 1.6 und Zerstören (C<finalize>), Setzen und Lesen von Properties und eine
106 root 1.4 Spezialität von GObject - C<dispose>. Letzteres ist eine Art Anfrage an
107     ein Objekt, sich freiwillig aufzulösen.
108    
109 root 1.6 Gtk2 fügt noch einige weitere hinzu, wie die C<destroy>-Methode, die aktiv
110     versucht, ein Objekt zu zerstören: In GUI-Programmen ist es manchmal
111     schwer, alle Referenzen im richtigen Moment aufzulösen, da sie häufig
112     zirkulär sind. Manche Objekte "leben" auch ganz eigenständig, z.B. wird
113     ein Toplevel-Fenster im allgemeinen vom Benutzer "referenziert", was sich
114     aber nicht notwendigerweise im Referenz-Zähler niederschlägt.
115    
116     Um solche Objekte loszuwerden, kann man sie bitten, sich zu
117     I<destroyen>. Dabei gibt es alle Referenzen auf andere Objekte frei und
118     bittet diese, sich ebenfalls zu destroyen. Dadurch werden zirkuläre
119     Referenzen effektiv aufgebrochen.
120    
121 root 1.7 Methoden kann man in Perl nicht direkt implementieren, dafür aber eigene
122     Signale, die beliebige Parameter oder Rückgabewerte besitzen können und
123     mehr oder weniger direkt von C oder anderen Sprachen aus aufgerufen werden
124     können.
125 root 1.6
126 root 1.4 =item Signale
127    
128 root 1.6 Signale ähneln Methoden, Callbacks oder sogenannten "Delegates". Wie
129     Methoden sind sie fest an eine Klasse gebunden und rufen (in C) eine
130     Methode der Klasse auf, sobald sie ausgelöst werden.
131    
132     Ein Signal kann von jedem ausgelöst werden, insbesondere lösen aber
133     Ereignisse (Events) in Gtk2 Signale aus. Der Signal-Handler eines Objektes
134     verarbeitet das Ereignis (und beendet die Signalauslieferung) oder tut
135     nichts, woraufhin Gtk2 ein anderes Objekt als Empfänger sucht.
136    
137     Zusätzlich kann man vor oder nach dem eigentlichen Signal-Handler
138     des Objektes weitere Callbacks einklinken. Z.B. löst das Text-Widget
139     beim Mausklick rechts ein C<populate-menu>-Signal aus, das
140     normalerweise ein Popup-Menü generiert. Das kann man verändern oder
141     ganz überschreiben. Und wenn man Mausklicks abfangen möchte, kann man
142     das C<button-press-event>-Signal überschreiben und so Mausklicks vom
143     Text-Widget fernhalten.
144    
145 root 1.4 =item Properties (Eigenschaften)
146    
147 root 1.6 Properties sind von der jeweiligen Klasse definierte Eigenschaften, die
148     das Objektverhalten beeinflussen.
149    
150 root 1.7 #TODO#
151    
152 root 1.6 =item Schlüssel-Wert-Paare
153    
154 root 1.7 #TODO#
155    
156 root 1.4 =back
157 root 1.3
158 root 1.9 =head2 Leben und sterben lassen: Wie man seine Objekte wieder loskriegt
159    
160     #TODO
161    
162     =head2 Informationen über Typen und Klassen zur Laufzeit abfragen
163    
164     Die Typinformationen, wie Werte von Aufzählungen, Namen von Datentypen,
165     Objekt-Signale, -Properties uvm., sind alle zur Laufzeit abfragbar.
166    
167     Dadurch wird das Schreiben von Klassenbrowsern oder RAD-Tools serh
168     einfach. Aber auch beim Entwickeln von Programmen ist das nützlich, da man nicht immer
169     die Dokumentation zu Rate ziehen muss.
170    
171     Z.B. liefert C<< $obj->list_properties >> (oder
172     C<Glib::Type::list_properties> Klassenname) eine Liste von Arrayrefs mit
173     Name, Typ, Flags und Beschreibung zurück, die man sich z.B. mit folgender
174     Funktion ausgeben lassen kann:
175    
176     use Gtk2;
177    
178     sub gobj_props {
179     for ($_[0]->list_properties) {
180     printf "%-16s %-24s %-24s %s\n", $_->{name}, $_->{type}, (join ":", @{$_->{flags}}), $_->{descr};
181     }
182     }
183    
184     Der Aufruf C<gobj_props "Gtk2::Widget"> (oder mit einem
185     C<Gtk2::Window>-Object als Argument) liefert folgende Properties, die alle
186     Gtk2-Widgets besitzen:
187    
188     user-data gpointer readable:writable
189     Anonymous User Data Pointer
190     name Glib::String readable:writable
191     The name of the widget
192     parent Gtk2::Container readable:writable
193     The parent widget of this widget. Must be a Container widget
194     width-request Glib::Int readable:writable
195     Override for width request of the widget, or -1 if natural request should be used
196     ...
197     extension-events Gtk2::Gdk::ExtensionMode readable:writable
198     The mask that decides what kind of extension events this widget gets
199     no-show-all Glib::Boolean readable:writable
200     Whether gtk_widget_show_all() should not affect this widget
201    
202     Signale lassen sich ebenso abfragen:
203    
204     sub gobj_signals($) {
205     # Signale haben Argumente und Parameter, daher Dumpvalue
206     use Dumpvalue;
207     Dumpvalue->new (bareStringify => 0)->dumpValue ($_)
208     for Glib::Type->list_signals ($_[0]);
209     }
210    
211     gobj_signals "Gtk2::Widget";
212    
213     ...
214     'signal_id' => 23
215     'signal_name' => 'button-press-event'
216     'itype' => 'Gtk2::Widget'
217     'param_types' => ARRAY(0x83b4f28)
218     0 'Gtk2::Gdk::Event'
219     'return_type' => 'Glib::Boolean'
220     'signal_flags' => [ run-last ]
221     -> 2
222     ...
223    
224     Das C<button-press-event>-Signal möchte also ein Event als einziges
225     Argument und liefert einen Wahrheitswert.
226    
227     Die Abstammung von C<Gtk2::Window> ist schnell gefunden:
228    
229     warn join " ", Glib::Type->list_ancestors ("Gtk2::Window");
230     Gtk2::Window Gtk2::Bin Gtk2::Container Gtk2::Widget
231     Gtk2::Object Glib::Object at gtk.pl line xx.
232    
233     # und list_interfaces wollte ich auch erwähnen:
234     warn join " ", Glib::Type->list_interfaces ("Gtk2::Window");
235     Gtk2::Atk::ImplementorIface at gtk.pl line xx.
236    
237     Wenn man gtk+ von C her kennt (oder eben die C-Dokumentation benutzt),
238     kann man aus dem C-Typnamen den Namen in Perl erfahren:
239    
240     warn Glib::Type->package_from_cname ("GtkWindowPosition");
241     Gtk2::WindowPosition at gtk.pl line xx.
242    
243     warn Glib::Type->package_from_cname ("GdkPixbuf");
244     Gtk2::Gdk::Pixbuf at gtk.pl line xx.
245    
246     Aufzählungen und Flags kann man ebenso hinterfragen:
247    
248     sub g_vals($) {
249     for (Glib::Type->list_values ($_[0])) {
250     printf "%-30s %s\n", $_->{name}, $_->{nick};
251     }
252     }
253    
254     g_vals "Gtk2::Gdk::EventMask";
255    
256     GDK_EXPOSURE_MASK exposure-mask
257     GDK_POINTER_MOTION_MASK pointer-motion-mask
258     ...
259     GDK_SCROLL_MASK scroll-mask
260     GDK_ALL_EVENTS_MASK all-events-mask
261    
262     =head3 Aufzählungen und Flags
263    
264     Natürlich kann man zur Laufzeit auch eigene Typen hinzufügen. Z.B. ein
265     neuer Flag-Typ:
266    
267     Glib::Type->register_flags (Meine::Flags =>
268     'eins', # implizit 1<<0
269     'zwei', # implizit 1<<1
270     ['drei' => 15 ], # explizit 15
271     ['vier' => 35 ], # explizit 35
272     'fuenf', # implizit 1<<4
273     );
274    
275     Diese neuen Typen sind gleichwertig zu den vorhandenen, können also von C
276     oder anderen Programmiersprachen aus benutzt werden.
277    
278     Aufzählungen und Flags sind in Perl überladen. Das ist besonders hilfreich
279     in Event-Handlern:
280    
281     $widget->signal_connect (button_press_event => sub {
282     if ($_[1]->type eq "button-press") {
283     if ($_[1]->button == 1) {
284     if ($_[1]->state == "shift-mask") {
285     # Umschalt-Klick
286     if ($_[1]->state * "shift-mask") { # oder '&'
287     # Umschalt-Klick (eventuell plus anderen Modifiern)
288     if ($_[1]->state * ["control-mask", "shift-mask"]) { # oder '&'
289     # Klick + Umschalt ODER Strg (eventuell plus anderen Modifieern)
290     if ($_[1]->state >= ["control-mask", "shift-mask"]) {
291     # Klick + Umschalt UND Strg (Übermenge)
292    
293     Oder beim Manipulieren von Event-Masken:
294    
295     $widget->set (events =>
296     $widget->get ('events') - [qw(key_press_mask button-motion-mask)]
297     );
298    
299     Auch eigene Klassen sind möglich, siehe Teil 2 :)
300 root 1.1
301 root 1.4
302     =head2 Beispiel: Session-Management
303 root 1.1
304 root 1.9 Häufig gibt es in C sogenannte I<convinience methods>
305     ("Bequemlichkeitsfunktionen"). Sofern sie sinnvoll sind, wurden sie
306     bei Glib und Gtk2 umgesetzt. So gibt es z.B. eine C<set_events>- und
307     eine C<add_events>-Methode, die bei Gtk2-Widgets die Event-Maske
308     verändert. Doch für alle Properties kann man die generischen C<set>- und
309     C<get>-Methoden verwenden.
310    
311     Damit läßt sich ein einfaches Session-Management schreiben:
312    
313     use Scalar::Util;
314    
315     my %get = (
316     window_size => sub { [ ($_[0]->allocation->values)[2,3] ] },
317     column_size => sub { $_[0]->get ("width") || $_[0]->get ("fixed_width") },
318     modelsortorder => sub { [ $_[0]->get_sort_column_id ] },
319     );
320    
321     my %set = (
322     window_size => sub { $_[0]->set_default_size (@{$_[1]}) },
323     column_size => sub { $_[0]->set (fixed_width => $_[1]) },
324     modelsortorder => sub { $_[0]->set_sort_column_id (@{$_[1]}) },
325     );
326    
327     my $state = Storable::retrieve "session.dat"; # Alte Session-Daten laden
328     my %widget;
329    
330     sub state {
331     my ($widget, $class, %attr) = @_;
332    
333     while (my ($k, $v) = each %attr) {
334     $v = $state->{$class}{$k}
335     if exists $state->{$class} && exists $state->{$class}{$k};
336    
337     $set{$k} ? $set{$k}->($widget, $v) : $widget->set ($k => $v);
338     }
339    
340     $widget{$widget} = [$widget, $class, \%attr];
341     Scalar::Util::weaken $widget{$widget}[0];
342     }
343    
344     Naja, I<gaanz> so einfach ist es nicht: Man kann damit shcon recht viel
345     anfangen, und es sind zugegebenermaßen mehr als drei Zeilen.
346    
347     Was macht der Code? Es gibt Eigenschaften, die man über eine Session
348     hinweg retten möchte, aber keine Properties sind. Für diese Eigenschaften
349     (z.B. C<window_size>) definiere ich eigene C<set>- und C<get>-Funktionen.
350    
351     Die Eigentliche Schnittstelle ist die C<state>-Funktion. Sie wird so benutzt:
352    
353     my $window = new Gtk2::Window;
354     state $window, "game::window", window_size => [600, 500];
355    
356     my $hpane = new Gtk2::HPaned;
357     state $hpane, "game::hpane", position => 500;
358    
359     Diese beiden Widgets werden in einem (nicht sehr fiktiven) Go-Programm
360     benutzt um ein Spiel darzustellen. Der erste Aufruf von C<state>
361     sagt: Beim Widget vom Typ C<game::window> (ein willkürlicher Name) soll
362     die Property C<window_size> von einer Session in die nächste Übertragen
363     werden. Falls keine Sessiondaten existieren, nimm als Default C<[600,
364     500]>. Der zweite Aufruf macht das gleiche für die C<Position>-Property
365     des C<Gtk2::HPaned>-Widgets.
366    
367     Beides Zusammen sorgt dafür, daß neue Spielfenster in der gleichen
368     Größe erscheinen wie bei der letzten Benutzung und daß die horizontale
369     Unterteiling (links Spielbrett, rechts Chat-Bereich) ebenfalls erhalten
370     bleibt.
371    
372     In der Realität benutze ich eine etwas erweiterte C<state>-Funktion mit
373     einem C<$instance>-Argument: manche Benutzer möchten z.B. verschiedene
374     Chat-Räume in verschieden großen Fenstern darstellen. Das zusätzliche
375     Argument dient der Unterscheidung: Wird ein neuer Raum betreten, werden
376     die Werte des Raum-Typs benutzt, wird ein bekannter Raum betreten, werden
377     dessen bekannte Werte benutzt.
378    
379     Die Funktion liest übrigens nur Werte aus den Sessiondaten C<$state> aus,
380     aber irgendwie müssen sie auch dort abgelegt werden. Dies geschieht in
381     meinen Programmen meistens durch Benutzeraufforderung: der Benutzer stellt
382     sein gewünschtes Layout zusammen und drückt dann C<Layout Speichern> o.ä.,
383     worauf dann folgende Funktion aufgerufen wird.
384    
385     sub save_state {
386     for (grep $_, values %widget) {
387     my ($widget, $class, $attr) = @$_;
388    
389     next unless $widget; # widget schon tot...
390     $widget->realize if $widget->can ("realize");
391    
392     while (my ($k, $v) = each %$attr) {
393    
394     $state->{$class}{$k} =
395     $get{$k} ? $get{$k}->($widget) : $widget->get ($k);
396     }
397     }
398    
399     Storable::nstore $state, "session.dat";
400     }
401    
402     Sie geht alle Widgets durch, die mit C<state> behandelt wurden, prüft, ob
403     sie noch existieren, sorgt (mit C<realize>) dafür, daß die Eigenschaften
404     auch mit sinnvollen Werten gefüllt sind, und speichert dann die
405     entsprechenden Eigenschaften in C<$state>.
406    
407     =head2 Beispiel: Rapid Application Development mit Glade - mein Weg
408    
409     Ich will es nicht verschweigen: Ich I<HASSE> GUI-Programmierung. Nichts
410     ist langweiliger bzw. nerviger, als Dialogboxen zusammenzustöpseln oder
411     Widgets in der Hierarchie zu verschieben.
412    
413     Glücklicherweise gibt es RAD-Tools, mit denen man sich seine Applikation
414     zusammenklicken kann. Was mich an RAD-Tools allerdings stört ist ihre
415     Starrheit: meistens wollen sie gleich den Quelltext schreiben, inklusive
416     des Hauptprogramms. Und häufig ist es schwierig, generelle Klassen zu
417     definieren, z.B. ein Chat-Room-Widget, von dem es zur Laufzeit beliebig
418     viele geben kann.
419    
420     Auch I<Glade>, ein (das!) Gtk+ und Gtk+2 RAD-Tool, ist keine Ausnahme
421     davon. Zum Glück kann man Glade auch etwas anders zum Entwickeln benutzen,
422     und diesen anderen Weg (ich kenne niemanden, der Glade so benutzt), möchte
423     ich hier beschreiben.
424    
425     Zuallererst ist es notwendig, die Widget oder die UI in Glade zu
426     erstellen und als GladeXML-Datei zu speichern. Z.B. habe ich für
427     ein Bilder-Anzeige-Programm (Gtk2::CV, reiner Beta-Code) einen
428     "Ausdrucken"-Dialog erstellt:
429    
430     =for latex
431     \begin{center}\includegraphics{freenet1.png}\end{center}
432    
433     Die Beschreibung ist in der XML-Datei C<cv.glade> gespeichert. Darin habe
434     ich den einzelnen Widgets Namen gegeben, z.B. heißt das Dialogfenster
435     C<PrintDialog>, das Option-Menü zum Auswählen der Papiergröße C<papersize>
436     usw.
437    
438     Den ganzen Dialog kapsele ich in einem Perl-Modul namens
439     C<Gtk2::CV::PrintDialog> ab, mit insgesamt 70 Zeilen und zwei Methoden.
440     Die kürzeste davon benutzt ein anderes Modul C<Gtk2::CV::PostScript>
441     zum Ausdrucken und ist völlig uninteressant :) Die längste ist die
442     C<new>-Methode, die ein neues PrintDialog-Widget erzeugt. Zuerst der
443     Standardkopf:
444    
445     use Gtk2;
446     use Gtk2::GladeXML;
447     # uvm.
448    
449     sub new {
450     my $class = shift;
451     my $self = bless { @_ }, $class;
452    
453     Als nächstes wird die GladeXML-Datei geladen:
454    
455     $self->{dialog} = my $d = new Gtk2::GladeXML ".../cv.glade", "PrintDialog";
456    
457     Mit C<PrintDialog> wird ein Teilbaum aus dem Widget-Baum geladen, und zwar
458     der mit dem C<PrintDialog>-Namen. So kann man viele verschiedene Dialoge
459     in einer Datei ablegen. Das Laden ist nicht unbedingt eine schnelle
460     Angelegenheit, ist aber in den meisten Fällen flott genug, um bei jedem
461     Aufruf von neuem gemacht zu werden (und man hat sowieso keine Wahl :)
462    
463     Das Ergebnis ist I<kein> Widget, sondern ein C<Gtk2::GladeXML>-Objekt, das
464     die Methode C<get_widget> besitzt, mit der man anhand des Namens einzelne
465     Widgets "herausgreifen" kann.
466    
467     Damit fülle ich den Dialog mit Leben:
468    
469     $d->get_widget ("destination")->set (text => $ENV{CV_PRINT_DESTINATION} || "| lpr");
470    
471     my $menu = $d->get_widget ("papersize")->get_menu;
472     for (Gtk2::CV::PostScript->papersizes) {
473     my ($code, $name, $w, $h) = @$_;
474     $menu->append (my $item = new Gtk2::MenuItem $name);
475     $item->set_name ($code);
476     }
477     $menu->show_all;
478     $d->get_widget ("papersize")->set_history (0);
479    
480     $d->get_widget ("PrintDialog")->signal_connect (close => sub {
481     $_[0]->destroy;
482     });
483     $d->get_widget ("PrintDialog")->signal_connect (response => sub {
484     if ($_[1] eq "ok") {
485     $self->print (
486     size => (Gtk2::CV::PostScript->papersizes)
487     [$d->get_widget ("papersize")->get_history],
488     margin => $d->get_widget ("margin")->get_value,
489     ...
490     destination => $d->get_widget ("destination")->get ("text"),
491     binary => $d->get_widget ("encoding_binary")->get ("active"),
492     );
493     }
494     $_[0]->destroy;
495     });
496    
497     return $self; # Ende
498     }
499    
500     Jetzt wird klar, warum das Ding C<$d> heißt und nicht einen längeren Namen trägt.
501    
502     Wer Das GladeXML-Modul kennt, weiß, daß es noch viel "einfacher" geht,
503     z.B. mit C<signal_autoconnect_from_package>. Leider weiß man in den
504     Callbacks, die diese Methode mit den Widgets verbindet, nichts mehr über
505     das ursprüngliche C<PrintDialog>-Objekt, so daß sie mir recht nutzlos
506     erscheint, wenn man nicht alles in globalen Variablen ablegen will (was
507     häufig der Fall ist).
508    
509     Daher habe ich die Funktion C<signal_autoconnect_all> geschrieben. Sie
510     geht einen etwas anderen Weg und erlaubt es, die Signal-Callbacks als
511     Closures anzugeben. Damit wäre das Namensraum-Problem gelöst. Leider
512     muss man dazu jedem Signal-Handler einen Namen geben, und das ist so
513     umständlich, daß ich die Funktion selbst nie benutzt habe und es einfach
514     "per Hand" Anhand der Widget-Namen mache.
515    
516     Dies alles heißt nicht, daß man es nicht einfacher anders besser machen
517     könnte. Es ist einfach "mein Weg", Glade zu benutzen. Und wenn ich noch
518     etwas darüber nachdenke, muß ich sagen, daß es mit Glade nicht wirklich
519     einfacher ist, Widgets umzustellen oder GUIs zu designen.
520    
521     *seufz*.
522    
523 root 1.1
524     =head1 Teil 2 - Gtk+ als solide Grundlage für Eigenentwicklungen
525    
526 root 1.8 #TODO
527    
528 root 1.1 =head2 Perl-Objekte vs. Glib-Objekte
529 root 1.8
530    
531 root 1.3
532 root 1.7 =head3 Die Perl-Methode
533 root 1.1
534 root 1.9 #TODO
535    
536 root 1.7 =head3 Die unsaubere Glib-Methode
537 root 1.1
538 root 1.9 #TODO
539    
540 root 1.7 =head3 Die saubere Glib-Methode
541 root 1.1
542 root 1.9 #TODO
543    
544     #TODO
545 root 1.1
546 root 1.7 =head2 Objekte aus anderen Sprachen nutzen
547 root 1.1
548 root 1.9 #TODO
549    
550 root 1.7 =head1 Verweise
551 root 1.1
552 root 1.7 =over 4
553 root 1.1
554 root 1.7 =item http://www.gtk.org/
555 root 1.1
556 root 1.9 Die Dokumentation zu Gtk+, Glib usw.
557 root 1.1
558 root 1.7 =item apt-get install devhelp-book-gtk2 # oder devhelp-books
559 root 1.1
560 root 1.7 Installiert unter debian I<devhelp>, einen inetraktiven Help-Browser und
561     das Gtk2-Buch (dazu gehört auch GObject, Glib-Doku uvm.). Sehr hilfreich
562     beim Programmieren.
563 root 1.9
564     =item Gtk2::PodViewer, Gtk2::GoBoard, Gtk2::CV
565    
566     Verschiedene Module, die Gtk2-Widgets implementieren.
567 root 1.1
568 root 1.7 =back
569 root 1.1
570