Virtual OS/2 International Consumer Education
VOICE Homepage: http://de.os2voice.org
November 2002

[Inhaltsverzeichnis]
[Vorherige Seite] [Nächste Seite]
[Artikelverzeichnis]

editor@os2voice.org


DrDialog, oder wie ich lernte, REXX zu lieben - Teil 3

Von Thomas Klein © November 2002

Herzlich willkommen zurück zum dritten Teil unserer Serie, der diesmal sozusagen "zwischen zwei Warpstocks" stattfindet. Bevor wir aber loslegen, muß ich wie üblich noch ein paar Sätze loswerden:

Feedback

Natürlich (Danke!) haben mich zur letztmonatigen Ausgabe auch wieder viele nette Leute angeschrieben, mit guten Ideen zu Beispielprogrammen. Hier ist noch keine endgültige Entscheidung gefallen... es ist nicht so einfach, wie ich dachte. Ein Frontend für die Freeware-Fax-Programme von Harald Pollack (fsend, frec) ist mehr als eine gute Idee, jedoch sprengt es die Grenzen einer simplen Beispielanwendung. Der persönliche Assistent (PIM) ist auch noch in der engeren Wahl, ebenso das Frontend für die Infozip-Programme. Problematisch ist halt, daß es ein Programm sein soll, welches nicht zu komplex ist und mit dem jeder etwas anfangen kann. Ich bin also immer noch offen für Ihre Vorschläge. Seltsamerweise hat sich bis jetzt niemand kritisch, nörgelnd oder korrigierend zur Serie geäußert... Hey! Wenn ich irgendetwas falsch mache oder besser machen könnte: Raus damit! Diese Serie ist schließlich für Sie gedacht, nicht damit ich eine Ausrede habe, mich vor meiner Frau oder Tochter zu drücken!
...obwohl das zugegebenermaßen manchmal auch ein netter Nebeneffekt ist. ;)

Unter den Mails vom letzten Monat war eine, die ganz besonders hervorstach, denn - Sie werden es kaum glauben - sie stammte vom Entwickler von DrDialog (David C. Morrill), den ich im Vorfeld der Artikelserie mehrmals vergeblich zu kontaktieren versucht hatte. Eines schönen Montagmorgens jedenfalls hatte ich eine E-Mail von ihm in meiner Box, und Sie war nicht nur sehr nett, sondern auch sehr positiv (siehe Leserbriefe, Addenda, Errata). Ich bin gespannt, was sich daraus vielleicht noch alles entwickelt (ohne hier jetzt irgendjemanden unter Druck setzen oder falsche Hoffnungen schüren zu wollen).

Einige Tips

Jetzt noch etwas, daß ich seit dem ersten Teil unserer Serie immer wieder vergessen habe: Die Online-Hilfe.
Zwar setzen die einzelnen Themen in DrDialogs Onlinehilfe unter Umständen bereits Kenntnisse zu anderen Themen voraus und die Lernkurve ist anfangs etwas steil... wenn man sich aber nicht unterkriegen läßt und weiter sucht, findet man für gewöhnlich immer genau die Information, die einem fehlt. Zum Erlernen von DrDialog ist die Online-Hilfe nicht unbedingt geeignet, als Nachschlagewerk (gerade zu Beginn) ist sie allerdings unverzichtbar. Der Dateiname, um den es hier geht, lautet DRDIALOG.INF und die Datei befindet sich standardmäßig im Programmverzeichnis von DrDialog.

Wenn Sie gleichzeitig auch REXX-Neueinsteiger sind, sollten Sie auf jeden Fall auch die REXX-Informationen parat haben, die bei der Installation von OS/2 (bzw. eCS) bereitgestellt werden. Darunter verbirgt sich die Datei mit dem Namen REXX.INF, die standardmäßig im Verzeichnis BOOK auf dem OS/2-Installationslaufwerk befindet. Momentan verwenden wir zwar eigentlich sehr wenig "reines REXX" in unseren Programmen, aber das wird sich zunehmend ändern...

Um gerade am Anfang schnell Hilfe zur Verfügung zu haben, sollten Sie für beide Dateien eine Verknüpfung in Ihrem WarpCenter, XCenter oder Ihrer Klickstartleiste (oder einem Tray darin) anlegen. Aus persönlicher Erfahrung kann ich Ihnen nur zum Einsatz hoher Auflösungen und großer Bildschirme raten, die es einem erlauben, neben DrDialog selbst immer auch die beiden INF-Dateien geöffnet zu haben... ;) Sie werden sehen, daß Sie diese beiden Dateien relativ häufig benötigen - ich selbst brauche Sie nach wie vor.

In diesem Zusammenhang noch ein Hinweis:
Ich habe auf meinem System bemerkt, daß das Drücken von <F1> im Entwicklungsmodus von DrDialog dazu führt, daß das Programm sich sang- und klanglos beendet, bevor die Hilfedatei angezeigt wird. Ich möchte nicht ausschließen, daß dies an irgendeiner (fehlerhaften) Einstellung meines Systems liegt, aber seien Sie gewarnt: Verwenden Sie lieber die nebenstehende Schaltfläche aus der 'Werkzeugleiste' von DrDialog - damit klappt's in gewohnter Form.

Auf geht's

Ich möchte die Fortsetzung mit einem Nachschlag zur letzten Ausgabe begeinnen. Sie erinnern sich vielleicht, daß wir in der letzten Ausgabe nach einer Stelle im Programm gesucht haben, die sich zur "Initialisierung" unseres Textausgabefelds eignet... und genau da habe ich doch tatsächlich übersehen, daß es noch eine weitere Stelle gibt, die darüber hinaus von Ihrer "Natur" her eigentlich am besten dafür geeignet wäre:
Wenn unser Dialog geladen wird, wird dadurch das "OPEN"-Ereignis ausgelöst. Innerhalb des OPEN-Ereignisses werden dann für alle im Dialog enthaltenen Anzeigeelemente (also "controls") die jeweiligen INIT-Ereignisse aufgerufen. Na perfekt! Sie können also unsere Anweisung

call ausgabe.text("")

auch mittels Code-Editor im INIT-Ereignis des controls Ausgabe angeben. Dazu (aber das wissen Sie ja...) klicken Sie doppelt auf die Textbox, wodurch im Code-Editor sofort das INIT-Ereignis geladen wird. Geben Sie dann den Befehl (pardon, die "Methode" ;) ) ein:

Jetzt können Sie die gleiche Anweisung im OPEN-Ereignis natürlich löschen, sonst würde Sie zweimal ausgeführt - was zwar kein Fehler, aber trotzdem überflüssig wäre.

Wenn wir die in der letzten Ausgabe angesprochene "globale Startroutine" einmal außer Acht lassen, haben wir also 2 Ereignisse, die wir zum "Leeren" unserer Textbox verwenden können...:

...schön, aber welches ist "besser" geeignet und warum?

Natürlich können Sie jedes der beiden Ereignisse nutzen, aber im Prinzip sollte man zunächst genau betrachten, was da eigentlich paasiert, denn das OPEN-Ereignis wird für den Dialog generiert; das INIT-Ereignis für die Textbox. Da unsere Anweisung sich nur auf die Textbox bezieht, sollten wir auch das Ereginis verwenden, welches sich nur auf die Textbox bezieht, denn:

Anders sähe es aus, wenn Sie gleich mehrere Controls initialisieren möchten und dazu vielleicht noch auf gespeichert Werte (wie INI-Daten) zurückgreifen: Hier bietet es sich aus Gründen der besseren Dokumentation an, alle Anweisungen zentral hintereinander zu codieren. Das können Sie entweder direkt im OPEN-Ereignis selbst machen oder durch Aufruf einer speziellen Routine aus dem OPEN-Ereignis heraus, die dann die notwendigen Anweisungen enthält.

Was Sie bei der Auswahl Ihrer Mittel aber immer im Hinterkopf behalten sollten, ist der zeitliche Ablauf der Geschehnisse:
Zuerst wird das "INIT" des Dialogs erzeugt, dann dessen "OPEN", danach das "INIT" der Textbox und der anderen Controls. Ab dann ist der Dialog erst "auf sich allein gestellt" und die Aktionen des Anwenders bestimmen die Reihenfolge der ausgelösten Ereignisse.

So viel also zu den Ereignissen, die wir für unsere "Mach-Leer"-Anweisung verwenden können... lassen Sie uns diese Anweisung einmal etwas genauer anschauen - das wird Ihnen bestimmt gefallen. ;)
Laut der Onlinehilfe ist die Syntax der verwendeten Funktion text() wie folgt:

oldText = [dialog.][control.]Text( [newText] )

Aha. Also eine Funktion, die uns etwas zurückgibt ("oldText"). Teufel auch, wieso steht denn weiter unten als Beispiel

/* Clear the contents of an edit field: */
CALL myDialog.edit.Text ""

Herrjeh - das sieht ja ganz anders aus, als das, was oben steht, und als das, was wir selbst geschrieben haben...
Nun, keine Panik: Man kann die Funktion text auf drei verschiedene Arten aufrufen, in Abhängigkeit davon, wozu man Sie verwenden möchte - nämlich:

Wenn Sie rudimentäre Grundkenntnisse in der Objektorientierung haben (so wie ich), dann kommen Sie jetzt bloß nicht auf die Idee, mich zu fragen, ob das jetzt ein Beispiel für "Polymorphie" ist - ich habe keinen blassen Schimmer. ;) Fakt ist, daß man die Funktion eben so verwendet, wie man Sie braucht:

Wenn Sie ein Feld namens AUSGABE haben, das Bestandteil des Dialogs MEINDIALOG ist, und Sie möchten nur abfragen, was gerade darin steht, dann nehmen Sie

Inhalt = MEINDIALOG.AUSGABE.TEXT()

Die leere Klammer zeigt, daß Sie keinen neuen Inhalt übergeben wollen. Jetzt möchten Sie den Inhalt wissen und zusätzlich noch Hallo als neuen Inhalt in das Feld Schreiben (das passiert natürlich erst, nachdem der "alte" Inhalt ausgelesen wurde...):

Inhalt = MEINDIALOG.AUSGABE.TEXT("Hallo")

So - zu guter letzt möchten Sie gar nix wissen, sondern nur dafür sorgen, daß als Inhalt Hallo drin steht. In diesem Fall brauchen Sie auch keine Variable anzugeben, die den Rückgabewert der Funktion (also den alten Inhalt) aufnimmt:

CALL MEINDIALOG.AUSGABE.TEXT("Hallo")

Natürlich können Sie auch die erste Schreibweise verwenden und den Rückgabewert schlicht ignorieren, aber mittels der CALL-Schreibweise dokumentieren Sie auch in einem, daß Sie der vorherige Inhalt nicht interessiert und Sie im weiteren Verlauf auch keine Verarbeitung damit vorhaben.

Zeit für eine Tasse Tee... lassen Sie das obige auf sich wirken und lesen Sie es ruhig so oft durch, bis Sie das Prinzip ungefähr verstanden haben. Diese Art von Aufrufen betrifft übrigens auch alle anderen Funktionen in DrDialog, die sich auf controls (also Steuerelemente bzw. Bildschirmelemente) beziehen.

Genug erholt? Weitermachen? Okay:
Jetzt kommt's nämlich schon etwas dicker. Wie Sie vielleicht aus anderen Syntaxdiagrammen wissen, werden eckige Klammern verwendet, um optionale Teile einer Syntax zu kennzeichnen. Aus unserer Anweisung

oldText = [dialog.][control.]Text( [newText] )

würde also nach Entfernung aller "optionalen" Teile

oldText = Text()

Ups? Was soll das denn sein? Das klappt doch nie! Irrtum. Es klappt:
Wie Sie sehen, verwendet die Syntax hier eine komplette "Klassifizierung" der Funktion Text, indem angegeben wird, wessen Funktion hier verwendet werden soll, nämlich durch Angabe des Dialogs und des Controls, dessen Funktion wir verwenden möchten.
Das ist erst mal für sich alleine gesehen die vollständige und absolute, immer eindeutige Anweisung. Das ist genau so, als ob Sie einen Dateinamen inklusive Laufwerksbuchstaben und vollständigem Pfad angeben, wie in C:\CONFIG.SYS. Diese Angabe ist auf dem ganzen System immer eindeutig, egal in welchem Verzeichnis oder auf welchem Laufwerk Sie sich befinden.
Bleiben wir beim Dateinamebeispiel: Wenn Sie sich bereits in einem OS/2-Fenster auf dem Laufwerk C: befinden, reicht (egal in welchem Verzeichnis Sie sich dann befinden) die Angabe \CONFIG.SYS, um die Datei zu identifizieren. Befinden Sie sich zusätzlich im Wurzelverzeichnis von C:, reicht sogar einfach CONFIG.SYS.

Ganz so ähnlich verhält es sich mit den Funktionen der DrDialog-Controls: Wenn Sie sich in einer Ereignisroutine befinden, die den Dialog unserer Textbox betrifft (z.B. Dialog-OPEN Ereignis), dann können Sie den ersten optionalen Operator [Dialog] weglassen: Die Anweisung bezieht sich dann auf den Dialog, in dessen "Kontext" Sie sich gerade bewegen. Versuchen Sie es einmal, indem Sie in das OPEN-Ereignis des Dialogs

call ausgabe.text("Dialoginit")

schreiben. Ach, und löschen Sie die Anweisung im Textbox-INIT Ereignis, sonst werden Sie von dieser Ausgabe hier nichts sehen! ;)
Na gut, diese Syntax kennen wir ja schon. Sie können in jeder Ereignisroutine des Dialogfensters oder eines enthaltenen Controls verwenden. Jetzt löschen Sie diese Anweisung wieder, und schreiben in das INIT-Ereignis der Textbox:

call text("Textboxinit")

Starten Sie das Programm zum Test... und? Klappt. Aber: Es klappt nur hier, im INIT-Ereignis der Textbox! Diese Anweisung befindet sich nun "im Kontext" des Textbox-Controls. Wenn Sie diese Anweisung an eine andere Stelle setzen, wird es nicht klappen: Schreiben Sie doch einmal testweise in das "OPEN"-Ereignis des Dialogs und starten Sie das Programm... na, was wird wohl passieren?

Hossa! Was ist denn jetzt los? ;)
Ganz einfach: Die Anweisung befindet sich nun im Kontext des Dialogfensters. Da Sie keinen [Control]-Operator verwendet haben, bezieht sich Ihr Aufruf also auf die Text()-Funktion des Dialogfensters, welche den Inhalt der Titelzeile setzt oder liest - eben je nach Aufrufmethode.
Angenommen, ein Dialogfenster hätte jetzt nicht zufälligerweise ein Funktion namens "Text", würde DrDialog eine Fehlermeldung ausgeben - nämlich, daß er die angegebene Funktion oder Routine nicht finden kann.

Was lernen wir also daraus? Ein ganz einfaches Schema: Wenn Sie sich auf eine Funktion eines Controls beziehen, müssen Sie weder Dialog noch Control angeben, solange Sie sich in einer Ereignisroutine dieses Controls befinden. Wenn Sie die Funktion "von woanders" her aufrufen, müssen Sie nur das Control angeben, solange Sie sich in einer Routine desselben Dialogs befinden. Wenn Sie von einem anderen Dialog (oder einer "globalen Routine") heraus die Funktion eines Controls aufrufen möchten, müssen Sie das Ding vollständig qualifiziert angeben: Mit Dialog- und Controlnamen.

Kehren wir zurück zu unserem Beispielprogramm: Das einzige, was wir also zum Leeren unserer Textbox letztendlich brauchen, ist die Anweisung

call text("")

im INIT-Ereignis unserer Textbox. Uff. Jetzt wäre es Zeit für etwas "härteres" als Tee, hm? ;)

Nächsten Monat werden wir damit beginnen, uns die wichtigsten bzw. am häufigsten benötigten Eigenschaften der Controls anzuschauen, die den "Standardumfang" einer grafischen Benutzeroberfläche bilden. Das wären folgende Kandidaten:

Gut - es fehlen jetzt Bildlaufleisten, Bitmaps und was weiß ich noch alles. Aber diese Jungs hier sind die "echten" elementaren, interaktiven Bestandteile einer grafischen Oberfläche, die Sie auf jedem System wiederfinden werden, sei es unter OS/2, Windows, Mac, Linux, oder einer grafischen DOS-Oberfläche. Meist variiert die grafische Darstellung dieser Komponenten zwischen den einzelnen Plattformen, aber im Prinzip sind es funktional immer dieselben.

Tja. Leider kann ich mein Versprechen vom letzten Monat nicht halten: Wir werden in dieser Ausgabe keinen zweiten Dialog in unser Beispielprogramm aufnehmen. Dafür werden wir aber schon einmal einen kleinen Vorgeschmack auf nächsten Monat bekommen, indem wir unser Beispiel um eine Liste und ein Eingabefeld erweitern.

Bis jetzt macht unser Programm ja nichts aufregendes. Wir drücken auf einen Knopf und es kommt immer derselbe Text. Wie langweilig - keine Verarbeitung. Also setzen wir nun folgendes Ziel:

Ich weiß - das ist auch nicht viel aufregender, aber Sie lernen dadurch zwei neue Controls kennen und können bis zum nächsten Monat Ihre Sprachkennnisse aufpolieren. ;)

Beginnen wir mit dem leichten Teil: Das Texteingabefeld
Suchen Sie sich einen freien Platz auf Ihrem Dialog oder vergrößern Sie ihn notfalls. Ziehen Sie dann ein Texteingabefeld von der Werkzeugleiste auf Ihren Dialog

oder wählen Sie das Texteingabefeld aus dem Kontextmenü des Dialogs

Auch die Texteingabe hat - wie Sie sehen - einen voreingestellten Anzeigewert. Diesen können Sie jetzt ändern oder auch komplett löschen über die beiden ausgiebig diskutierten Methoden, die wir von der Textbox kennen:

Verpassen Sie dem Eingabefeld noch einen Namen. Ich nehme "Eingabe".

Kommen wir jetzt zur Auswahlliste. Bei den Listen unterscheiden wir einerseits die klassischen "Listen" von der sogenannten combo box ("Kombinationsliste"), die sich wiederum unterschiedlich ausprägen bzw. verhalten kann.

Beispiel für "klassische Liste"

Beispiel für Kombinationsliste

Die Kombinationsliste läßt sich, wie bereits erwähnt, in unterschiedlichen Arten verwenden - mit oder ohne sichtbarem Listenteil bzw. mit oder ohne Texteingabe, wobei die Texteingabe auch auf eine Suchfunktion beschränkt werden kann.

simple

drop down

drop down list

Die letztendliche Art der Liste wird in DrDialog durch Ihre Style-Eigenschaft eingestellt - in allen Fällen ist es aber dennoch immer das nebenstehende Symbol, welches uns eine Kombiliste zur Verfügung stellt.
In unserem Beispiel möchten wir eine Kombinationsliste verwenden, die allerdings nur eine Auswahl ermöglicht, also keinen Texteingabeteil verwendet. Dazu fügen wir unserem Dialog also zunächst einmal eine Kombiliste hinzu (mit Ziehen aus der Werkzeugleiste oder über das Kontextmenü des Dialogs).

Jetzt geben wir an, daß diese Liste nur zum Auswählen von bereits vorhandenen Einträgen dienen und auch keine Such- oder Eingabefunktion aufweisen soll. Wählen Sie aus dem Kontextmenü der Liste den Eintrag Style und wählen Sie im dann erscheinenden Dialog die Option Drop down list:

Geben wir der Liste noch einen Namen... wie wär's mit Auswahl?

Das wär's an Aufgaben, die zur Entwicklungszeit anfallen. Den Rest machen wir zur Laufzeit, nämlich erstens: Inhalt der Kombiliste festlegen.
Das ist etwas, was eigentlich nur einmal gemacht werden muß, nämlich zum Start des Programms, bzw. Dialogs... na, das "riecht" ja förmlich nach einer klassischen "INIT"-Anweisung, nicht wahr? ;) Und so ist es auch. Also begeben wir uns nun zur Ereignisroutine "INIT" für unsere Kombiliste im Codeeditor

und schauen wir uns an, wie man einer Liste etwas hinzufügt:

result = [dialog.][control.]Add( item [, "Ascending" | "Descending" | "Last" | n] [, data] )

Hmmm. Schwierig... da werden so viele verschiedene und nützliche Funktionen implementiert, daß es einen zunächst erschlägt. Mein Tip: Wir wollen ganz, ganz einfach nur Einträge in eine leere Liste machen, die auch nicht sortiert werden oder bestimmte Reihenfolgen erfüllen soll. Schmeissen wir doch einmal wieder alles "optionale" raus, dann bleibt übrig:

result = Add( item )

Na bitte. Schon besser. ;)
Sie sehen: Ich habe auch die Qualifizierungsoperatoren [Dialog] und [Control] entfernt - was ja kein Problem ist, da wir die ADD-Funktion ja innerhalb der INIT-Routine der Liste selbst verwenden.
Wenn wir nun noch darauf verzichten, den Index des neu in die Liste eingefügten Eintrags zu erhalten (das brauchen wir für unser Beispiel nicht), dann können wir die Funktion auch ohne Rückgabewert verwenden:

call Add( item )

So. Wir möchten, daß in unserer Liste folgende Einträge auftauchen: Hello, Salut, Ciao, Hola und Hallo.

Also geben wir in der INIT-Routine an:

call add("Hello")
call add("Salut")
call add("Ciao")
call add("Hola")
call add("Hallo")

Jetzt ist das so ein kleines Problemchen mit Listen, daß Sie in Ihrem frisch geladenen Zustand zwar viele Einträge haben mögen, davon jedoch keiner ausgewählt ist... wenn wir also blindlings darauf vertrauen, daß beim Drücken unseres pushbuttons der Anwender schon etwas ausgewählt hat, könnte das unter Umständen buchstäblich "in die Hose" gehen... Wir müssen also sicherstellen, daß immer ein Eintrag ausgewählt ist, bevor wir die Liste "verarbeiten".
Zwar könnten wir jetzt vor der Verarbeitung immer prüfen "ist denn überhaupt ein Eintrag ausgewählt", aber das ist reine Zeitverschwendung, wenn man weiß, daß unser Listentyp nur zu Beginn keinen ausgewählten Eintrag aufweist. Ist erst einmal ein Eintrag ausgewählt, kann dieser nur durch Auswählen eines anderen Eintrags wieder abgewählt werden - hihi - somit stellt sich das Problem nur zu Beginn des Programms. Und da ist es am einfachsten, dem Anwender einfach einen bereits vor-ausgewählten Eintrag zu präsentieren, den er gegebenenfalls ändern kann. Wir verwenden hierfür die Funktion Select:

result = [dialog.][control.]Select( [index [, "Select" | "Unselect" | "Next" | "Top" ] ] )

Seufz - machen wir's kurz:

result = Select( [index ] )

Ja, okay, dieses mal habe ich einen optionalen Parameter übriggelassen. Die Funktion Select unterstützt ähnlich wie die Funktion Text der Textbox sowohl das Setzen als auch das Abfragen eines Eintrags einer Liste mit einem Aufruf.

Da ich aber nicht nur wissen will, welcher Eintrag ausgewählt ist, sondern dieses mal einen Eintrag auswählen möchte, muß ich dessen Eintragsnummer (Index) hier angeben. Wir nehmen dafür den ersten Eintrag der Liste, also Index = 1. Dafür interessiert mich aber nicht, welcher Eintrag eventuell vorher ausgewählt war, weil es bekanntlich keinen gab - ich verwende also wieder die Aufrufform ohne Rückgabewert

call Select(1)

als Anweisung direkt hinter dem Füllen meiner Liste im INIT-Ereignis. Und das war's schon. Jetzt müssen wir nur noch die Ausgabe unserer Meldung ändern, die auf Knopfdruck erfolgt.
Unser Ziel ist es, die in der Liste ausgewählte Begrüßung zusammen mit dem im Texteingabefeld eingetragenen Namen auszugeben in der Form

Hallo Welt.

Kümmern wir uns erst einmal darum, in Erfahrung zu bringen, welcher Eintrag der Liste ausgewählt wurde, wenn auf unseren pushbutton gedrückt wird. Eben hatten wir erfahren, daß die Select-Funktion der Liste das kann, sie gibt uns nämlich den Index (die Nummer, beginnend mit 1 für den ersten Eintrag) des ausgewählten Eintrags zurück, wenn wir die "Aufrufform mit Rückgabewert" verwenden:

result = Select( [index ] )

Da wir keinen neuen Eintrag auswählen wollen, können wir den optionalen Übergabewert weglassen und haben:

result = Select()

Moment, moment... aber wir verwenden diese Funktion nicht in einer Routine, die zum "Kontext" der Listbox gehört, sondern beim Drücken des pushbuttons. Also müssen wir noch hinzufügen, wessen Select-Funktion wir da aufrufen. Da unsere Liste Auswahl heißt, muß unsere Anweisung also lauten:

result = Auswahl.Select()

Die Variable result wird dann von REXX automatisch zur Verfügung gestellt, sofern sie nicht schon existierte und enthält danach den Index des ausgewählten Eintrags. ...Moment... Index? Das nützt uns nichts - wir brauchen doch den Eintrag selbst! Schließlich wollen wir nicht 1 Welt. sondern Hallo Welt. ausgeben! Nach kurzem Wühlen in der DrDialog-Hilfe stellen wir fest, daß man das scheinbar mit der Funktion "Item" macht:

result = [dialog.][control.]Item( [index [, "Value" | "Data" ] [, value] ] )

Also, ich spare mir die Anmerkungen zu allen von der Funktion unterstützten Features und vereinfache wie folgt:

result = [control.]Item( [index ] )

Oder, um bei unserem Beispiel zu bleiben:

result = Auswahl.Item( [index] )

Jetzt bräuchten wir nur [Index] durch den Rückgabewert von

result = Auswahl.Select()

zu ersetzen, und das wär's. Natürlich könnten Sie auch "schön sauber" alle Rückgabewerte in speziellen Variablen speichern, wie...

Nummer = Auswahl.Select()
Grusstext = Auswahl.Item(Nummer)

...und dann mit der Variable Grusstext weiterarbeiten, aber wozu denn unnötig Aufwand betreiben? Da die Funktion Select also einen Index zurückgibt, und die Funktion Item einen Index benötigt, könnte man das ganze vereinfachen:

Grusstext = Auswahl.Item( Auswahl.Select() )

Nachdem wir das geklärt hätten, kümmern wir uns um unsere Texteingabe. Na, das ist doch einfach, denn wir kennen doch unsere Text()-Funktion noch aus dem Syntaxbeispiel weiter oben:

oldText = [dialog.][control.]Text( [newText] )

woraus wir

Grussname = Eingabe.Text()

machen, denn unser Eingabefeld heißt "Eingabe" und ich muß den Operanden [Control] angeben, da ich mich nicht im Kontext der Eingabebox befinde, sondern im Click-Ereignis des pushbuttons.

Wir haben also nun den Text der Begrüßung und den Text aus dem Eingabefeld. Jetzt müssen wir das nur noch aneinander hängen und in unsere Textbox schieben. Das "Aneinanderhängen" (auch 'Konkatenieren' genannt) wird mit REXX erledigt, das zwei Zeichenketten über die "Doppel-Pipe" miteinander verbindet:

Text3 = Text1 || Text2

Oder um bei unserem Beispiel zu bleiben:

Ausgabetext = Grusstext || Grussname

Jetzt halten wir erst einmal fest, was wir beim Klicken des pushbuttons alles machen müssen. Die Anweisungen sehen also wie folgt aus:

Grusstext = Auswahl.Item( Auswahl.Select() )
Grussname = Eingabe.Text()
Ausgabetext = Grusstext || Grussname

Die Verkettung "||" hängt beide Texte unmittelbar aneinander. Das würde also einen Grußtext wie "HalloWelt" ergeben - nee, das geht nicht. Hängen wir also noch eine Leerstelle hinein und den Punkt (".") an's Ende:

Ausgabetext = Grusstext || " " || Grussname || "."

Schon besser.
Das alles schreiben wir also in das "Click"-Ereignis des pushbuttons. Dann müssen wir natürlich noch die eigentliche Ausgabeanweisung ändern von

call ausgabe.text("Hallo Welt!")

in

call ausgabe.text(Ausgabetext)

Ein cooles Programm. Wenn Sie noch nicht müde sind, können wir das auch noch etwas "straffen" und uns eigentlich unbenötigter Variablen entledigen. Sie wissen ja, was eine Gleichung ist, oder? Klar. Demnach ist aufgrund der folgenden Gleichung (oder "Zuweisung")

Ausgabetext = Grusstext || " " || Grussname || "."

der Inhalt von Ausgabetext dasselbe, wie das, was in der Formel dahinter steht. Somit können wir also auch in der Anweisung entsprechend ersetzen. Aus

call ausgabe.text(Ausgabetext)

machen wir

call ausgabe.text( Grusstext || " " || Grussname || "." )

und schon brauchen wir die Variable Ausgabetext nicht mehr. Unsere Anweisungen sähen dann also so aus:

VORHER:

Grusstext = Auswahl.Item( Auswahl.Select() )
Grussname = Eingabe.Text()
Ausgabetext = Grusstext || Grussname
call ausgabe.text(Ausgabetext)

NACHHER:

Grusstext = Auswahl.Item( Auswahl.Select() )
Grussname = Eingabe.Text()
call ausgabe.text( Grusstext || " " || Grussname || "." )

Wenn Ihnen solche Straffungen gefallen, dann können Sie das auf die Spitze treiben und auch noch Grusstext und Grussname durch die enstprechenden Gegenstücke ersetzen und die gesamte Ausgabeverarbeitung auf einen ultimativen Einzeiler zusammenstreichen:

call ausgabe.text( Auswahl.Item( Auswahl.Select() ) || " " || Eingabe.Text() || "." )

Hier wurden nur alle "Zwischenvariablen" ersetzt durch die jeweilige Funktion, deren Rückgabewert darin gespeichert war. Lesen Sie sich den Passus gerne einige Male durch und gehen Sie schrittweise vor und zurück, das hilft.
Wenn Sie es nicht kapieren: Wen kümmert's schon - Sie können natürlich auch mit den ausformulierten Zuweisungen und den Zwischenvariablen arbeiten. Es dokumentiert sich besser und wir leben nicht mehr in einem Zeitalter, wo jede überflüssige Variable im Hauptspeicher richtiges Geld gekostet hat. ;)

Hausaufgaben geüwnscht?
Spielen Sie ein wenig herum mit Ihrem "neuen" Programm. Wenn Sie z.B. merken, daß Sie bei Verwendung einiger führender Leerzeichen vor der Namenseingabe eine entsprechend verschobene Ausgabe erhalten...

Beispiel: "Peter" wird eingegeben als "   Peter" (drei Leerstellen davor)
Ausgabe: "Hallo    Peter."

...dann schauen Sie sich doch in der REXX-Dokumentation einmal die Funktion "strip" an - keine Angst, ist jugendfrei - und überlegen Sie, wie man die noch in die Ausgabe unserer Meldung einbauen könnte.
Machen Sie es sich nicht zu schwer, und verwenden Sie die "ungekürzte" vierzeilige Version der Click-Ereignisroutine, die wir hier besprochen haben. Die Auflösung erfolgt in der nächsten Ausgabe, bevor wir "richtig loslegen" und uns die wichtigsten Controls und Ihre Eigenheiten - pardon - Eigenschaften näher anschauen.

Liebe Leser, es ist wieder einmal so weit: Zeit zu gehen... Aber dieses Mal könnten sich unsere Wege treffen! Kommen Sie nach Arnheim zur Warpstock Europa 2002. Wenn Sie möchten, besuchen Sie mich am VOICE-Stand und diskutieren Sie mit mir, was ich besser machen könnte, wo Sie Probleme haben, oder villeicht auch ein aktuelles Problem, daß Sie mit DrDialog haben. Ich habe natürlich mein Notebook mit vor Ort und wenn es die Zeit erlaubt, klicke ich gerne ein wenig mit Ihnen in DrDialog herum.

Also: Auf Wiedersehen in Arheim!

Daten und Quellen:

GuiObjectREXX Yahoo!-Gruppe: http://groups.yahoo.com/group/GuiObjectREXX/
Newsgruppe zur GUI-Programmierung mit REXX: news://news.consultron.ca/jakesplace.warp.visualrexx
Download von Hobbes: http://hobbes.nmsu.edu/cgi-bin/h-search?key=drdialog&pushbutton=Search


[Artikelverzeichnis]
editor@os2voice.org
[Vorherige Seite] [Inhaltsverzeichnis] [Nächste Seite]
VOICE Homepage: http://de.os2voice.org