Verwendung FOX Toolkit
Free Objects for X(FOX) ist ein
cross-platform GUI Toolkit, der vom Jeroen
van der Zijp etwickelt wurde. In Vergleich
zu Tk und GTK+ ist FOX ein ziemlich junger
Werkzeug, aber mit der Zeit gewinnt er
unter Softwareentwicklern mehr an
Beliebtheit. FOX wurde ursprünglich für
UNIX und Linux geschrieben und später auf
andrere Betriebsysteme(Windows und MacOS)
übertragen. FXRuby ist ein Ruby
Erweiterungsmodul, das eine Schnittstelle
zwischen FOX und einem Ruby Programm
anbietet. Das Modul wurde vom Lyle Johnson
entwickelt und kann von Homeseite http:://fxruby.sourceforge.net
heruntergeladen werden.
Installation
Die Voraussetzung für die
Programmierung mit FXRuby ist eine
arbeitsfähige FOX-Umgebung. Wenn Sie
Standard-Rubyinstllation fürs Windows
verwenden(von der Pragmatic Programmer's
Homeseite), ist die Wahrscheinlichkeit,
dass das Modul schon mit Rubyinstallation
mitinstalliet wurde, groß. Sie können aber
eine kompatible schon vorbereitete
Binary-Distribution des FXRuby Moduls von
der FXRuby Homeseite herunterladen. Der
Vorteil dieses Pakets ist, dass die
"shared" Bibliothek in dieser Distribution
schon ein FOX Bibliothek enthält, so dass
man nach dem Downloaden und dem
Installieren der Distribution in der Lage
ist, mit dem Programmieren anzufangen und
besoderes in der erster Stelle sich das
Ergebnis anzuzeigen. Man braucht also keine
Extrainstallation von FOX.
Wenn Sie eine andere
Ruby-Version benutzen(nicht für Windows),
werden Sie sich höchstwahrscheinlich etwas
mehr anstrengen. Im Gegensatz zu Tk und
GTK+ beinhaltet keine Linux-Distributionen
ein Standard-Installation Paket von FOX,
was sich allerdings mit der Zeit ändern
wird. Also Sie müssen sich FOX downloaden,
kompilieren und anschließend installieren.
Den Sourcecode von FOX kann man sich von
der FOX Homeseite herunterladen(www.fox-toolkit.org/).
Eine Installationsanweisung sollte dabei
sein. Für Linux und Unix-Derivaten wird der
Prozess der Instllation bekannt vorkommen:
configure,
make und make
install. Sobald man eine
funktonsfähige FOX-Installation hat, kann
man mit dem FXRuby-Erweiterungsmodul
beginnen. Der Installtionsprozess für
FXRuby beginnt mit der Konfiguration:
ruby setup.rb
config
Dann ruft man die Installtion
selbst:
ruby setup.rb
setup
Erst wenn der Buildprozess
beendet ist, kann man FXRuby komplett
installieren:
ruby setup.rb
install
Um mehr die Information über
den Installationsprozess zu bekommen,
schlagen Sie in der FXRuby Dokumenation
nach.
FXRuby Basis
FXRuby's API(Application
Programming Interface)-Schnittstelle folgt
genau der FOX's C++ API und meistens werden
Sie die Standard FOX-Klasse Dokumentation
verwenden, um FXRuby Klassehierarchie und
Schinttstelle zu lernen. Alle FXRuby
Klassen , Methoden un Konstanten sind in
dem Single-Ruby Modul, benannt als
Fox untergebracht und das
meistens von FXRuby wurde im C++
Erweiterungsmodul implementiert, dessen
Name fox ist. Ein kleines
FXRuby Programm würde so aussehen:
require
'fox'
include Fox
application = FXApp.new("Hello",
"FoxTest")
application.init(ARGV)
main = FXMainWindow.new(application,
"Hello", nil, nil, DECOR_ALL)
FXButton.new(main, "&Hello
World!", nil, application,
FXApp::ID_QUIT)
application.create()
main.show(PLACEMENT_SCREEN)
application.run()
Das Programm lädt das
Fox Modul bei erforderlicher
fox Feature. Trotz der
Tatsache, dass alle FXRuby Klasse in dem
entsprechenden Namensraum vom
Fox Modul zu finden sind,
beginnt der Klassenname mit FX
Prefix, um sozusagen eine Diskrepanz mit
andrenen Klasssennamen zu vermeiden. Und
das ist aus dem Grund, dass viele FXRuby
Programms können sicher den Inhalt des
Fox Modules direkt in globalen
Namensraum verwenden(include
Fox)
Bevor wir uns mit der Analyse
dieses kleines Programms beginnen, füge ein
paar Worte dazu, die im Originalartikel
nicht zu finden sind. Also dieses kleines
Programm kann man statt normalen
Dateinamenerweiterung .rb die
Erweiterung .rbw verwenden.
Das ist die übliche Erweiterung für
FXRuby-Applikationen Welche Vorteile bringt
das uns? Unter Windows kann man einfach auf
die Datei doppelklicken, dabei wird keine
Eingabeaufforderung geöffnet, die da für
Ein- und Ausgabe bereitsteht, sondern wird
das Programm wie üblich gestartet. Der
"Nachteil" dieses Vorgehens ist es, dass
man dabei alle Fehlermeldungen verloren
gehen.
Die Applikation beginnt mit der
Erzeugung eines FXApp
Objektes. Bei seiner Erzeugung mit
new werden zwei
Zeichenketten(stings) als Argumente
übergeben: ein interner Name für
FOX-Anwendung(hier einfach "Hello") und ein
so gennanter vendor key,
welcher die Art oder den Hersteller der
Anwendung(hier "FoxTest") beschreibt. Von
allen Toolkits, die wir unter der Lupe
nehmen, ist FOX der Einzigste, der eine
explizite Erzeugung und Verweisung auf
application Objekt braucht,
welches als eine Art der Quelle für globale
Programmenresoursen(wie Grundapplikation's
Farben, Schriften und etc.) Das ist auch im
Wesentlichen für die Verwaltung des
Ereignisschleife(event loop)
verantwortlich, wie wir am Ende sehen
werden.
Der nächste Schritt ist das
Initialisieren des Programmes. Wir rufen
die init Methode auf, die zu
unserem Anwendung's Objekt gehört und
übergeben in der Kommandozeile ein Argument
und zwar Ruby's ARGV Array,
welches für FOX sinnvolle Optionen
übergibt. Zum Beispiel, um FOX's
tracing(spur) Output zu aktivieren, kann
man in der Kommandozeile die
tracelevel Option
verwenden:
ruby hello.rb -tracelevel
301
Um mehr Information darüber zu
bekommen, schlagen Sie bitte in der FOX
Dokumentaion.
An dieser Stelle sind wir
endlich dazu gekommen, unseren ersten
Widget zu erzeugen. Das
Hauptfenster(bennant main) ist
eine Instanz von der
Fox::FXMainWindow Klasse, die
new Methode erwartet eine
Referenz zu Applikation's Objekt, das ist
zuvor erzeugte FOX-Anwendung, den
Fenstertitel und auch drei Optionen, die
das Aussehen des Fensters beeinflussen.
Der nächste Widget ist ein
Button(also eine Instanz von
Fox::FXButton), und wurde als ein Kind des
Hauptfensters erzeugt. Dieser Button zeigt
uns eine Zeichenkette "Hello World!" und
die erste Buchstabe("H") wird
untergestrichen, weil wir ein
"Ampersand"-Zeichen("&") vor der
Buchstabe plaziert haben. Das ist ein
spezieller Signal, das zum
FXButton Widget gesendet wird,
um den sogenannter "Schortkey" in diesem
Fall Strg+H zu verwenden,
damit kann man den gleichen Effekt
erreichen, wenn man einfach direkt auf den
Button klickt. Der vierte und fünfte
Argumente von der new Methode
sind wichtig, und zwar in Bezug, wie FOX
die Ereignisse verarbeitet. Also der vierte
Argument ist ein Zielobjekt(eine Instanz
von FXApp oder eine von seiner Subklasse),
das eine Nachricht bekommt, und schließlich
der fünfte Argument, der als
"Nachrichtenbezeichner" (message
identifier) da ist.In unserem Fall ist
"application"(das Programm selbst) ein
"Nachrichtenziel" für den Button, und wenn
man darauf klickt, werden, bzw. wird,
Ereignisse generiert und als ein Ergebnis
an das Programm geschickt. Der
Nachichtenbezeichner dient zur
Unterscheidung zwischen ähnlichen aber
verschiedenen Nachrichten, welche das
Zielobjekt empfangen könnte; irgendein
Objekt kann als "Nachrichtentziel" für
mehrere Widgets sein.
Die serverseitige(gemeint wird
hier,dass FOX ursprünglich für
X-Server-Client Applikationen geschafft
worden war) Ressourcen, wie Fenster,
Schriftarten und Cursors, werden während
des Aufrufes der create
Methode erzeugt. Dass der FOX zwischen der
Darstellung von klientseitgen Objekten(so
wie seine Instanzvariablen) und
serverseitigen Ressourcen, die mit ihren
Objekten verbunden sind, unterscheidet,
macht FOX einzigartig. Eins wenn Fenster's
und andere Ressourcen erzeugt worden sind,
wird das Hauptfenster zentriert und danach
starten wir Hauptereignisschleife (main
event loop) mit der Hilfer der
run Methode.
Zielobjekte und Nachrichten
FOX's Ereignis Model basiert
auf der Idee der Sendung
messages von einem
Applikationsobjekt zum anderen, das als
sein Ziel da ist, when etwas geschieht.
Also das ist Ihr Job als Programmier, sich
zu entscheiden, wie das Zielobjekt auf eine
Nahricht(message) antwortet. Da dieses
"Ziel-Nachricht" System
"innewohnend"(inherently) und
"bidirectional" ist, bringt ein Teil des
Antwortes mit sich häufig eine
back Nachricht zum
Originalsender mit.
Jeder Widget in ihrem Programm
hat eine Fähigkeit zum Senden einer
Nachricht, aber manche Nachrichten sind
mehr "bedeutunsvoller" als andere; zum
Beispiel Sie möchten sich wahrscheinlich
ein Programm, das sich in irgendeiner Art
und Weise reagiert, when der Anwender einen
neuen Text in einem Textfeld eintippt, oder
sich einen Eintrag in einer
baumstrukturigen Liste auswählt. Sie würden
ein Zielobjekt, das Nachrichten
entgegenimmt, für diese Widgets festlegen,
an denen Sie möchten die wichtige
Nachrichten senden. Fast jeder von FOX's
Widgets erlaubt uns in seiner Konstruktion,
seine Zielobjekte festzulegen. Zum Beispiel
um eine neue Instanz von der
FXList Klasse und ihres
anObject als Ziel festzulegen,
würden so schreiben:
myList =
FXList.new(parent, numItems, anObject,
...)
Sie können auch, wenn man so
braucht, das Ziel, nachdem der Widget schon
erzeugt wurde, ändern, dabei wird eine
setTarget Methode
aufgerufen:
myList.setTarget(anotherObject)
Jede Nachricht hat ein
sogenannter Typ type, was auf
seine Wichtigkeit hinweist. Manche
Nachrichten stellen low-level Ereignisse
dar, die vom Windows System generiert
wurden.; zum Beispiel die
SEL_LEFTBUTTONPRESS Nachricht
wird gesendet, wenn die linke Maustaste
gedrückt wird, während die
SEL_LEFTBUTTONRELEASE
Nachricht gesendet wird, wenn der glecher
Button released wird. Andere Nachrichten
werden von FOX generiert und weisen mehr
auf die Ereignisse,die von Benutezern
ausgelöst sind, hin, wie zum Beispiel das
Löschen eines Textes aus dem Textwidget
oder das Auswählen einer Zelle in einer
Tabelle. Die Nachrichten Typs sind einfach
ganze Zahlen(integer)(in Gegensatz zur
Zeinchenketten(Strings),di in Ruby/Tk
Ereignissen oder Ruby/GTK Signalen
verwendet werden), aber Sie müssen immer
eine sybolische Konstante mit dem Namen in
der Form wie SEL_name
verwenden.
Ein Nachrichtentyp, den Sie
häufig in FOX's Programmen treffen würden
ist die SEL_COMMAND Nachricht.
In Allgemeinen wird damit gemeint, dass der
Widget nur sein Hauptaktion erledigt, es
klingt ein wenig komplizierter, aber lassen
wir uns das an einem Beispiel erläutern;
ein FXButton Widget wird eine
SEL_COMMAND zu seinem
Zeilobjekt aussenden, nachdem der User auf
den Button klickt, während ein FXTextField
Widget wird eine SEL_COMMAND
aussenden, wenn der User die
Enter Taste im Textfeld
betätigt, oder einfach außer des Textfeldes
klickt.
Es is schon eine allgemeine
Gewohnheit in FOX Applikationen, ein Objekt
als ein Ziel mehreren Widget's Nachrichten
zu machen. Zum Beispiel, ihres Programm
könnte mehrere Menübuttons enthalten, für
solche Operationen wie "Öffnen Datei",
"Speichern Datei", oder "Drücken Datei",
und alle diese Button senden ihre
SEL_COMMAND Nachrichten zu
einem Zielobjekt. Aber Sie werden sich
fragen, wie dieser Zielobjekt in Zustande
ist, zwischen ähnlichen Nachrichten von
verschiedenen Widgets zu unterscheiden. Sie
denken, wenn das Zielobjekt eine
SEL_COMMAND Nachricht
empfängt, wie das Zielobjekt
herausgefunden, welcher Button eine
Nachricht geschickt hat? Die Antwort ist
einfach, weil jede Nachricht ein
Nachrichten-ID(indentifier)
enthält(zusätzlich zu seinem Typ), damit
wird zusätziliche Information über der
Quelle und der Wichtigkeit der Nachricht
erreicht.
Das Nachrichten-ID ist einfach
eine ganze Zahl(integer), gewöhnlich als
eine symbolische Konstante dargestellt, die
beim "Empfänger" der Nachricht definiert
wurde. Eine Klasse definiert verschiedene
Nachrichten-ID und, da FOX ein
objekt-orientierender Toolkit ist, ein
Objekt versteht auch alle Nachrichten-ID,
die bei der Vorfahrklasse festgelegt
wurden. Zum Beispiel, da FXButton eine
Subklasse von FXLabel ist, erbt er die
Nachrichten-ID, die bei FXLabel und
FXLabel's Basisklassen definiert
wurden.
Um für ein Zielobjekt eine
Nachricht zu empfangen und danach zu
antworten, muss man
Nahrichtenbehandlungsfunktionen für
verschiedene Nachrichtentypen und
Nachrichten-ID registrieren. Diese
Zuordnung erfolgt in der
initialize Methode unserer
definierten Klasse durch die Verwendung
FXMAPFUNC Methode erledigt, damit werden
der Nachrichtentyp und die Nachrichten-ID
mit dem Namen der Instanzmethode für diese
Klasse verbunden. Zum Beispiel wenn wir
sozusagen SEL_COMMAND
Nachrichtentyp mit
ID_OPEN_FILE Nachrichten-ID
verwenden wollen, und benutzen
onOpenFile Methode um diese
Nachricht zuhandhaben, würde wir so in der
initialize Methode
schreiben:
FXMAPFUNC(SEL_COMMAND,
ID_OPEN_FILE, "onOpenFile")
Die Funktionen, die die
Nachrichten abwickeln, wie unsere
onOpenFile Methode, haben
immer drei Argumente:
def onOpenFile(sender,
sel, ptr)
...irgendwelcher Code...
end
Das erste
Argument(sender) ist das
FOX-Objekt, das die Nachricht versendet(der
Sender), Eis ist oft praktisch zu wissen,
wer eine Nachricht versendet hat, vor
allem, wenn ein Teil der Antwort eine
Nachricht back mit sich
bringt,um zum ursprünglichen Sender etwas
mitzuteilen. Das zweite Argument ist der
sogennte Selektor und ist
eingentlich eine ganze Zahl,
welcher(Selektor) die beide Attribute
Nachrichtentyp und Nachrichten-ID
verschlüsselt. When es erforderlich ist,
können Sie den Nachrichtentyp und die
Nachrichten-ID aus dem Selektor entnehmen,
dabei muss man die SELTYPE und SELID
Funktionen verwenden:
def onOpenFile(sender,
sel, ptr)
hfkhfmessageType =
SELTYPE(sel)
hfkhfmessageId =
SELID(sel)
hfkhf...irgendwelcher
Coder...
end
Das letzte Argument, das zur
Nachrichtbehandlung weitergeleitet wird,
ist ptr; es enthält
zusätzliche Daten; der Typ der Daten hängt
von Sender- und Nachrichttypen ab. Zum
Beispiel, when ein FXTextField Widget eine
SEL_COMMAND Nachricht zu einem
Ziel aussendet, die Daten, die mit der
Nachricht mitgesendet werden, beinhalten
eine Zeichenkette(string),die nicht alles
Anderes ist, als ein Inhalt des Texfeldes.
When ein FXColorWell Widget zum seinem Ziel
SEL_COMMAND Nachricht
aussendet, wie auch immer, die
Nachrichtendaten sind ein ganze Zahl, die
auf die Farbe der aktuellen Farbenquelle
hinweist. Unseres Beispielprogramm hat
einige Arten der Nachrichten, die innerhab
des Programm verwendet werden, aber um
komplete Information darüber zu erlangen,
schlagen Sie auf der FOX Homeseite
nach.
Arbeitsweise mit FOX's Layout
Manager
Die Auswahl von Fox's Layout
Manager ist ähnlich zu der, die wir für Tk
und GTK+ hatten, es gibt dabei ein wenig
Unterschiede. Wir werden uns lediglich auf
vier Arten des Layout Manager's
konzentrieren und zwar: FXPacker,
FXHorizontalFrame, FXVerticalFrame und
FXMatrix. Wie ihre Rivalen in Tk und GTK+
sind diese Layout Manager, die am häufsten
beim GUI Programmieren verwendet werden.
Für eine Information darüber, wie andere
spezifische Layout Manager(wie FXSwitcher,
FXSplitter und FX4Splitter) benutzt werden,
müssen in der FOX Dokumentation
nachschlagen.
Wie in GTK+ sind FOX Layout
Manager selbs einfach unsichtbare Behälter
für andere Widgets. Sie sind aber nicht so
genau unsichtbar, weil Sie eine gewisse
sozusagen Kontrole darüber haben, wie zum
Beispiel die Außenränder des Behälters
gezogen werden(Frame Style), aber wir
werden uns meistens mit der Zuordnung von
Kinder-Widgets auf der Oberfläche
beschäftigen. Wie in Tk werden FOX Widgets
immer so erzeugt, dass sie dabei als erstes
Argument ihre Vater-Widget bekommen. Sie
können später einem Kind-Widget einen neuen
Elternteil zuweisen (das ist, wenn Sie ihn
von einem Vater-Widget entfernen und dem
anderen hinzufügen), aber in Gegensatz zu
Ruby/GTK kann Kind-Widget ohne den
Vaterteil nicht existieren. Auch so
ungleich verhalten sich die Fox
Kind-Widgets bei der Festlegung ihrer
Layout's Preferenzen(oder layout hints
gennant) und zwar als ein Teil ihrer
Konstruktion. Sie können ihre Lyout's
Einstellungen ändern, auch wenn sie schon
existieren. Man ruft dabei eine
setLayout Instanzmethode, aber
das ist trotzdem ein anderes Modell, als
das in Tk und GTK+ verwendet wird. Wie der
FOX Layout Manager funktioniert, ist es
einzigartige Layout's Strategie. Er braucht
die Layout's Einstellungen von jedem seiner
Kind-Widgets und danach verwendet sie, um
die Größe und Position festzusetzen.
Wir werden uns jetzt FXPacker
anschauen, weil dieser meistens von allen
Layout Manager verwendet wird und der dient
als Basisklasse für die anderen drei:
FXHorizontalFrame, FXVerticalFrame und
FXMatrix). FXPacker verwendet ungefähr die
gleiche Layout' Strategie als Tk's Packer
und Namen der Layout's Prefärenzen spiegeln
sozusagen ihre "Erbschaft" wieder. Die
new Methode für FXPacker
könnte es so aussehen:
aPacker =
FXPacker.new(parent, opts=0,
hfkhfkahkahjhkjhkjx=0,
y=0, h=0,
hfkhfkahkahjhkjhkjpl=DEFAULT_SPACING,
pr=DEFAULT_SPACING,
hfkhfkahkahjhkjhkjpt=DEFAULT_SPACING,
pb=DEFAULT_SPACING
hfkhfkahkahjhkjhkjhs=DEFAULT_SPACING,
vs=DEFAULT_SPACING)
Es mag sein, dass Sie beim
Ansehen dieses Codes den Eindruck gewinnen
können, dass der eine sehr lange
Argumentenliste hat. Bei näherer Prüfung
sollten Sie erleichtert sein, weil alles
außer den ersten Argument optional ist, das
heisst, sie haben eingentlich "default"
Werte. Genauso wenn Sie sich die
new Methode für andere Widgets
ansehen, werden Sie diesen Mustern wieder
begegnen: eine lange Argumentenliste mit
Grundwerten für die meisten Argumenten. Und
eigentlich, meistens oder alle von diesen
Argumenten können umgetauscht werden,
nachdem der Widget schon erzeugt wurde, und
dabei werden seine zusätzliche Methode
verwendet, so dass man folgende Code
schreiben kann:
aPacker =
FXPacker.new(parent, LAYOUT_EXPLICIT, 0, 0,
150, 80)
und das gleichbedeutend mit
diesen vier Zeilen des Codes:
aPacker =
FXPacker.new(parent)hfkhfkajhkjh#
annehmen der Grundwerten
aPacker.width = 150JHHGjklhjhjhjkkjljljkhjhjh#
festsetzen der Breite(in pixel)
aPacker.height = 80hfkhfkahjhkhkkjlkahjhkjh#
festsetzen der Höhe(in pixel)
aPacker.layoutHints =
LAYOUT_EXPLICIThfkd# kontrolliert
die Aktualität der Breite und Höhe
enforced!
Nun müssen wir mehr über die
Bedeutung dieser Argumente sagen. Lassen
wir uns kurz das zweite
Argument(opts) stehen und
betrachten wir restlichen Argumente. Die
x, y, w und h
sind ganze Zahlen, die auf die Position,
wobei wird das "vaterliche"
Koordinatesystem verwendet, und die Größe
für den Widget hindeuten. Diese Argumente
kann man ignorieren, wenn wir nicht auch
die entsprechende Layoutshinweise
festsetzen (LAYOUT_FIX_X,
LAYOUT_FIX_Y,
LAYOUT_FIX_WIDTH oder
LAYOUT_FIX_HEIGHT). Diese
Argumente zeigen sich in beinahe jeder
new Methode eines Widgets, und
sie sind übliche Argumente für
FXPacker.new Widgets. Im
Codebeispiel, den wir gerade besprochen
haben, haben wir die "shortcut option"
LAYOUT_EXPLICIT verwendet, die
einfach die oben erwähnte Argumente
vereinigt; das hat Sinn, weil man ein
Layout mit festgelegten Positionen und
Größe verwendet wird, alles, dass wir
brauchen, diese Option zu setzen. Die
nächsten vier Argumenten(pl=DEFAULT...) für
FXPacker.new sind die innere
Abstände links, rechts, oben und unten vom
Rand in pixel. Wie schon erwähnt wurde,
bezieht sich das auf den Extra-Raum, der um
die innere Rände des Behälters plaziert
wird, und wenn der Layout in ihrem Programm
besonders aussehen sollte, kann man extra
einen Raum an den Ränden verschaffen, um zu
versuchen, die Werte vom Grundwert
DEFAULT_SPACING(ein
Konstantwert gleich 4 pixel) abweichen zu
lassen. Die letzte zwei Argumente für den
Widget deuten auf einen horizontalen und
vertikallen Abstand in pixel hin, welcher
zwischen den Kind-Widgets ist. Wie die oben
erwähnte interne Abstände(padding), haben
diese zwei Argumente Grundwerte jewels vier
pixel. Nun lassen wir uns zum zweiten
Argument zurückkehren und zwar der Option
opts Die meisten FOX's
new Methoden verwenden diesen
Wert. Damit werden verschiedene
"bitartige-flags" ein-, oder ausgeschaltet.
Diese "flags" beschreiben das Erscheinen
und das Verhalten von Widgets. Wir haben
schon bereits gesehen, dass manche von
diesen "flags" Layouthinweise beinhalten,
die Hinweise vom Kind-Widget zum seinen
Vater-Widget, und auch darüber , wie es
während der Layoutprozedur behandelt werden
sollte. Zusätzlich zum
LAYOUT_FIX Hinweis gibt's
auch:
LAYOUT_SIDE_LEFT,
LAYOUT_SIDE_RIGHT und
LAYOUT_SIDE_TOP,
LAYOUT_SIDE_BOTTOM die deuten
darauf hin, welcher(n) Seite(n) gegenüber
die Kind-Widgets gepackt werden
können;
LAYOUT_FILL_X,
LAYOUT_CENTER_X und
LAYOUT_FILL_Y,
LAYOUT_CENTER_Y weisen darauf
hin, wie der Kind-Widget sich verhalten
würde, sich ausdehnen und damit den ganzen
Raum füllen oder sich lediglich im Zentrum
platzieren.
Es gibt noch zwei spezifischen
Optionen oder sozusagen "packing styles":
PACK_UNIFORM_WIDTH und PACK_UNIFORM_HEIGHT.
Ähnlich wie "homogeneous" Eigenschaften des
Ruby/GTK Layout Managers, erzwingen
sozusagen diese zwei Optionen den Layout
Manager für die Kind-Widgets die gleiche
Breite oder, bzw. und Höhe. Diese zwei
Optionen sind auf alle Kind-Widgets
anwendbar und dabei überschreiben sie alle
andere Präferenzen (einschließlich
LAYOUT_FIX_WIDTH und LAYOUT_FIX_HEIGHT).
Diese Optionen sind mehr für die anderene
Layout Manager geeignet, die von FXPacker
abgeleitet sind, aber man kann sie trotzdem
generell verwenden, wenn man weiss, was man
tut.
Nun betrachten wir die nächste
Layout Manager und zwar
FXHorizontalFrame und
FXVerticalFrame zusammen, weil
sie ähnlich sind. Wie Sie schon vermuten,
ordnen diese beide iher Kind-Widgets in der
horizontaler, bzw. vertikaler Richtung an.
Die new Methode für
FXHorizontalFrame sieht so
aus:
aHorizFrame =
FXHorizontalFrame.new(parent, opts=0,
enjoyyourselfenjoyyourselfenjoyyourselfex=0,
y=0, w=0, h=0,
enjoyyourselfenjoyyourselfenjoyyourselfepl=DEFAULT_SPACING,
enjoyyourselfenjoyyourselfenjoyyourselfepr=DEFAULT_SPACING,
enjoyyourselfenjoyyourselfenjoyyourselfept=DEFAULT_SPACING,
enjoyyourselfenjoyyourselfenjoyyourselfepb=DEFAULT_SPACING,
enjoyyourselfenjoyyourselfenjoyyourselfehs=DEFAULT_SPACING,
enjoyyourselfenjoyyourselfenjoyyourselfevs=DEFAULT_SPACING)
Die Grundeinstellung für diesen
Layout Manager sieht es vor, die
Kind-Widgets horizontal von links nach
rechts anzuordnen, in dieser Reihenfolge
werden sie hinzugefügt. Wenn es
erforderlich ist, dass ein bestimmter
Kind-Widget an der rechten Seite des Raumes
angeordnet werden soll, gibt man einfach
den LAYOUT_RIGHT
Layoutshinweis über. Vertikale Frames
ordnen ihre Kind-Widgets von oben nach
unten und zwar "defaultmäßig, mit dem
LAYOUT_BOTTOM Hinweis kann man
dieses Vorgehen verändern. Der letzte
Layout Manager, den wir besprechen, ist
FXMatrix, welcher seine Kind-Widgets in
Zeilen und Spalten anordnet. Die
new Methode für FXMatrix
ist:
aMatrix =
FXMatrix.new(parent, size=1, opts=0,
enjoyyourselfenjoyyourselfx=0,
y=0, w=0, h=0,
enjoyyourselfenjoyyourselfpl=DEFAULT_SPACING,
pr=DEFAULT_SPACING,
enjoyyourselfenjoyyourselfpt=DEFAULT_SPACING,
pb=DEFAULT_SPACING,
enjoyyourselfenjoyyourselfhs=DEFAULT_SPACING,
vs=DEFAULT_SPACING)
Der Widget
FXMatrix hat zwei wichtige
Optionen MATRIX_BY_ROWS und
MATRIX_BY_COLUMNS Sie weisen
darauf hin, wie das size
Argument für den FXMatrix.new
interpretiert werden kann. Für die
MATRIX_BY_ROWS, das ist die
Grudneinstellung, zeigt die
size die Anzahl der Zeilen;
die Anzahl der Spalten ist schließlich die
gesamte Anzahl der Kind-Widgets für den
Matrix. In unserem Beispiel bedeutet es,
dass der erste Kind-Widget zur ersten Reihe
hinzugefügt wird, der zweite zur zweiten
Reihe und so weiter, wobei alle
Kind-Widgets sich in einer Spalte befinden.
In anderem Fall wird die Option
MATRIX_BY_COLUMNS verwendet,
wobei das Argument size die
Anzahl der Spalten zeigt und die Anzahl der
Reihen wird unterschiedlich.
FOX Beispielprogramm
Der folgende Code zeigt den
kompletten Sourcecode von unserem
Beispielprogramm. Den können Sie auch
herunterladen fox-xmlviewer
#!/bin/env ruby
-w
require "fox"
require "fox/responder"
require
"nqxml/treeparser"
include Fox
class XMLViewer <
FXMainWindow
enjinclude
Responder
enj# Define
message identifiers for this class
enjID_ABOUT,
ID_OPEN, ID_TREELIST =
enjoyenum(FXMainWindow::ID_LAST,
3)
enjdef
createMenubar
enjoymenubar
= FXMenubar.new(self,
LAYOUT_SIDE_TOP|LAYOUT_FILL_X)
enjoyfilemenu
= FXMenuPane.new(self)
enjoyFXMenuTitle.new(menubar,
"&Datei", nil, filemenu)
enjoyFXMenuCommand.new(filemenu,
enjoyyou"&Öffnen...\tCtl-O\tOpen
document file.", nil, self, ID_OPEN)
enjoyFXMenuCommand.new(filemenu,
enjoyyou"&Beenden\tCtl-Q\tQuit
the application.", nil,
enjoyyogetApp(),
FXApp::ID_QUIT, 0)
enjoyhelpmenu
= FXMenuPane.new(self)
enjoyFXMenuTitle.new(menubar,
"&Hilfe", nil, helpmenu,
LAYOUT_RIGHT)
enjoyFXMenuCommand.new(helpmenu,
enjoyyou"&Über
FOX...\t\tDisplay FOX about panel.",
enjoyyonil,
self, ID_ABOUT, 0)
enjend
enjdef
createTreeList
enjoylistFrame =
FXVerticalFrame.new(@splitter,
enjoyyuLAYOUT_FILL_X|LAYOUT_FILL_Y|FRAME_SUNKEN|FRAME_THICK)
enjoy@treeList =
FXTreeList.new(listFrame, 0, self,
ID_TREELIST,
enjoyyu(LAYOUT_FILL_X|LAYOUT_FILL_Y|
enjoyyuTREELIST_SHOWS_LINES|TREELIST_SHOWS_BOXES|TREELIST_ROOT_BOXES))
enjend
enjdef
createAttributesTable
enjoytableFrame =
FXVerticalFrame.new(@splitter,
enjoyyuLAYOUT_FILL_X|LAYOUT_FILL_Y|FRAME_SUNKEN|FRAME_THICK)
enjoy@attributesTable
= FXTable.new(tableFrame, 5, 2, nil,
0,
enjoyyu(TABLE_COL_SIZABLE|TABLE_ROW_SIZABLE|
enjoyyuFRAME_SUNKEN|FRAME_THICK|LAYOUT_FILL_X|LAYOUT_FILL_Y))
enjend
enjdef
initialize(app)
enjoy#
Initialize base class first
enjoysuper(app, "XML
Editor", nil, nil, DECOR_ALL, 0, 0, 800,
600)
enjoy# Set up
the message map
enjoyFXMAPFUNC(SEL_COMMAND,
ID_ABOUT, "onCmdAbout")
enjoyFXMAPFUNC(SEL_COMMAND,
ID_OPEN, "onCmdOpen")
enjoyFXMAPFUNC(SEL_COMMAND,
ID_TREELIST, "onCmdTreeList")
enjoy# Create
the menu bar
enjoycreateMenubar
enjoy@splitter =
FXSplitter.new(self,
LAYOUT_FILL_X|LAYOUT_FILL_Y)
enjoy# Create
the tree list on the left
enjoycreateTreeList
enjoy#
Attributes table on the right
enjoycreateAttributesTable
enjoy# Make a
tool tip
enjoyFXTooltip.new(getApp(),
0)
enjend
enj# Create
and show the main window
enjdef
create
enjoysuper
enjoyshow(PLACEMENT_SCREEN)
enjend
enjdef
loadDocument(filename)
enjoy@document =
nil
enjoybegin
enjoyyu@document =
NQXML::TreeParser.new(File.new(filename)).document
enjoyrescue
NQXML::ParserError => ex
enjoyyuFXMessageBox.error(self,
MBOX_OK, "Error",
enjoyyou"Couldn't
parse XML document")
enjoyend
enjoyif
@document
enjoyyo@treeList.clearItems()
enjoyyopopulateTreeList(@document.rootNode,
nil)
enjoyend
enjend
enjdef
populateTreeList(docRootNode,
treeRootNode)
enjoyentity =
docRootNode.entity
enjoyif
entity.instance_of?(NQXML::Tag)
enjoyyotreeItem =
@treeList.addItemLast(treeRootNode,
entity.to_s, nil, nil, entity)
enjoyyodocRootNode.children.each
do |node|
enjoyyoupopulateTreeList(node,
treeItem)
enjoyyoend
enjoyelsif
entity.instance_of?(NQXML::Text) &&
entity.to_s.strip.length != 0
enjoyyotreeItem =
@treeList.addItemLast(treeRootNode,
entity.to_s, nil, nil, entity)
enjoyend
enjend
enjdef
onCmdOpen(sender, sel, ptr)
enjoydlg =
FXFileDialog.new(self, "Öffnen")
enjoydlg.setPatternList([
enjoyyo"Alle
Dateien (*)",
enjoyyo"XML
Documents (*.xml)"])
enjoyif
dlg.execute() != 0
enjoyyoloadDocument(dlg.getFilename())
enjoyend
enjoyreturn
1
enjend
enjdef
onCmdTreeList(sender, sel, treeItem)
enjoyif
treeItem
enjoyyoentity
= treeItem.getData()
enjoyyoif
entity.kind_of?(NQXML::NamedAttributes)
enjoyyoukeys
= entity.attrs.keys.sort
enjoyyou@attributesTable.setTableSize(keys.length,
2)
enjoyyoukeys.each_index
{ |row|
enjoyyous@attributesTable.setItemText(row,
0, keys[row])
enjoyyous@attributesTable.setItemText(row,
1, entity.attrs[keys[row]])
enjoyyou}
enjoyyoend
enjoyend
enjoyreturn
1
enjend
enj# About
box
enjdef
onCmdAbout(sender, sel, ptr)
enjoyFXMessageBox.information(self,
MBOX_OK, "�er XMLViewer",
enjoyyo"FXRuby
Sample Application/Beispielprogramm")
enjoyreturn
1
enjend
enend
eif $0 ==
__FILE__
enj# Make
application
enjapplication =
FXApp.new("XMLViewer", "FoxTest")
enj# Open the
display
enjapplication.init(ARGV)
enj# Make
window
enjmainWindow
= XMLViewer.new(application)
enj# Create
the application windows
enjapplication.create
enj# Run the
application
enjapplication.run
eend
Die FXRuby Version unseres
Programm beginnt mit einer Einbindung der
Module fox und
fox/responder, welche der FOX
Hauptbibliothek entsprechen und außerdem
wird dadurch erreicht, dass die Widgets
ihre Nachricht-Handler Methoden sozusagen
bei der Bibliothek registrieren können:
require "fox"
require "fox/responder"
require
"nqxml/treeparser"
include Fox
class XMLViewer <
FXMainWindow
enjinclude
Responder
enj# Define
message identifiers for this class
enjID_ABOUT,
ID_OPEN, ID_TREELIST =
enjoyenum(FXMainWindow::ID_LAST,
3)
Wie man schon sieht, brauchen
wir eine Hauptfensterklasse(XMLViewer) um
auf drei Nachricht-ID's zu reagieren:
ID_ABOUT, welche mit dem
Über... Menübefehl
zusammenhängt; ID_OPEN, welche
mit dem Öffnen Menubefehl
in der Beziehung steht; und
ID_TREELIST, welche verwendet
wird, wenn man ein Entrag in der Liste
auswählt. Um Nachricht-Handler Funktionen
für diese Klasse anzumelden, muss man auch
mix-in Responder Module
einbinden. Die enum Funktion
ist sozusagen "Helfer", die von diesem
Modul bereitgestellt wird und das baut
einfach ein Array mit ganzen Zahlen auf.
Der Array beginnt mit seinem ersten
Input(FXMainWindow) und als zweites
Argument wird die Anzahl der Nachricht-ID's
übergeben. In unserem Fall stellen wir
sicher, dass die Argumente für die
enum Funktion mit
FXMainWindow::ID_LAST beginnt,
damit erreichen wir, dass es keine
gegenseitige Störungen mit anderen
FXMainWindow's Nachricht-ID's gibt. Und das
ist eingentlich ein Standard-Vorgang für
FXRuby Applikationen. Der erste Schritt in
initialize Methode ist das
Deklarieren der
Basisklasse(FXMainWindow):
super(app, "XML Editor",
nil, nil, DECOR_ALL, 0, 0, 800,
600)
Dabei ist es wichtig, diesen
Schritt nicht zu unterlassen. Hier ist das
zweite Argument zu
FXMainWindow initialize
Methode der Titel des Fensters("XML
Editor"). Das fünfte Argument ist eine
Reihe von Optionen, die Hinweise für
Fenster's Manager beinhalten, welche
Fenster's Dekorationen(z.B. ein Titelmenü
oder eine Handhabung der Fenstergröße)
gezeigt werden könnten. In unserem Fall
wünschen wir uns alle mögliche
Dekorationen(DECOR_ALL). Die
letzte zwei Argumente setzen die
anfängliche Breite und Höhe für
Hauptfenster fest. Der nächste Schritt ist
die Zuordnung einer Nachrichten-ID zu einer
Methode:
FXMAPFUNC(SEL_COMMAND,
ID_ABOUT, enj"onCmdAbout")
eFXMAPFUNC(SEL_COMMAND,
ID_OPEN,enjoy"onCmdOpen")
eFXMAPFUNC(SEL_COMMAND,
ID_TREELIST, "onCmdTreeList")
Die FXMAPFUNC
Methode ist ein "mixed-in" aus dem
Responder Modul. Die Methode
hat drei Argumente und zwar
Nachrichten-Typ, Nachrichten-ID und den
Methodennamen. Der erste Aufruf, zum
Beispiel, gibt es bekannt, wenn
XMLViewer Objekt vom
Nachrichtentyp SEL_COMMAND
gefragt wird, wobei die Nachrichten-ID
XMLViewer::ID_ABOUT verwendet
wird, dass die onCmdAbout
Methode aufgerufen wird. Der Rest der
initialize Methode legt den
Inhalt und den Layout des Hauptfensters
fest. Die erste sozusagen interessante
Stelle in der Applikation kommt, wenn die
Menübar des Programmes erzeugt wird. Dafür
haben wir die createMenubar
Methode verwendet:
enjdef
createMenubar
enjoymenubar
= FXMenubar.new(self,
LAYOUT_SIDE_TOP|LAYOUT_FILL_X)
enjoyfilemenu
= FXMenuPane.new(self)
enjoyFXMenuTitle.new(menubar,
"&Datei", nil, filemenu)
enjoyFXMenuCommand.new(filemenu,
enjoyyou"&Öffnen...\tCtl-O\tOpen
document file.", nil, self, ID_OPEN)
enjoyFXMenuCommand.new(filemenu,
enjoyyou"&Beenden\tCtl-Q\tQuit
the application.", nil,
enjoyyogetApp(),
FXApp::ID_QUIT, 0)
enjoyhelpmenu
= FXMenuPane.new(self)
enjoyFXMenuTitle.new(menubar,
"&Hilfe", nil, helpmenu,
LAYOUT_RIGHT)
enjoyFXMenuCommand.new(helpmenu,
enjoyyou"&Über
FOX...\t\tDisplay FOX about panel.",
enjoyyonil,
self, ID_ABOUT, 0)
enjend
Ein "FXMenubar" wird als ein
horizontalorientierender Behälter, so dass
er ein oder mehrere "FXMenuTitle"- Widgets
enthalten kann. "FXMenuTitle" hat als
Argument ein Textstring, der als ein Name
für den Menütitel benutzt wird (wie
"Datei") und außerdem wird beim Anklicken
des Menütitels ein
Popup-Fenster("FXMenuPane" )eröffnet,
welches ein oder mehrere "FXMenuCommand"
widgets enthält. Der Textstring für den
Menütitel kann vorne das
"Ampersandzeichen"("&"); enthalten,
wenn das vorhanden ist, wird die erste
Buchstabe unterstrichen, was den FOX
veranlasst, den "Keybord-Beschleiniger"
einsetzen, um das Menü mit der
Tastekombination zu aktivieren. Zum
Beispiel hat "FXMenuTitle" für das
Datei Menü:
FXMenuTitle.new(menubar,
"&Datei", nil, filemenu)
den Textstring "Datei" mit "D"
unterstrichen, und wenn man die
Alt+F Tastekombination
verwendet, wird das Menü "Datei" benutzt.
So ähnlich kann der Textstring für
Menücommands spezielle Kontrollzeichen
beinhalten:
FXMenuCommand.new(filemenu,
enjoyyou"&Öffnen...\tCtl-O\tOpen
document file.", nil, self,
ID_OPEN)
Das "Ampersandzeichen" vor der
Buchastabe "Ö" in "Öffnen" legt "hot key"
für den Menübefehl; wenn das
Datei Menü schon geöffnet
ist, kann man Ö Taste
drücken um den "Öffnen..." Befehl zu
aktivieren. Die
Tabulatorzeichen("\t")
werden bei FOX als Feldseparatoren erkannt.
Das erste Feld ist der Haupttext, welcher
in "FXMenuCommand" Widget gezeigt wird. Das
zweite Feld ist ein optionaler String, der
auf di Tastekombination hindeutet, die
verwendet kann, um direkt auf den Befehl
zugreifen, nur aber wenn das Menü schon
geöffnet wurde. Und das letzte Feld ist
auch optional, welches ein Textstring
enthält, der uns einfach erklärt, was
dahinter steckt.
Obwohl wir in unserem Beispiel
keine Separatoren verwenden, ist est oft
hilfreich, ein oder mehrere horizontalen
Separatoren zu "Pulldown-Menü hinzuzufügen.
Damit kann man zusammenhängende Menübefehle
gruppieren. Um ein Separator zu
"FXMenuPane" hinzuzufügen, erzeugt man
einfach eine Instanz von der
FXMenuSeparator Klasse in der
gewünschten Position:
FXMenuSeparator.new(filemenu)
Die linke Seite des
Hauptfensters unterbringt eine
baumstrukturige Liste von XML
Dokumentknoten; das wird durch die
createTreeList erzeugt:
def
createTreeList
enjoylistFrame =
FXVerticalFrame.new(@splitter,
enjoyyuLAYOUT_FILL_X|LAYOUT_FILL_Y|FRAME_SUNKEN|FRAME_THICK)
enjoy@treeList =
FXTreeList.new(listFrame, 0, self,
ID_TREELIST,
enjoyyu(LAYOUT_FILL_X|LAYOUT_FILL_Y|
enjoyyuTREELIST_SHOWS_LINES|TREELIST_SHOWS_BOXES|TREELIST_ROOT_BOXES))
enjend
Da die FXTreeList
Klasse nicht von FXFrame
abgeleitet wird, hat man hier keine
Framestyle's Optionen gesetzt. Um nun jetzt
gut aussehende tiefliegende Kanten zu
bekommen, müssen wir den FXTreeList Widget
sozusagen umgeben, bzw. in ein von
FXFrame-abgeleiteter
Kind-Widget packen; hier werden wir
FXVerticalFrame verwenden. Die
dritte und vierte Argumente von
new Methode für den
FXTreeList Widget stellen das
Hauptfenster(self) als
Nachrichtenziel und auch deren
Nachrichten-ID und zwar
XMLViewer::ID_TREELIST. Wie
Sie sich schon bestimmt erinnern, haben wir
in der initialize Methode der
Nachrichten-ID ID_TREELIST
eine onCmdTreeList Methode
zugeordnet, also wenn
SEL_COMMAND Nachricht mit
dieser Nachrichten-ID gesendet wird,
veranlasst es, dass die
onCmdTreeList aufgerufen
wird:
enjdef
onCmdTreeList(sender, sel, treeItem)
enjoyif
treeItem
enjoyyoentity
= treeItem.getData()
enjoyyoif
entity.kind_of?(NQXML::NamedAttributes)
enjoyyoukeys
= entity.attrs.keys.sort
enjoyyou@attributesTable.setTableSize(keys.length,
2)
enjoyyoukeys.each_index
{ |row|
enjoyyous@attributesTable.setItemText(row,
0, keys[row])
enjoyyous@attributesTable.setItemText(row,
1, entity.attrs[keys[row]])
enjoyyou}
enjoyyoend
enjoyend
enjoyreturn
1
enjend
Wenn der
FXTreeList Widget den
SEL_COMMAND Befehl zu seinem
Nachrichtenziel sendet, ist die
Nachricht(das dritte Argument, das an die
"message handler methode" weitergeleitet
wird) ein Verweis auf den ausgewählten
Eintrag in der XML-Datei, wenn überhaupt.
Angenommen, dass der ausgewählte
Eintrag(als treeItem genannt)
nicht nil ist, dann empfangen
wir einen Verweis, der auf Angaben, die mit
diesem Eintrag verbunden sind, hindeutet.
Wie Sie später sehen werden, wenn wir die
populateTreeList Methode
besprechen werden, durch die die Einträge
der XML-Datei dargestellt werden, also
Angaben, die der User vornimmt, sind mit
den Einträgen verbunden, die ihrerseits die
XML-Entities repräsentieren. Wenn ein
Eintrag mit ihm verbundene Attribute hat,
modifizieren wir die Anzahl der
Tabellenzeilen, erreichen wir das, wenn man
die setTableSize Methode
aufrufen und danach übergeben wir alle
vorhandene Attribute, um den Inhalt in
Tabellenzellen auf einen neuen Zustand zu
bringen.
Die mit den Attributen gefüllte
Tabelle auf der rechten Seite des
Hauptfensters wird durch die
createAttributesTable Methode
erzeugt und besteht aus
FXTable Widget, welcher
ebenfalls in FXVerticalFrame
Widget eingeschloßen wird:
enjdef
createAttributesTable
enjoytableFrame =
FXVerticalFrame.new(@splitter,
enjoyyuLAYOUT_FILL_X|LAYOUT_FILL_Y|FRAME_SUNKEN|FRAME_THICK)
enjoy@attributesTable
= FXTable.new(tableFrame, 5, 2, nil,
0,
enjoyyu(TABLE_COL_SIZABLE|TABLE_ROW_SIZABLE|
enjoyyuFRAME_SUNKEN|FRAME_THICK|LAYOUT_FILL_X|LAYOUT_FILL_Y))
enjend
Wie Sie sich schon errinern
können, haben einige von anderen GUI
Toolkits den Namen table nur
dafür, um an den Layout-Manager zu
verweisen, der seine Kinder in Reihen und
Spalten anordnet(was dafür FOX den
FXMatrix Layout-Manager
aufruft). Für FOX ist FXTable
mehr als ein Tabellenkalkulationsähnlicher
Widget. Wir haben anfangs den
FXTable Widget mit 5
sichtbaren Zeilen und 2 sichtbaren Spalten
erzeugt, obwohl, wir werden es später
sehen, die Tabellengröße sich dynamisch
ändern kann, während das Programm läuft.
Die onCmdOpen Methode
behandelt die SEL_COMMAND
Nachricht, die erzeugt wird, sobald der
User auf den Öffnen...
Menübefehl aus dem Datei
Menü klickt:
enjdef
onCmdOpen(sender, sel, ptr)
enjoydlg =
FXFileDialog.new(self, "Öffnen")
enjoydlg.setPatternList([
enjoyyo"Alle
Dateien (*)",
enjoyyo"XML
Documents (*.xml)"])
enjoyif
dlg.execute() != 0
enjoyyoloadDocument(dlg.getFilename())
enjoyend
enjoyreturn
1
enjend
In dieser Methode wird ein
neues FXFileDialog Objekt
aufgebaut, dann wird seine Musterliste
initialisiert und anschließend wird durch
den Aufruf der execute Methode
ein Dialogfenster angezeigt. Die
execute Methode gibt
"nicht-null" zurück, wenn der User den
OK Button drückt, und das
der Fall ist, werden wir nach einem
Dateinamen gefragt, den wir entweder
auswählen oder eingeben müssen. Daraufhin
wird die loadDocument Methode
aufgerufen, die eine XML-Datei laden
kann:
enjdef
loadDocument(filename)
enjoy@document =
nil
enjoybegin
enjoyyu@document =
NQXML::TreeParser.new(File.new(filename)).document
enjoyrescue
NQXML::ParserError => ex
enjoyyuFXMessageBox.error(self,
MBOX_OK, "Error",
enjoyyou"Couldn't
parse XML document")
enjoyend
enjoyif
@document
enjoyyo@treeList.clearItems()
enjoyyopopulateTreeList(@document.rootNode,
nil)
enjoyend
enjend
Wenn der XML Parser eine
Ausnahme auslöst, während der Versuchung
ein NQXML::Document Objekt zu
erzeugen, rufen wir eine
FXMessageBox.error Singletone
Methode auf, um ein einfaches Dialogbox zu
zeigen, die dem User erklälrt, was
geschehen ist. Das erste Argument von
FXMessageBox.error
identifiziert sozusagen den Besitzer der
Dialogbox, andersgesagt wem die Dialogbox
gehört. Die Box schwebt sozusagen über dem
Besitzer, bis die abgewiesen wird. Das
zweite Argument ist ein "flag", der darauf
hinweist, welche Art von "Ende-Buttons" in
dieser Dialogbox erzeugt werden könnte; es
gibt dafür auch andere Optionen und zwar
MBOX_OK_CANCEL,
MBOX_YES_NO,
MBOX_YES_NO_CANCEL,
MBOX_QUIT_CANCEL und
MBOX_QUIT_SAVE_CANCEL. Die
FXMessageBox Klasse
unterstützt ein paar anderen praktischen
singleton Methoden, durch die nützliche
Nachrichten wie information,
question und
warning angezeigt werden
könnten. Wenn es keine Fehlermeldungen
gibt, löschen wir den alten Inhalt der
Liste und danach bauen durch den
wiederholenden Aufruf der
populateTreeList Methode neuen
Listeninhalt auf:
enjdef
populateTreeList(docRootNode,
treeRootNode)
enjoyentity =
docRootNode.entity
enjoyif
entity.instance_of?(NQXML::Tag)
enjoyyotreeItem =
@treeList.addItemLast(treeRootNode,
entity.to_s, nil, nil, entity)
enjoyyodocRootNode.children.each
do |node|
enjoyyoupopulateTreeList(node,
treeItem)
enjoyyoend
enjoyelsif
entity.instance_of?(NQXML::Text) &&
entity.to_s.strip.length != 0
enjoyyotreeItem =
@treeList.addItemLast(treeRootNode,
entity.to_s, nil, nil, entity)
enjoyend
enjend<
Hier verwenden wir eine
addItemLast Methode, die zum
FXTreeList Widget gehört,
damit wird es erreicht, dass neue
Listenenträge hinzugefügt werden. Das erste
Argument von der addItemLast
Methode ist ein Verweis auf einen
Listeneintrag, es wird sozusagen ein
"Vater" für diesen Eintrag erzeugt; die
Listeneinträge in "top-level" erzeugt, man
kann stattdesen nil für dieses
Argument übergeben. Das zweite Argument für
diese Methode ist ein Textstring, der
angezeigt wird, wenn man auf den Entrag
klickt, das dritte und vierte Argumente
sind optional und das sind "plus" Icon für
"öffnen" und "minus" Icon für "schließen".
Die werden vor dem Textstring des
Listeneintrages angezeigt. Wenn es keine
Icons angeboten werden, wird der
FXTreeList Widget anstatt der
"plus" und "minus" Icons eine
standartmäßige viereckige Icon darstellen.
Das letzte Argument der
addItemLast Methode ist eine
optionale User's Angabe; das ist ein Ruby
Objekt, welches mit dem frisch erzeugten
XML-Eintrag verbunden ist. In unserem Fall
speichern wir hier einen Verweis auf den
XML-Entinity, welche durch diesen Eintrag
repräsentiert wird.
Nun ist die Zeit zum
Ausprobieren. Die unten ausgeführte
Abbildung lief auf Windows OS:
Und das ist die Abbildung des
Programms, das auf Linux OS ausprobiert
war:
Anschließend noch Mal zur
Erinnerung, dass man den aktuellen Stand
FXRuby Projektes auf der jeweiligen
Homeseite erfahren kann.