Zurck zur Homepage

Verwendung SWin/VRuby Erweiterungen

SWin und VRuby sind zwei Grundbestandteilen des VisualuRuby's Projektes. SWin ist ein Ruby-Erweiterungsmodul, geschrieben in C, welches vielen von Win32 API zu den Ruby-Interpreter bereitsteht. VRuby ist eine Bibliothek, die aus reinen Rubymodulen besteht, bildet sich auf SWin auf, so dass es eine Schnittstelle auf höchster Ebene für Win32-Programmierung zur Verfügung stellt. Wie es der Fall mit anderen Ruby-Erweiterungen ist, gibt es meistens die Dokumentaion für SWin und VRuby nur in Japanisch. Auf der offizielen Seite des VisualuRuby Proejktes kann man sich Beispielprogramme besorgen, die man als Musterprogramme für seine Ideen ausprobieren und was eingentlich mit SWin und VRuby machen kann, und dadurch können Sie sich schon mit allgemeinen Windowsprogrammierungsvorstellungen vetraut machen. Dieser Abschnitt liefert genug Information der VRuby(API) Schnittstelle um unseres Beispielprogramm zu entwicklen, aber für die tieferen Kenntnissen in SWin/VRuby müssen sich gut genug mit den Hintergründen der Windowsprogrammierung auskennen. Es gibt einige hervorragende Bücher in diesem Gebiet, und wenn auch sie aus dem Blinkwinkel der C Programmierung Win32 API besprechen, könnten sie durchaus gut einige Lücken des nötigen Wissens mit VRuby Programmierung auffüllen. Außerdem gibt es auch auf anderer Seite eine sehr nützbare Information der Win32 API Referenz auf der Microsoft Developer Network Seite auch als CD's erhältlich.

Installation

SWin und VRuby Module sind im Ruby-Installer von der "Pragmatic Programmers" Webseite enthalten. Also heisst es, dass wenn man sich Ruby installiert hat(es handelt sich natürlich nur um Windows OS), kann man sich loslegen. Man kann sich auch Sourcecode für SWin von der VisiualuRuby Projekt Seite herunterladen, und kann auch so gut schon precompilierte Binäres finden.

VRuby Bibliothek Basis

Da es so wenig Dokumentaion in Englisch für SWin und VRuby gibt, werden wir an dieser Stelle zusätzliche Information liefern, die Ihnen einen Überblick von der VRuby Bibliothek und ihren Klassen und Modulen verschafft. Um mehr Information darüber herauszubekommen, wäre es hilfreich, Kommentare von der Sourcedateien zu studieren, welche selbst allerdings ziemlich skizzenhaft sind, aber das könnte Ihnen helfen, anzufangen, wenn Sie beabsichtigen, mit VRuby zu arbeiten. Die VRuby Bibliothek ist als eine Reihe der Ruby Sourcedateien aufgebaut, und wird ins vr Package-Verzeichnis installiert. Die unten dargestellte Tabelle 1 listet einige der meistens wichtigen Dateien, die Sie in ihren Programmen verwenden werden, und entsprechend require Statement. Dabei ist es, anzumerken, dass die meiste oder alle der nicht sozusagen "Kern-Dateien" von der Kern-Klassen und Modulen aus vr/vruby.rb abhähngig sind, so dass es wahrscheinlich nicht notwendig ist, diese Dateien zusätzlich zu importieren.

Tabelle 1 Inhalt der VRuby Bibliothek



Beschreibung  Wie wird es importiert 
Kern-Klasse und Module  require 'vr/vruby' 
Layout Manager  require 'vr/vrlayout' 
Standard Steuerung  require 'vr/vrcontrol' 
Allgemeine Steuerung  require 'vr/vrcomctl' 
Multipane Windows  require 'vr/vrtwopane' 


Die Kern-Klasse und Module für VRuby(Tabelle 2) besteht aus allein "High-Level" Basisklassen und "mixin"-Modulen, die Sie aber nicht direkt in meisten Programmen verwenden werden. Es gibt aber zwei bemerkenswerte Ausnahmen, wie auch immer, VRForm und VRScreen. VRForm ist die Basisklasse, die für die "top-level" Fenster verwendet wird, solche, wie in ihren Programmen Hauptfenster sind. Wie Sie in unserem Beispielprogramm sehen werden, muss man nur lediglich unseres Hauptfenster von der VRForm Klasse ableiten, eventuell auch eine andere Verhalten des Fensters bringen, und werden Sie es kennenlernen, wie in dieser Klasse durch die construct Methode nach ihren Bedürfnissen das Verhalten und das Aussehen der Applikation handhaben wird.

Tabelle 2 Kern-Klasse und Module für VRuby



Name von Klasse/Modul  Beschreibung 
VRMessageHandler  Dieses Modul könnte in irgendwelchen Klassen verwendet werden, die Windows Nachrichten empfangen müssen; das stellt acceptEvents und addHandler zur Verfügung
VRParent  Dieses Modul liefert die Modulmethode, die von dem Vater-Fenster verwendet wird(das Fenster kann als ein Behälter für die anderen Kind-Fenster sein), passt gut unter anderem mit VRForm und VRPanel Klassen zusammen, weil sie die meist verwendete "Behälterklasse", die man am häfigsten verwendet wird 
VRWinComponent  Das ist die Basisklasse von allen Fenster
VRControl  Basisklasse für alle Controlwidgets; eine Subklasse von VRWinComponent
VRCommonDialog  Dieses Modul bietet mehrere passende Funktionen an, die für allgemeinen Fensterdialogen verwendet werden; liefert Modulmethoden wie openFilenameDialog, saveFilenameDialog, chooseColorDialog und chooseFontDialog 
VRForm  Das ist Basisklasse für alle Hauptfenster, wie das Hauptfenster von unseren Beispielprogramm, und kann auch mit VRMessageHandler, VRParent und VRCommonDialog Modulen verwendet werden 
VRPanel  Das ist die Basisklasse für alle Kind-Fenster(wie ControlWidgets); eine Subklasse von VRControl 
VRDrawable  Dieses Modul kann mit einigen Klassen verwendet werden, die man braucht, um "Bild-Nachrichten" handzuhaben(ein Verweis, dass die Fensterinhalte rekonstruiert werden); diese Klasse kann die self_resize Methode außer Kraft setzen 
VRResizeable  Dieses Modul kann in irgendwelchen Klassen benutzt werden, um Ereignisse abzufangen, die die Änderung der Fenstergröße handhaben; diese Klasse kann die self_resize Methode außer Kraft setzen 
VRUserMessageUseable  Dieses Modul kann in irgendeiner Klasse verwendet werden, um Benutzerdefinierte Nachrichten mit dem Betriebsystem zu passen 
VRScreen  Diese Klasse stellt die Fensteroberfläche dar, und bietet Methoden an, um neue Hauptfenster-Widgets zu erzeugen und zu zeigen, und dazu kann dies die Hauptereignisschleife zu steuern. VRuby legt genau eine globale Instanz dieser Klasse, VRLocalScreen 


Einige der Window's Steuerungen existierten seit der Zeiten, als noch Windows 95 nocht nicht zur Welt geblickt hat, was aber, wie man schon weiß, nicht verhindern konnte, dass diese Steurungen sich als standard Steurungen etabliert haben. Die Standardsteurungen(wie Buttons, Labels, Textfelder) sind zugägnlich, wenn man vr/vrcontrol.rb in Anspruch nimmt. Die nachstehende Tabelle 3 listet die Klassen, die dieses Modul präsentieren.

Tabelle 3 Standard Steuerelemente für VRuby



Klassen/Modul Name  Beschreibung 
VRStdControl  Diese Klasse(eine Subklasse von VRControl ist einfach die Basisklasse von allen Standard Steurungenselementen 
VRButton  Das ist ein Standard Drück-Button; Man kann auch den Button's Text zuweisen, dabei wird eine caption Instanz-Methode verwendet 
VRGroupbox  Die Gruppenbox 
VRCheckbox  Das ist eine Checkbox Steurungseinheit. Man kann ein sogennantes Häkchen setzen oder das entfernen, gemacht wird das durch die check Instanz-Methode, um den aktuellen Zustand zu prüfen, verwendet man die checked? Instanz-Methode 
VRRadioButton  Das ist ein Radio-Button, gewöhnlich wird es als eine Gruppe von Radio-Buttons angezeigt, wird verwendet, wenn nur eine Auswahl getroffen werden muß. Da es besonderer Fall(eine Subklasse) der VRCheckbox ist, wird auch hier die check und checked? Instanz-Methoden unterstützt 
VRStatic  Das ist ein statischer Text-Steureungselement, welches einfach eine nicht editierbare Textbeschriftung anzeigt. Der Beschriftungstext kann durch die caption Instanz-Methode zugewiesen werden 
VREdit  Das ist einzigzeilige editierbare Text-Steurungseinheit. Die liefert eine Zahl von Instanz-Methoden zusammenhängend mit dem Editieren und Eingeben vom Text, und sowie die Bearbeitung des ausgewählten Textes und auch die Übertragung von einem Text zwischen der VREdit und Windows Clipboard(Zwischenspeicher) 
VRText  Das ist vielzeilige editierbare Text-Sterugseinheit. Sie ist ähnlich wie einzigzeilige Darstellung (VREdit), aber bietet eine Zahl von zusätzlichen Instanz-Methoden an, die mit dem Navigieren durch den Text zusammenhängen 
VRListbox  Das ist eine vertikalorientierte Liste von Strings, von welchen der User sich einen oder mehrere Einträge aussuchen kann 
VRCombobox  Das ist eine "Drop-Down" Liste von Strings, ähnlich wie VRListbox, nur aber mit dem Unterschied, dass man sich lediglich einen Eintrag aussuchen kann 
VRMenu  Das ist eine Menübar, die mit pulldown Menüs ausgestattet ist, und gewöhnlich erscheint entlang des oberen Randes von Hauptprogrammfenster 
VRMenuItem  Das ist ein einzelnen Menüeintrag, welcher in VRMenu Widget erscheint(z.B. Speichern als... Befehl in der Datei Menü eines Programmes). Sie werden im Allgemeinen es implizit erzeugen, wenn Sie eine Menü's set Befehl aufrufen 
VRMenuUseable  Dieses Modul könnte mit anderen verschiedenen Klassen verwendet werden, welche Menüs benutzen müssen; das liefert die newMenu und setMenu Modulmethode 
VRBitmapPanel  Das ist eine besondere Art von Panel, die verwendet wird, um statische Bitmaps zu zeigen 
VRCanvasPanel  Das ist eien spezielle Art von Panel, die benutzt wird, um zeichengeeignete Bitmap Images zu zeigen; Sie können die Größe und Höhe von Panel und kann man auch GDI Funktionen, um darauf zu zeichnen  


Windows 95 hat sehr viele neue Benutzerfreundlichen Steuereinheiten eingeführt, die als common(allgemeine) Steuerelemente genannt werden. Diese beinhalten solche Steuerelemente, die als list views, tree views bekannt sind und werden umfassend in Windows Explorer verwendet. Die VRuby Klassen stellen algemeine Steuerelemente, die in der Tabelle 4 auflistet sind.

Tabelle 4 Allgemeine Steuerelemente für VRuby



Klassenname  Beschreibung 
VRNotifyControl  Diese Klasse(eine Subklasse von VRControl) ist einfach die Basisklasse fü alle allgemeine Steuerelemente 
VRListView  Das ist eine steigende "Listensteuerung", welche konfiguriert werden kann, um Daten in verschiedenen Formaten zeigen zu lassen(z.B. als Icons mit einer einfachen Beschreibung, oder in der mehr detalierten Listenform). Meinstens wird diese Steuerung, wie in Windows Explorer bekannter Form verwendet. 
VRTreeview  Diese Steuerung, auch gewöhnlich als Tree-Liste bekannt ist, wird verwendet, um die hierarchisch-strukturierte Daten zeigen zu lassen. Das ist eine beliebte Auswahl für meiste Windowsprogrammen, wird zum Beispiel in Register Editor Utility verwendet  
VRProgressbar  Diese Steuerung wird während eines sozusagen "zeitaufgebrauchten" Vorgehens verwendet, damit wird den User eine Rückmeldung angeboten, über die er erfahren kann, wie weit irgendwelche Operation vorangekommen ist und wieviel Zeit übriggeblieben ist, bis die Operation beendet wäre
VRTrackbar  Dieses Steuerungselement besteht aus einem sozusagen Schieber oder einer Führung und optionalen Markierungszeichen. Das kann benutzt werden, wenn der User möchte, einen diskreten Wert aus einer Reihe von Werten auszuwählen 
VRUpdown  Diese Steurung besteht aus ein Paar Pfeil-Buttons(gewöhnlich ein nach oben und andere nach unten gerichtet),die der User benutzen kann, um eine Zunahme oder eine Abnahme einigen Werten im Programm zu zeigen. Die bildet fast immer ein Paar mit "buddy" Fenster, wie mit VREdit Steuerung, um ihre aktuelle Einstellungen zu zeigen 
VRStatusbar  Das ist ein horizontales Streifen, welches am unteren Rand des Hauptfensters erscheinen kann, um die Statusinformation anzeigen zu lassen  
VRStatusbarDockable  Dieses Modul könnte mit der VRForm Klasse verwendet werden. Damit wird die Statusbar-Steureung eingeschloßen. Benutzt wird dabei eine addStatusbar Methode, um die Statusbar in den Widget hinzuzufügen 
VRTabControl  Diese Steuerung zeigt ein oder mehrere Tabs, welche man verwenden kann, um als eine Basis für dei Eigenschaftentabelle oder Tabspanel zu benutzen 
VRTabbedPanel  Diese Steuerung kombiniert VRTabControl mit einer Reihe von Panels, um "tabbed" notebook Steuerungen zu erzeugen 


Layout Manager

Im Gegensatz zu allen anderen GUI Tookits, die wir bis jetzt gesehen haben, bietet VRuby nicht so viel, was Layout Manager betrifft. Das ist hauptsächlich auf den Fakt zurückzuführend, dass Win32 API, auf der SWin und VRuby basirien, überhaupt keine irgendwelche Layout Manager enthalten. Obwohl die Layout Manager jetzt mit VRuby mitgeliefert werden, sind sie etwas begrenzt, eins würde in dieser Situation erwarten, als VRuby ausgereifter auszubaeun. Es gibt für VRuby drei Layout Manager und zwar VRHorizLayoutManager, VRVertLayoutManager und VRGridLayoutManager. Diese Layout Manager sind einfach Module, die man mit einer Behälterklasse, wie VRPanel, verwenden kann, und die dienen nicht als Standalone-Behälterklasse. Ähnlich wie ihre Gegenstücke in Ruby/GTK und FXRuby ordnen die erste zwei Layout Manager ihre Kind-Widgets in der horizontalen oder vertikalen Richtung. Um diese Layout Manager zu benutzen, muss man erstens das gewünschte Layout Manager-Modul mit seiner Behälterklasse zusammenmischen:

require 'vr/vrlayout'

eclass MyPanelClass < VRPanel
enjinclude VRHorizLayoutManager
eend

Danach werden einen oder mehrere Kind-Widgets (oder in der "Windows-Sprache" als controls (Steuerelemente)genannt) zum Behäterfenster durch die addControl Methode hinzugefügt:

aPanel = MyPanelClass.new ...

eaPanel.addControl(VRButton, "button1", "Überschrift für den ersten Button")
eaPanel.addControl(VRButton, "button2", "Überschrift für den zweiten Button")

Die volle Argumentenliste für unsere Layout Manager VRHorizLayoutManager#addControl (oder VRVertLayoutManager#addControl ist:

addControl(type, name, caption, style=0)

wo type eine VRuby Klasse fürs Steuerungselement ist, name sein Name ist, und caption ein Textstring ist, der auf dem Steuerungselement erscheint(natürlich für diejenige, die das unterstützen). Das letzte Argument style kann verwendet werden, um zusätzlich "windows style flags" für dieses Steuerelement zu übergeben. Die Grundeinstellung dafür ist es, dass VRuby eine Steuerung erzeugt, die nur "basis style flags" enthält; zum Beispiel, VRButton-Steuerungselemente werden durch die WStyle::WS_VISIBLE oder WStyle::BS_PUSHBUTTON flags erzeugt. Im Gegensatz zu anderen GUI Toolkits brauchen Sie tatsächlich keine Steuerungen über die Parameter von Kinder-Widgets, um deren Größe zu beinflüssen. Zum Beispiel für VRHorizLayoutManager ist es so, dass die Höhe von Kinder-Widgets ebenso gleich wie die Höhe des Vater-Widgets ist und die Breite des Vater-Fensters wird durch die Anzahl der Kinder-Steuerungen dividiert. Ferner jeder Kind-Widget breitet sich automatisch(horizontal oder vertikal) aus, um seinen zugewiesenen Raum zu füllen.

Der VRGridLayoutManager entspricht ungefähr dem Tk's grid Layout, GTK's Gtk::Table und FOX's FXMatrix, allerdings mit einer Art der Beschränkung für die Größe der Kind-Steuerungen, die wir schon bei den VRHorizLayoutManager und VRVertLayoutManager gesehen haben. Bevor die Kind-Steuerungen zum Behälter hinzugefügt werden, dabei wird VRGridLayoutManager verwendet, müssen wir zunächst eine Anzahl von Spalten und Zeilen mit Hilfe der setDimension Methode festlegen:

require 'vr/vrlayout'

eclass MyPanel < VRPanel
enjinclude VRGridLayoutManager
eend
eaPanel = MyPanel.new ...
eaPanel.setDimension(5, 3)

wo die zwei Argumente auf die Anzahl der Zeilen beziehungsweise Spalten hindeuten. Gleich danach kann man die Kind-Steuerungen durch die VRGridLayouManager#addControl Methode hinzufügen.

addControl(type, name, caption, x, y, w, h, style=0)

Hier sind die erste drei Argumenten gleich den Argumenten, die wir vorhin für die VRHorizLayoutManager und VRVertLayoutManager erläutert haben. Die nächste zwei Argumente(x und y) weisen auf eine Zelle hin, die sich oben links in der Reihe von Zellen befindet, diese Zelle wird die entsprechende Steuerung belegt, und schließlich die "w" und "h" Argumente weisen darauf hin, wieviel die Breite und die Höhe der insgesamt in der Reihe vorhandenen Tabellenzellen beträgt. Für die Steuerung, die nur eine Tabellenzelle einnimmt, werden Sie lediglich die Breite und die Höhe einer Zelle verwenden.

Handhabung von Ereignissen

VRuby verwendet Callback-basierende Methode, um die Ereignisse zu behandeln, die ganz anderes als die Methoden von anderen GUI's ist, die wir schon gesehen haben. Sie können erstaunt sein, wie man den Namen für jede Steuerung, die Sie zur einer Form hinzufügen möchten, festlegt. Zum Beispiel, wenn man ein Button(das ist natürlich ein Steuerungselement) hinzufügen möchte, kann man so vorgehen:/p>

aForm.addControl(VRButton, "button1", "Beschriftung für Button", ...)

Das dritte Argument ist ein Beschriftungsstring, der auf dem Button angezeigt wird. Das allerdings nicht heisst, dass dieser Namenstring überal erscheinen kann, aber eingentlich, jedesmal, wenn Sie neue Steuerung zu den VRForm oder VRPanel hinzufügen(die sind übrigens im VRParent Modul vorhanden), legt das Behälter-Objekt auch eine neue Instanzvarible und Zugriffsmethoden fest, und zwar mit den Namen, den Sie durch den Aufruf die Methode addControl vorher erzeugt haben. Diese neue Instanz-Variable ist einfach ein Verweis auf das Kind-Steuerungselement. Also nachdem der obengennante Zeilencode ausgeführt wird, könnten Sie später die Beschriftung von Button mit dem folgenden Code ändern:

aForm.button1.caption = "Neue Beschriftung für den Button"

Die Namen von Steuerungselementen sind dafür da, um die Callbacks zu erzeugen und diese Callbacksmethoden müssen solche Namen tragen, wie wir das an folgenden Coden erkennen können:

def controlname_eventname
en...Behandle dieses Ereignis
eend

So zum Beispiel, wenn Sie möchten, ein clicked Ereignis für die button1 Steuerung abzufangen, müssen Sie der Methode als Name button1_clicked vergeben:

def button1_clicked
evputs "Button1 wurde angeclickt!"
eend

Diese Callbacksmethoden müssen als Instanzmethoden fürs Behälterfenster festgelegt werden, und das heisst, wenn wir button1 Steuerung als ein Kind-Widget fÜr den aForm erzeugt haben, muss die button1_clicked Methode als eine Instanzmethode vom aForm Vater-Widget sein. Wir werden später es sehen, wie das im unseren Beispielprogramm funktioniert. Die folgende Tabellen 5 und 6 bieten eine Liste von Ereignisnamen für alle VRuby's Steuerungselementen, die Sie verwenden können.

Tabelle 5 Ereignisnamen für Standard-Steuerungen



Steurungsklassen  Ereignisname(n) 
VRButton  clicked, dblclicked 
VREdit  Changed 
VRListbox  Selchange 
VRCombobox  Selchange 


Tabelle 6 Ereignisnamen für allgemeine Steuerungselementen



Steuerungsklassen  Ereignisname(n) 
Alle allgemeine Steuerungen  clicked, dblclicked, gotfocus, hitreturn, lostfocus, rclicked, rdblclicked 
VRListview  itemchanged, itemchanging, columnclick, begindrag, beginrgrad 
VRTreeview  selchanged, itemexpanded, deleteitem, begindrag, beginrdrag 
VRUpdown  Changed 
VRTabControl  Selchanged 


VRuby Beispielprogramm

Der untenstehende Code zeigt uns eine VRuby's Version unseres Beispielprogrammes im seinen vollen Umfang. Den können Sie selbsverständlich auch herunterladen vruby-xmlviewer. Der Code beginnt mit dem Importieren von verschiedenen VRuby Bibliotheken, die wir benötigen werden:

require 'vr/vruby'
erequire 'vr/vrcontrol'
erequire 'vr/vrcomctl'
erequire 'vr/vrtwopane'

Als Nächstes definieren wir globale Konstanten, die benötigt werden, um später im Programm Nachrichtenboxen zu zeigen

# The values of these constants were lifted from "winuser.h"
eMB_OKenjoyenjoyenjoy = 0x00000000
eMB_ICONEXCLAMATION = 0x00000030
eMB_ICONINFORMATION = 0x00000040

Die Win32 Schnittstelle verwendet eine lange Zahl für die Namen von Konstanten(wie MB_OK, MB_ICONEXCLAMATION und MB_ICONINFORMATION), um die "style flags" für die Steuerungen festzulegen. In unserem Fall legt das letzte Argument der VRuby's messageBox Funktion Optionen von der Nachrichtenbox fest, solche wie gezeigte Buttons und Icons. Da diese Konstanten nocht nicht gut bei SWin/VRuby repräsentiert werden, müssen Sie sozusagen in allen Windows Header Dateien wühlen, um die aktuelle numerische Werte für diese Konstanten festzusetzen. Wie Sie schon bestimmt geahnt haben, ist das ein Zeitpunkt, wo die Windowsprogrammierung ihre Stelle einnehmen würde. Der nächste bedeutunsvolle Block des Codes legt die XMLViewerForm Klasse fest, und damit auch ihre Instanzmethoden; das ist sozusagen ein Brennpunkt der unseren Applikation. Bevor wir uns damit beschäftigen, lassen wir uns für eine kurze Zeit einen Teil des Codes überfliegen und werfen wir einen Blick auf letzte wenige Zeilen des Programmes:

mainWindow = VRLocalScreen.newform(nil, nil, XMLViewerForm)
emainWindow.create
emainWindow.show

e# Start der Nachrichtenschleife
eVRLocalScreen.messageloop

Nachdem wir die XMLViewerForm Klasse definiert haben(die ist einfach eine Subklasse von VRForm, rufen wir newform Methode auf, die zur VRLocalScreen Klasse gehört, damit erzeugen wir eine Instanz von der XMLViewerForm Klasse. Zur Erinnerung, VRLocalScreen ist eine spezielle Variable in VRuby; das ist einzige globale Instanz von VRScreen Klasse und sie entspricht locker dem Windows Desktop. Die erste zwei Argumente für newform Methode sind Vater-Fenster und "style flags" für dieses neuen Fenster. Im unseren Fall ist das das Hauptfenster unseres Programmes und so damit übergeben wir nil als Argument an die newform Methode. Letzendlich haben wir erreicht, dass sozusagen "Stil"(style) "default" wird. Danach rufen wir mainWindow.create auf, die eingentlich nichts Anderes macht, als das wirkliche Fenster als Ruby Objekt erzeugt. Von diesem Zeipunkt an ist das Behälter-Fenster, der Aufruf dieser Methode(create) löst den Aufruf der anderen Methode aus, und zwar construct Methode(wir werden das später sehen), um Steuerungselemente und Menüs zu erzeugen. Und schließlich wird die show Methode aufgerufen, damit wird das Hauptfenster sichtbar, bevor die Hauptereignisschleife(main even loop) eintritt.

Nun lassen wir uns zurückgehen, und schauen wir uns den Code für unsere "Formklasse" und zwar XMLViewerForm. Wir beginnen damit, dass wir zwei Module einbinden, die sehr nützliche Funktionen von VRForm zur Vefügung stellen:

include VRMenuUseable
einclude VRHorizTwoPane

Das VRMenuUseable Modul liefert uns die newMenu und setMenu, die dazu dienen, dass man damit Pulldown's Menüs aufbauen kann. Das VRHorizTwoPane Modul fügt die addPanelControl Methode hinzu, und ermöglicht einen horizontal-gesplitterten Layout für den Inhalt des Haupfensters. Als nächstes definieren wir zur Form gehörige construct Methode, die nichts anderes macht, als die Menüs erzeugt und Steuerugselemente zum Hauptfenster hinzufügt:

endef construct
enj# Set caption for application main window
enjself.caption = "XML Viewer"

enj# Create the menu bar
enj@menu = newMenu()
enj@menu.set([ ["&File", [ ["&Open...", "open"], ["Quit", "quit"] ] ],
enjoyenjoyenj["&Help", [ ["About...", "about"] ] ] ])
enjsetMenu(@menu)

enj# Tree view appears on the left
enjaddPanedControl(VRTreeview, "treeview", "")

enj# List view appears on the right
enjaddPanedControl(VRListview, "listview", "")
enj@listview.addColumn("Attribute Name", 150)
enj@listview.addColumn("Attribute Value", 150)
enend

Der Aufruf der newMenu Methode erzeugt einfach eine leere Menü und weist die danach zur unseren @menu Instanzvarible zu; und gleich danach der Aufruf der set Methode legt einfach den Inhalt des Menüs fest. Das sieht ein wenig kompliziert aus, muss aber nicht sein, weil set Methode ein Argument hat, welches ein Array von Array's ist, ein pro Pulldown Menü. Das für jede Pulldown Menü Subarray ist selbst ein zweielemengites Array. Betrachten wir das erste Array, welches der File Menü entspricht:

[ ["&File", [ ["&Open...", "open"], ["Quit", "quit"] ] ]

Das erste Arrayelement ist der Name des Pulldown Menü. Durch die Platzierung "ampersand"("&") vor der Buchstabe "F" in "File" wird es erreicht, dass die Alt+F Shortkey-Kombination verwendet kann, um das "File" Menü aufzuklappen. Das zweite Element in diesem Array ist auch ein anderes Array, diesmal ein Array, das einen Eintrag im "File" Menü darstellt. Jedes Element solches Array's ist entweder ein zweielementiges Array, das für den Menüentrag eine Beschriftung und einen Namen anbietet, oder soeben die Beschriftung und noch ein anderes Array eines Menüeintrages um ein weiteres "cascasding" sozusagen Submenü zu präsentieren. Solche Submenüs machen unseren Author(M.Neumann) ein bisschen "verrückt", und so bleibt der Author weiter hin mit Single-Level Menü zu beschäftigen. Einen Kapiter zuvor haben wir das Thema "Ereignisbehandlung" unterrichtet und haben gesehen, dass Namen von Steuerungselementen sehr wichtig sind, weil sie in den Namen für VRuby's Callback's Methoden verwendet werden. Auf gleicherweise sind auch von Ihnen zugewiesenen Namen von Menüeinträgen wichtig; wenn der Anwender auf einen solchen Menüeintrag klickt, wird VRuby nach der Callbackmethode suchen, die den Namen name_clicked trägt. Bald werden wir sehen, dass die XMLViewerForm Klasse die Callback's Methoden open_clicked, quit_clicked, about_clicked definiert, um diese drei Menübefehle festzusetzen.

Nachdem wir mit der Hilfe der construct Methode die Applikationsmenü's definiert haben, f&uugen wir genau zwei Steuerungselemente zum unseren horizontalen "Schauplatz"(pane):

e# Tree view appears on the left
eaddPanedControl(VRTreeview, "treeview", "")

e# List view appears on the right
eaddPanedControl(VRListview, "listview", "")

Die Namen von Kinder-Steuerungselementen, die man zu VRParent hinzufügte, werden als Namen Instanzvariablen. Wir werden daraus einen Vorteil nutzen, um weiter den Listview Widget mit dem Namen listview zu konfigurieren:

e@listview.addColumn("Attribute Name", 150)
e@listview.addColumn("Attribute Value", 150)

Als nächstes lassen wir uns auf drei Callback's Methoden konzentrieren. Die behandeln Open..., Quit und About Menüsbefehle. Da der Name fürs Menüeintrag Open... open war, wurde seine Callback-Methode als open_clicked gennant:

endef open_clicked
enjfilters = [["All Files (*.*)", "*.*"],
enjoyenjoy["XML Documents (*.xml)", "*.xml"]]
enjfilename = openFilenameDialog(filters)
enjloadDocument(filename) if filename
enend

Die openFilenameDialog Methode ist eine bequeme Funktion um einen üblichen Windows Dateidialog zu zeigen. Das ist eine Modulmethode, die im VRCommonDialog Modul integriert ist. Die kann genauso gut auch in der VRForm Klasse verwendet werden, so dass man diese Methode für irgendwelche Form benutzen. Als Argument erwartet diese Methode ein Array von Dateinamen's Mustern(oder wie in unserem Fall filters), welches im Dateidialog angezeigt wird und danach den Namen der ausgesuchten Datei zurückliefert(oder nil, wenn der Anwender den Dialog abbricht). Der Callback für den About... Menübefehl wird durch die "about_clicked" Methode gehandelt:

endef about_clicked
enjmessageBox("VRuby XML Viewer Example", "About XMLView",
enjoyMB_OK|MB_ICONINFORMATION)
enend

Die messageBox Methode ist eine andere Art der "bequem"-Funktion, und sie ist einfach eine Instanzmethode SWin::Window Klasse(eine weit entfernte Vorfahrklasse von unserer Form). Wie Sie schon wahrscheinlich vermutet haben, sind die drei Argumente die Nachricht selbst, die auf der Oberfläche des Fensters erscheint, der Titel des Fensters und "style flags", das darauf hinweist, welche Icons und Buttons(in der Regel zum Beenden) angezeigt werden. Der Callback für den Quit Menübefehl ist am leichtesten zu verstehen, weil der nur einfach Ruby's exit Methode aufruft:

endef quit_clicked
enjexit
enend

Die folgende Abbildung zeigt eine VRuby Version unseres Beispielprogrammes, das unter Window XP ausprobiert wurde:

Und hier ist der vollständige Code unseres Beispielprogrammes:

require 'vr/vruby'
erequire 'vr/vrcontrol'
erequire 'vr/vrcomctl'
erequire 'vr/vrtwopane'

erequire 'nqxml/treeparser'

e# The values of these constants were lifted from "winuser.h"
eMB_OKenjoyenjoyenjoy = 0x00000000
eMB_ICONEXCLAMATION = 0x00000030
eMB_ICONINFORMATION = 0x00000040

eclass XMLViewerForm < VRForm

eninclude VRMenuUseable
eninclude VRHorizTwoPane

endef construct
enj# Set caption for application main window
enjself.caption = "XML Viewer"

enj# Create the menu bar
enj@menu = newMenu()
enj@menu.set([ ["&File", [ ["&Open...", "open"], ["Quit", "quit"] ] ],
enjoyenjoyenj["&Help", [ ["About...", "about"] ] ] ])
enjsetMenu(@menu)

enj# Tree view appears on the left
enjaddPanedControl(VRTreeview, "treeview", "")

enj# List view appears on the right
enjaddPanedControl(VRListview, "listview", "")
enj@listview.addColumn("Attribute Name", 150)
enj@listview.addColumn("Attribute Value", 150)
enend

endef populateTreeList(docRootNode, treeRootItem)
enjentity = docRootNode.entity
enjif entity.instance_of?(NQXML::Tag)
enjoytreeItem = @treeview.addItem(treeRootItem, entity.to_s)
enjoy@entities[treeItem] = entity
enjoydocRootNode.children.each do |node|
enjoyenjpopulateTreeList(node, treeItem)
enjoyend
enjelsif entity.instance_of?(NQXML::Text) &&
enjoyenjentity.to_s.strip.length != 0
enjoytreeItem = @treeview.addItem(treeRootItem, entity.to_s)
enjoy@entities[treeItem] = entity
enjend
enend

endef loadDocument(filename)
enj@document = nil
enjbegin
enjoy@document = NQXML::TreeParser.new(File.new(filename)).document
enjrescue NQXML::ParserError => ex
enjoymessageBox("Couldn't parse XML document", "Error",
enjoyenjMB_OK|MB_ICONEXCLAMATION)
enjend
enjif @document
enjoy@treeview.clearItems()
enjoy@entities = {}
enjoypopulateTreeList(@document.rootNode, @treeview.root)
enjend
enend
endef open_clicked
enjfilters = [["All Files (*.*)", "*.*"],
enjoyenjoy["XML Documents (*.xml)", "*.xml"]]
enjfilename = openFilenameDialog(filters)
enjloadDocument(filename) if filename
enend

endef quit_clicked
enjexit
enend

endef about_clicked
enjmessageBox("VRuby XML Viewer Example", "About XMLView",
enjoyMB_OK|MB_ICONINFORMATION)
enend

endef treeview_selchanged(hItem, lParam)
enjentity = @entities[hItem]
enjif entity and entity.kind_of?(NQXML::NamedAttributes)
enjoykeys = entity.attrs.keys.sort
enjoy@listview.clearItems
enjoykeys.each_index { |row|
enjoyenjoy@listview.addItem([ keys[row], entity.attrs[keys[row]] ])
enjoy}
enjend
enend
eend

emainWindow = VRLocalScreen.newform(nil, nil, XMLViewerForm)
emainWindow.create
emainWindow.show

e# Start the message loop
eVRLocalScreen.messageloop

Valid XHTML 1.1! Valid CSS!