Virtual OS/2 International Consumer Education
VOICE-Homepage: http://de.os2voice.org
Juni 2004

Inhaltsverzeichnis
< Vorherige Seite | Nächste Seite >
Artikelverzeichnis

editor@os2voice.org


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

Von Thomas Klein © Juni 2004

Im heutigen Teil unserer Serie werden wir - entgegen meiner Ankündigung - nicht wieder sofort mit der Entwicklung in DrDialog einsteigen. Ich denke, es ist besser, wenn ich Ihnen einen "sanften" Übergang von der "reinen REXX-Programmierung" zurück zur DrDialog-Welt ermögliche: Seitdem wir mit der Umgebung und den Gegebenheiten vertraut waren, ist einige Zeit vergangen. Wir werden also kurz einige Fakten rekapitulieren und außerdem einen kurzen theorielastigen Teil zu bestimmten Eigenheiten von DrDialog erarbeiten und ich werde - ja, endlich! - eine kurze Vorstellung dessen geben, was ich als unser Beispielprojekt auserkoren habe und das uns über die nächsten Ausgaben beschäftigen wird. Aus diesem Grund werden wir uns also heute nochmals damit beschäftigen, wie die Arbeitsumgebung von DrDialog aussieht. Es wird uns einiges an Zeit und "grauen Zellen" retten, wenn ich in den kommenden Ausgaben davon ausgehen kann, daß Sie wissen, wo sich die richtigen Schaltflächen befinden...

Bevor wir aber loslegen, möchte ich Ihnen dringend raten, nochmals Chris Wohlgemuth's Leserbrief in der vorherigen Ausgabe des Newsletters zu lesen, der sich mit den rexxutil-Funktionen beschäftigt, und mich an dieser Stelle herzlich bei Chris für seinen Beitrag zu bedanken, der es uns ermöglicht, von seinem Erfahrungs- und Wissensschatz zu profitieren. Gerade wenn es sich um Computer und Programmierung handelt, gibt es einen Grundsatz, der für Sie, mich und uns alle gilt - egal, für wie gut wir uns in etwas halten möchten: Man lernt nie aus. Und dieses mal gebührt der Dank Chris, der uns ermöglicht hat etwas hinzuzulernen. Und ich kann es nicht oft genug sagen: Kommentare sind willkommen! Wenn Sie also erfahrener Entwickler (oder Anwender) sind und auf etwas stoßen, daß Ihrer Meinung nach nicht korrekt ist oder einer genaueren Beschreibung bedarf, dann lassen Sie es uns wissen, indem Sie einen entsprechenden Kommentar entweder an mich oder den Herausgeber senden, so wie Chris es tat. Dabei fällt mir ein: Hatte ich bereits erwähnt, daß Chris der einzige Entwickler "da draußen" ist, der immer noch dafür sorgt, daß sich der Funktionsumfang von DrDialog weiterentwickelt? Übrigens werden wir in einer der kommenden Ausgaben einen näheren Blick auf den Funktionsumfang seines Erweiterungspakets für DrDialog werfen.

Eine kurze (Wieder-) Einführung

In einem der ersten Teile unserer Serie hatten wir bereits besprochen, wie man DrDialogs Entwicklungsumgebung verwendet. Für diese und alle weiteren Ausgaben wollen wir nun einen "gemeinsamen Grundstein" legen, damit wir uns ständige Wiederholungen a la "wo ist..." sparen können.

Ich setze voraus, daß Sie wissen, wie Sie DrDialog selbst starten. Stellen wir nun also noch sicher, daß Sie wissen, wie die folgenden Funktionen bzw. Fenster in DrDialog aufgerufen werden:

Das Fenster des "run time monitor"
the controls window Die Sammlung der Steuerelemente ("controls")
Das Code-Notizbuch (respektive "Code-Editor")

Alle diese Schaltflächen sind erreichbar über die Menüleiste, unter dem Eintrag Tools um genau zu sein:

the tools menu

Beachten Sie, daß jedes dieser Fenster so eingestellt werden kann, daß es geöffnet bleibt, und ebenso, daß es direkt beim Start von DrDialogs integrierter Entwicklungsumgebung (IDE, "integrated development environment") geöffnet wird. Hierzu werden für das jeweilige Fenster die Einträge in dessen Systemmenü verwendet:

the system menu extensions

Das Fenster Dialoge:

the dialog windowAußerdem werden Sie - sobald Sie mehrere Dialogfenster im selben Programm verwenden - mit dem Fenster Dialoge arbeiten. Dieses Fenster wird über die Schaltfläche aufgerufen, die Sie links abgebildet sehen und die sich (genau wie die anderen oben besprochenen Fenster) entweder im Menüeintrag Tools oder (sofern geöffnet) dem Fenster Tools aufrufen läßt. Die anderen Fenster (wie z.B. Farbauswahl) werden wir für's erste nicht benötigen.

Alle codes sind gleich... aber manche sind gleicher als andere

Bisher haben wir bereits die Style-Einstellungen von Dialogen besprochen und was sie bewirken. Aber das betrifft nur so genannte "Designzeit"-Eigenschaften. Um mit mehreren Dialogen im selben Programm zu arbeiten müssen wir wissen, was man zur "Laufzeit" mit Ihnen anstellen kann - "aus dem Code heraus" sozusagen.
Um DrDialogs Verhalten verstehen zu können, müssen wir uns zuerst darüber klar werden, daß nahezu alles, was wir in DrDialog programmieren, auf die eine oder andere Weise mit Event-Handlern (Ereignisbehandlungsroutinen) verknüpft ist. Was geschieht eigentlich innerhalb von DrDialog, wenn ein Programm gestartet wird? Wo ist der Anfang in all den "losen Enden" von Code? Wie endet eigentlich ein Programm? Um das nun wiederum zu verstehen, müssen zwischen zwei "Arten" von Code in DrDialog unterscheiden:

Wie ihr Name vermuten läßt, sind Event-Handler-Codes an einen Event-Handler geknüpft und werden automatisch aufgerufen, sobald das entsprechende Ereignis eintritt. Noch wichtiger ist, daß (im Gegensatz zu VisualBasic bspw.) ein Event-Handler nicht manuell aufgerufen werden kann - außer man löst das zugehörige Ereignis manuell aus (z.B. das Öffnen eines Dialogs, um die Ereignisse INIT und OPEN auszulösen).
Das bedeutet, daß während wir eine einzelne Methode oder Eigenschaft eines Steuerelements von einer beliebigen Stelle im code heraus ansprechen bzw. abfragen/ändern können, wir bei DrDialog nicht in der Lage sind, eine Event-Handler-Routine aufzurufen... "Hä?" werden Sie jetzt vielleicht fragen... gut, hier ein Beispiel:

Wir möchten einen Dialog erzeugen, der uns die aktuelle Uhrzeit in einem Textfeld anzeigt. Zur Ladezeit des Textfeldes rufen wir also mittels der REXX-Funktion time() einfach die aktuelle Uhrzeit ab. Im INIT Event-Handler des Textfelds (angenommen, dessen Name wäre txt_tst) würden wir also codieren:

call txt_tst.text(time())

Probieren Sie's mal aus: Super. Es klappt.
Irgendwann im Laufe von Programmierung und Test des Programms stellen wir fest, daß unter Umständen einiges an Zeit seit dem Programmstart verstrichen sein könnte und beschließen, neben dem Textfeld eine Schaltfläche ("pushbutton") anzulegen, um eine Aktualisierung der angezeigten Uhrzeit zu ermöglichen. Alles, was diese Schaltfläche tun soll, ist genau das, was wir im Event-Handler INIT des Textfelds bereits codiert haben: Den Feldinhalt auf die aktuelle Uhrzeit zu setzen.
Nun gut denn - wir sind Programmierer und als solche faul und geizig. Warum also nicht einfach den Event-Handler INIT im CLICK Ereignis der Schaltfläche aufrufen? Ups... da fangen die Probleme an: Es gibt keinen "Aufruf", der das ermöglicht. Der Event-Handler INIT wird ausschließlich von DrDialogs interner Ereignis-Warteschlange aufgerufen. Gut, gut.. dann... machen wir's doch einfach anders herum: Wir tragen den Code im Event-Handler CLICK des pushbuttons ein. Dann ändern wir den INIT event-handler des Textfeldes dahingehend, daß einfach nur der Event-Handler CLICK für den pushbutton aufgerufen wird... und: Mist - wieder nix...

Aber es ist nicht tragisch: Es ist ja nur eine einzige Zeile Code. Wir könnten sie einfach in beide Event-Handler eintragen und "gut ist"... aber... was wäre, wenn es sich nicht um eine einzelne Zeile, sondern einen ganzen Anweisungsblock handelte? Möchten Sie wirklich identischen Code redundant an mehreren Stellen in Ihrem Programm verwenden? Das sieht doch irgendwie "doof" aus, oder? Außerdem ist es ziemlich aufwendig, wenn Sie beispielsweise einen Fehler in diesem Anweisungsblock entdecken - Sie müßten in dann an mehreren Stellen identisch korrigieren. Ach, das ist einfach nicht "raffiniert" genug! Und genau an dieser Stelle kommt der globale Code in's Spiel:

Der globale Code besteht aus (Unter-) Routinen und Funktionen, die nicht an einen bestimmten Event-Handler gebunden sind. Sie können aus jeder beliebigen Stelle im Programmcode aufgerufen werden - sei es aus einem Event-Handler oder aus einem anderen globalen Codestückchen.
Die Lösung ist also, den Aufruf der time()-Funktion in eine separate Unterroutine zu legen und dann lediglich aus den beiden Event-Handlern diese Routine aufzurufen. Um eine solche globale Routine (oder "Funktion") zu erstellen, müssen wir zunächst im Codeeditor von den ereignisbezogenen Routinen zum globalen Teil umschalten, indem wir die Schaltfläche mit dem "Globus" verwenden:

Der Codeeditor zeigt nun Indexzungen für jede bereits definierte globale Routine an. Wenn es (noch) keine solche gibt, ist das Fenster schlicht "ziemlich leer". Das Eingabefeld am oberen Bereich des Fensters dient zur Eingabe des Namens der Funktion, die Sie anlegen oder bearbeiten möchten. Geben Sie hier den Namen ein, den die Funktion tragen soll - beispielsweise "set_curr_date" (ohne die Anführungszeichen) und schließen Sie die Eingabe mit der Eingabetaste ab. Sie werden dann erkennen, daß der Codeeditor einen neuen Reiter mit diesem Namen anlegt.

Im Codeeingabebereich können Sie nun die Anweisungen eingeben, aus denen die Funktion bestehen soll. In unserem Fall wäre das:

call txt_tst.text(time())

...und schon falsch!
Diese Routine ist global. Das bedeutet also, daß sie von überall in unserem Programm aus aufgerufen werden kann. Daraus folgt, daß die Funktion nicht weiß, in welchem "Control-Kontext" sie sich jeweils gerade befinden könnte. Sie benötigt also den "voll qualifizierten Namen" des Steuerelements, das angesprochen wird, das heißt: Den Dialog, in dem sich das Element befindet, und den Namen des Elements. Wir müssen also vor den Namen des Elements noch den Namen des Dialogs setzen. Angenommen, der Name des Dialogs wäre MyDialog, müßte es also lauten

call MyDialog.txt_tst.text(time())

Schön. Sie werden sich vielleicht daran erinnern, daß man Dialogen nicht unbedingt einen Namen geben muß. In diesem Fall kann der Dialog immer noch gezielt angesprochen werden - nämlich über seine "ID-Nummer" in der Form "D100" beispielsweise ("D" ist der Präfix für Dialoge, 100 ist die ID-Nummer). Diese ID-Nummer eines Dialoges (oder auch Steuerelements) ist relativ leicht dadurch zu ermitteln, daß sie im Statusbereich am unteren Rand von DrDialogs Arbeitsbereichsfenster (dem "Hintergrund") angezeigt wird, sobald man den Mauszeiger auf das entsprechende Element bewegt:

Wenn unser Textfeld keinen Namen hätte, könnten wir es ebenfalls über seine ID-Nummer ansprechen: Steuerelemente verwenden den Präfix "C" (für "control" - Steuerelement) gefolgt von der ID-Nummer. Wäre die ID-Nummer des Textfelds z.B. "101", dann lautete sein voll qualifizierter Name:

D100.C101

Und daher würde der Aufruf in unserer globalen Funktion lauten:

call D100.C101.text(time())

Sobald Ihre globale Funktion vollständig ist, brauchen Sie sie nicht explizit irgendwie zu "speichern". DrDialog speichert sie automatisch, sobald man im Codeeditor einen anderen Bereich aufruft. Beachten Sie aber, daß DrDialog die Funktion automatisch löscht, wenn sich keinerlei Code darin befindet. Sie müßten Sie dann zunächst erst wieder wie oben beschrieben anlegen. Aber, wenn ja ohnehin kein code darin ist... kein Problem.

Bevor wir fortfahren, sollten wir noch besprechen, wie diese globale Funktion denn in den beiden Event-Handlern aufgerufen wird. Alles, was Sie dafür tun müssen, ist, die Anweisung

call set_curr_date

in beiden Event-Handlern einzutragen.
Das war jetzt vielleicht nicht das beste Beispiel, um die Vorzüge einer separaten, globalen Funktion zu erläutern. Stellen Sie sich einfach vor, diese Funktion würde statt einer Zeile ein ganzes Dutzend oder mehr Befehle enthalten. Beachten Sie auch, daß wir auf diese Weise volle Kontrolle über das Verhalten der Funktion haben und daher auch in der Lage wären, sie mit zusätzlichen Parametern aufzurufen, wenn wir das wollten. Damit könnten wir also die Funktion so ausbauen, daß Sie in Abhängigkeit von unterschiedlichen übergebenen Parameterwerten auf unterschiedliche Weise arbeitet.

Der Doktor wird geröntgt

Das war also ein Beispiel für eine globale Funktion bzw. Routine und wie man sie anlegt. Nun, da Sie wissen, was die Unterschiede zwischen Event-Handlern und globalen Routinen sind, können wir uns wieder der eingangs erwähnten Frage widmen: Wie startet eigentlich ein mit DrDialog erstelltes Programm?

Nun, DrDialog schaut zunächst nach, ob sich im globalen Teil des Programms (also unter den globalen Funktionen) eine Funktion befindet, die INIT heißt: Wenn eine solche Funktion vorhanden ist, wird sie ausgeführt und somit zum "Ursprungs-Event-Handler", wenn Sie so wollen.
Gibt es keine solche Funktion, lädt DrDialog das Dialogfenster mit der kleinsten ID-Nummer. Da die Existenz eines Dialogs mit dem INIT-Ereignis beginnt, wird also der INIT-Event-Handler zum Ursprungs-Event-Handler Ihres Programms.

Und das Programmende? Hier gibt es ebenfalls zwei Methoden: Eine "manuelle" und die in DrDialog "eingebaute":
Die eingebaute Methode besteht aus DrDialogs Überwachung der eigenen Fensterliste: Wenn das letzte existierende Dialogfenster geschlossen wird, wird auch das Programm beendet.
Die manuelle Methode besteht aus lediglich einem einzigen Befehl: "Exit" (ohne die Anführungszeichen) beendet das Programm. Vorsicht: Damit wird das Programm unverzüglich beendet - benehmen Sie sich also ordentlich, was eventuell geöffnete Dateien angeht! Und bitte verwenden Sie den exit-Befehl nicht irgendwo, tief im Code Ihres Programms. So etwas tun "schludrige" Programmierer. Versuchen Sie immer, die Programmlogik auf eine "kontrollierte" Art und Weise zu beenden.
Man kann zwar nie wissen, aber im Prinzip sollten Sie mit DrDialog nie in die Verlegenheit kommen, den EXIT-Befehl verwenden zu müssen, sofern Ihre Programmlogik "intakt" ist.

Aber wie bei jeder Regel, gibt es auch hier eine Ausnahme:
Angenommen, Sie möchten in Ihrem Programm überhaupt keine Dialoge verwenden, da es lediglich Batchverarbeitung ausführt, die keinerlei Eingaben oder sonstige Aktionen von Seiten des Anwenders erfordert, dann sollten Sie lieber "reines REXX" einsetzen statt DrDialog. Wenn Sie dennoch unbedingt DrDialog verwenden wollen, müssen Sie sich mit einer speziellen Eigenschaft dieser Umgebung auseinander setzen, die wir bereits in einem der ersten Teile der Serie besprochen haben: DrDialog erzeugt grundsätzlich ein Standard-Dialogfenster. Wenn Sie dieses löschen, wird sofort ein neues erzeugt.
Das liegt an DrDialogs rein ereignisgesteuerter Ausrichtung, die darauf beruht, daß alles mit einem Dialogfenster beginnt. Natürlich könnten Sie die Style-Eigenschaft des Dialogs auf "invisible" (unsichtbar) setzen, damit das Fenster gar nicht erst angezeigt würde und alles nötige in eine globale Routine INIT packen, mit der Ihr Programm dann startet... aber das wird so nicht klappen: Das Programm wird nämlich nicht beendet, wenn die letzte Anweisung Ihrer INIT-Routine abgearbeitet wurde. Nein - stattdessen wird nach Ausführung der letzten Anweisung das "vernachlässigte" Dialogfenster aktiv werden - egal, ob Sie es versteckt hatten oder nicht. Hoppla. Um dieses "Problem" zu umgehen, verwenden Sie einfach den EXIT-Befehl als letzte Anweisung in Ihrer Verarbeitungskette - das sollte dem Ding eine Lehre sein! Oder besser: Verwenden Sie einfach pures REXX, wenn Sie keine Dialoge benötigen.

Das wären also ein paar Hinweise zum Arbeiten ohne jegliche Dialoge gewesen. Was ist aber, wenn man mehrere Dialoge im selben Programm benötigt - beispielsweise einen Hauptdialog, einen "Optionen"-Dialog und eventuell einen Logo- bzw. Produktinformationsdialog? Worauf muss man achten?
Dafür muß man wissen, wie Dialoge aus dem Code heraus gesteuert werden können: Öffnen, Schließen, Sperren der Anwendung auf einen einzelnen Dialog... tja, um mit unseren Erwartungen mithalten zu können, ist es unabdingbar zu begreifen, wie DrDialog sich hinsichtlich Ereignisverarbeitung und Dialogsteuerung verhält. (Das ist der etwas "theorielastige" Teile, den ich eingangs erwähnte. Obwohl er vielleicht nicht unterhaltsam ist, sollten wir ihn dennoch "durchkauen", um einige wichtige Grundlagen für's Arbeiten mit DrDialog zu schaffen...)

DrDialog arbeitet ereignisorientiert und verwendet eine Nachrichten- bzw. Ereigniswarteschlange ("queue"). Das bedeutet im Prinzip, daß Ereignisse zunächst in einer Warteschlange abgelegt werden und dann nacheinander in der Reihenfolge des Auftretens abgearbeitet werden. Eigentlich ist das dasselbe, was andere Programmiersprachen unter graphischen, multitaskingfähigen Betriebssystemen auch tun. Das, was DrDialog hier von den anderen unterscheidet, ist die Art und Weise, wie diese Warteschlange "implementiert" ist:
Ich versuche, es einmal so zu erklären, wie ich es mir vorstelle - wenn jemand da draußen es besser (oder "richtig" ?) beschreiben kann, soll er es uns unbedingt wissen lassen! Na, jedenfalls... DrDialog verwendet den REXX-Interpreter des Betriebssystems, wodurch ihm nur eine einzige Warteschlange zur Verfügung steht. Da die GUI-bezogenen Ereignisse (z.B. Klicken einer Schaltfläche) von seiner eigenen Umgebung gesteuert und verarbeitet werden und diese ebenfalls die eine Warteschlange mitverwendet, ergeben sich leichte "Abweichungen" in dem uns eventuell bekannten Verhaltensmuster. Wenn Sie beispielsweise VisualBasic kennen, dann werden Sie wissen, daß Befehle und Ereignisse hinsichtlich der Reihenfolge Ihres Auftretens gleich behandelt werden: Wenn an einer beliebigen Stelle im Programm ein Dialogfenster geöffnet wird, führt VB unmittelbar die komplette, eventuell verschachtelte Verarbeitung aller zugehörigen Ereignisse aus und kehrt dann zu dem Befehl zurück, der auf die Öffnen-Anweisung des Dialogs folgt. Um Ihnen das einmal zu veranschaulichen, nehmen wir als Beispiel die folgende willkürliche Befehlssequenz:

- irgendein Befehl 1
- ÖFFNE Dialog "A"
- irgendein Befehl 2

VB würde das wie folgt ausführen:

- Verarbeitung von "irgendein Befehl 1"
- Aufruf für "Öffne Dialog A:" -> wird aufgelöst in:
-- Verarbeitung des INIT-Eventhandlers von Dialog A
-- Verarbeitung des OPEN-Eventhandlers von Dialog A
- Verarbeitung von "irgendein Befehl 2"

Jetzt mal keine Panik - Sie werden den Sinn des Ganzen begreifen, wenn wir uns anschauen, wie das in DrDialog aussieht.
DrDialog arbeitet hier anders. Da sich die REXX-Befehle und die möglichen Ereignisse dieselbe Warteschlange teilen müssen, haben die REXX-Befehle des aktuell ausgeführten Handlers "Priorität" vor den eventuell ausgelösten Ereignissen. Das bedeutet also, daß DrDialog alle GUI-bezogenen Ereignisse zunächst in der Warteschlange speichert und diese erst nach Abschluß des aktuellen Handlers ausführt. Für das obige Beispiel ergäbe sich unter DrDialog demnach ein anderer Ablauf. Zunächst schauen wir uns nochmals an, wie die Befehlssequenz war:

- irgendein Befehl 1
- ÖFFNE Dialog "A"
- irgendein Befehl 1

DrDialog würde das wie folgt verarbeiten:

- Verarbeitung von "irgendein Befehl 1"
- Aufruf für "Öffne Dialog A:"  ( -> in die Warteschlange stellen! )
- Verarbeitung von "irgendein Befehl 2"
< handler fertig, Warteschlange prüfen... aha: Ereignis auflösen in...: >
-- Verarbeitung des INIT-Eventhandlers von Dialog A
-- Verarbeitung des OPEN-Eventhandlers von Dialog A

Erkennen Sie den Unterschied? In der Praxis stellt uns das nun vor das eine oder andere Problem - zum Beispiel:
Wir denken meist in "prozeduralen" (oder auch "linearen") Abfolgen einer Verarbeitung und gehen beispielsweise davon aus, daß wir innerhalb einer Verarbeitungskette auf eine Benutzereingabe warten können. Obwohl das eigentlich richtig ist, läßt es sich mit einem Dialogfenster in DrDialog so nicht bewerkstelligen. Wenn Sie also eine Benutzeraktion (wie Eingaben) benötigen, um eine Verarbeitung fortzusetzen, können Sie nicht einfach einen Dialog aufrufen und auf das Klicken einer bestimmten Schaltfläche warten, da DrDialog zuerst die aktuelle Prozedur abarbeitet, bevor der Dialog erscheint.

Ein Programm auf eine Benutzereingabe warten zu lassen, ist übrigens Batch-Programmierung und DrDialog arbeitet ereignisorientiert. Daher wäre der richtige Ansatz für diese Problemstellung, nicht herauszufinden, wie zum Teufel man die Verarbeitung auf die Eingabe warten lassen kann, sondern vielmehr, die Verarbeitung erst nach der Eingabe zu starten, also: Vom Dialog aus.

Ein weiteres Kriterium zur Problemlösung ist die Tatsache, daß wir Betriebssysteme verwenden, die multitasking- und multithreading-fähig sind. Anstelle daß das Programm also auf eine Benutzeraktion wartet und wartet (was bedeutet, daß es also irgendwie CPU-Zeit verbraucht), sollte es lieber nichts tun (und CPU-Zeit an andere Prozesse abgeben), bis der Benutzer tatsächlich irgend etwas getan hat.
In der Praxis würden Sie also zuerst den Dialog anzeigen und stopp. Das wär's. Den Rest der Verarbeitung starten Sie erst, wenn der Benutzer auf die entsprechende Schaltfläche geklickt hat. Die Verarbeitung ist somit nicht der Bestandteil eines großen Anweisungsblocks, der vorher einen Dialog anzeigt, sondern Bestandteil dessen, was nach dem Drücken der Schaltfläche passiert. Sie verstehen? ;)

Der große Wurf

Gut. So weit also die Hinweise, die das Umgehen mit einem einzelnen Dialog betreffen. Jetzt gehen wir mal einen Schritt weiter. Einen großen...

Stellen Sie sich vor, Sie hätten die Idee zu einem neuen Programm - einem persönlichen Informationsassistenten. Eigentlich haben Sie keinen blassen Schimmer, was da später so alles noch auf Sie zukommt, aber Sie wissen, daß Sie unbedingt folgendes benötigen:

Sie sollten dann damit beginnen, bestimmte Verhältnisse unter den Dialogen zu bestimmen, wie z.B. deren Reihenfolge beim Programmstart. Um das ganze noch etwas komplizierter zu gestalten, nehmen wir also an, daß Ihnen außerdem noch folgendes vorschwebt:

  1. Beim Programmstart möchten Sie, daß der "Logo-Dialog" erscheint und eine Meldung wie "Programm wird geladen - bitte warten..." anzeigt, bis alle Einstellungen aus der INI-Datei geladen wurden.
  2. Das Logo soll immer in der Bildschirmmitte angezeigt werden, unabhängig von der Bildschirmauflösung
  3. Der Logo-Dialog sollte Statusmeldungen zum Ladevorgang des Programms ausgeben (z.B. "Einstellungen laden...", "Initialisierung..." usw.).
  4. Während des Ladevorgangs soll der Hauptdialog bereits "inaktiv im Hintergrund" geladen werden.
  5. Nach Abschluß des Ladevorgangs soll das Logo automatisch verschwinden und der Hauptdialog aktiviert werden.
  6. Wenn der Anwender eine passwortgeschützte Datei öffnet, erfordert dies eine entsprechende Eingabe per speziellem Dialog.
  7. Wenn beim Programmstart direkt ein Dateiname als Parameter mit übergeben wurde (beispielsweise als Programmparameter eines WPS-Programmobjekts). soll das Programm diese Datei automatisch laden bzw. bei Passwortschutz das Passwort anfordern.
  8. Wenn der Anwender das korrekte Passwort nicht eingeben kann und das Öffnen der Datei abbricht, soll das Programm in seinen vorherigen Zustand zurückkehren: Entweder die zuvor geöffnete Datei bleibt die aktuelle Datei oder es gibt keine. (Was bedeuten würde: Der Anwender kann nichts anderes tun, als eine Datei zu öffnen, das Programm zu beenden, eine neue anzulegen oder mit den Einstellungen herumzuspielen...)
  9. Zu guter Letzt möchten Sie außerdem, daß der Logo-Dialog gleichzeitig auch verwendet werden soll, um über das Menü "Hilfe" die "Produktinformationen" anzuzeigen. Dann soll der Dialog allerdings eine "OK"-Schaltfläche anzeigen, die den Dialog wieder schließt.

Das ist einiges. Und das ist noch ein Kinderspiel im Vergleich zu den "langweiligen" Sachen wie das Lesen, Schreiben und Darstellen von Daten.
Und es ist genau das, was wir als Beispielprogramm erstellen werden.
Au Backe... ich armer Kerl! Das kostet mich mindestens wieder ein Dutzend Artikel! Konnten Sie sich nichts leichteres Ausdenken? ;)

"Globale" Variablen:

Bevor ich Sie aber jetzt mit großen Erwartungen und einem Haufen offener Fragen zurücklasse, gönnen wir uns noch einen kleinen Wissenshappen zu DrDialog:
Da wir nun wissen, daß wir Event-Handler nicht wie andere Funktionen "manuell" aufrufen können, führt uns das direkt zu einer anderen Frage: Wie übergibt man Informationen an einen Dialog? Das wäre ziemlich nützlich, um beim Öffnen eines Dialogs gleich ein paar Parameter mitzugeben, wie Position, Größe, Titel und so weiter. Tja - keine Chance. Zumindest nicht auf direktem Weg... die Antwort lautet: Globale Variablen.

In den meisten Programmiersprachen werden Sie bestimmte Mittel finden um festzulegen, ob eine Variable nur in der aktuellen Funktion oder im gesamten Programm zur Verfügung steht (= "global" ist). In DrDialog ist das relativ einfach gelöst: Jede von Ihnen angelegte Variable ist automatisch global. Es sind keine besonderen Tricks und Kniffe nötig, damit Sie global ist. Aber Vorsicht - im Gegenzug gibt es auch keine Möglichkeit, eine Variable "lokal" zu machen: Wenn Sie den Inhalt einer Variable an einer Stelle des Programms ändern, ist sie "überall" geändert.

Noch ein kurzes Beispiel dazu? Hier ist es:
Beginnen Sie ein neues Programm in DrDialog. Der Standarddialog wird automatisch angelegt. Jetzt legen Sie eine Funktion mit dem Namen INIT im globalen Teil des Codeeditors an (wie das geht, hatten wir oben besprochen) und tragen dort den folgenden Befehl ein:

MeinDatenFeld = "Hallo"

Jetzt ziehen Sie eine Schaltfläche aus dem Controls-Fenster auf den Dialog. Der Text auf der Schaltfläche lautet standardmäßig Push. Nach einem Doppelklick auf die Schaltfläche erscheint im Codeeditor die Liste der dafür verfügbaren Event-Handler. Wählen Sie Reiter für das INIT-Ereignis aus und geben im Codefenster ein:

call text MeinDatenFeld

Starten Sie das Programm. Wie Sie sehen, wird als Text für die Schaltfläche nun der Inhalt der globalen Variablen verwendet, die wir in der INIT-Routine des Programms definiert haben.

Das wär's für heute. Ich hoffe, Sie freuen sich auf die nächste Folge. Wenn Sie schon immer wissen wollten, wie man einen Dialog "applikationsmodal" (die Anwendung "sperrend") in DrDialog angezeigt bekommt, sollten Sie dabei sein! ;)


Artikelverzeichnis
editor@os2voice.org
< Vorherige Seite | Inhaltsverzeichnis | Nächste Seite >
VOICE-Homepage: http://de.os2voice.org