02.07.2013 Aufrufe

Das LotusScript-Entwicklerbuch für Notes/Domino 8 - Addison-Wesley

Das LotusScript-Entwicklerbuch für Notes/Domino 8 - Addison-Wesley

Das LotusScript-Entwicklerbuch für Notes/Domino 8 - Addison-Wesley

MEHR ANZEIGEN
WENIGER ANZEIGEN

Sie wollen auch ein ePaper? Erhöhen Sie die Reichweite Ihrer Titel.

YUMPU macht aus Druck-PDFs automatisch weboptimierte ePaper, die Google liebt.

Grundlagen<br />

Teil I führt Sie auf praktische Weise zügig in die Programmierung von <strong>Notes</strong>-/<br />

<strong>Domino</strong> mit <strong>LotusScript</strong> ein.<br />

Sie lernen, wo und wie <strong>LotusScript</strong>-Programme erstellt und zum Laufen gebracht<br />

werden. Es werden sämtliche grundlegenden Elemente besprochen wie Lotus-<br />

Script-Befehle, -Variablen, -Objekte, -Module, -Prozeduren, usw.<br />

Natürlich erfahren Sie auch in allen Einzelheiten, wie der Debugger bedient und<br />

praktisch eingesetzt wird. Dieses Wissen ist eine wichtige Unterstützung bei der<br />

Durchführung effektiver Tests.<br />

Außerdem erhalten Sie eine ausführliche, anschauliche Darstellung zur objektorientierten<br />

Programmierung unter <strong>LotusScript</strong>. Ein gutes Verständnis dieses Punktes<br />

wird Ihnen bei der Bildung qualitativ hochwertiger Architekturen sehr behilflich<br />

sein.<br />

Die Darlegung des Stoffes beginnt zunächst sehr detailliert, um Sie beim Einstieg<br />

sicher zu begleiten und zieht dann im Tempo recht schnell an, um Sie schnellstmöglich<br />

zu den wesentlichen Erkenntnissen zu führen, die Sie <strong>für</strong> eine erfolgreiche<br />

Erstellung und Wartung auch komplexer Programme benötigen.<br />

IBM SOFTWARE PRESS


Einführung in die<br />

<strong>LotusScript</strong>-<br />

Programmierung<br />

Die Programmierung mit <strong>LotusScript</strong> ähnelt sehr der Programmierung mit VBA<br />

(Visual Basic for Applications von Microsoft). Abgesehen von der engen Sprachverwandtschaft,<br />

werden beide in Verbindung mit grafischen Benutzeroberflächen<br />

verwendet. Wer also Erfahrung mit der Erstellung von Makros in Microsoft-Office-<br />

Produkten hat, wird sich mit <strong>LotusScript</strong> sehr leicht tun.<br />

Für Programmierer, die gerade erst beginnen oder mit grafischen Benutzeroberflächen<br />

weniger Erfahrung haben, müssen einige grundlegende Dinge kurz erläutert<br />

werden, damit sie einen guten Einstieg finden.<br />

Wir beginnen gleich praxisorientiert; Learning-by-Doing ist häufig der schnellste<br />

Weg, um Dinge richtig zu »begreifen«. Sie können also jetzt das erste Programm<br />

»anfassen«.<br />

3.1 <strong>Das</strong> erste Programm<br />

<strong>LotusScript</strong>-Programme sind immer Teil einer <strong>Notes</strong>-Datenbank; sie können nicht<br />

frei davon existieren. Wir erstellen also zunächst einmal eine neue Datenbank (ab<br />

Version 8 auch Anwendung genannt) im <strong>Notes</strong>-Client.<br />

3.1.1 Neue Anwendung (Datenbank) anlegen<br />

Wählen Sie dazu im Menü DATEI/ANWENDUNG/NEU... (Abbildung 3.1).<br />

Abbildung 3.1 <strong>Das</strong> Erstellen einer neuen Anwendung (Datenbank)<br />

IBM SOFTWARE PRESS


32 Einführung in die <strong>LotusScript</strong>-Programmierung<br />

Im sich anschließenden Dialog geben Sie einen Titel <strong>für</strong> die Datenbank und den<br />

Dateinamen und inklusive Pfad an. Wenn Sie den Titel eintragen, wird dieser automatisch<br />

auch als Dateiname vorgeschlagen. Sie können den Dateinamen jetzt<br />

natürlich nach Belieben verändern. Außerdem wird dem Namen die Endung .nsf<br />

angehängt. <strong>Das</strong> ist die Standardendung <strong>für</strong> <strong>Notes</strong>-Datenbanknamen.<br />

Ich gebe der Datenbank in meinem Beispiel den Namen <strong>LotusScript</strong>-Programmierung,<br />

und zwar <strong>für</strong> TITEL und DATEINAME. Sie können es mir nachmachen oder einen<br />

anderen Namen wählen. Alle übrigen Einstellungen lassen wir unverändert und<br />

klicken auf OK (Abbildung 3.2).<br />

Abbildung 3.2 Titel und Dateinamen der neuen Datenbank festlegen<br />

Sofort wird die Datenbank erstellt und auch gleich geöffnet (Abbildung 3.3).<br />

Abbildung 3.3 Die neue Datenbank wird gleich geöffnet.


<strong>Das</strong> erste Programm 33<br />

Sie sehen in der linken Spalte oben den Titel und darunter ein Symbol <strong>für</strong> die automatisch<br />

erstellte, noch unbenannte Vorgabe-Ansicht. Diese ist im rechten Teil zu<br />

sehen. Ihre einzige Spalte trägt im Kopf das Nummernsymbol #. Natürlich sind<br />

noch keine Dokumente enthalten.<br />

Diese brauchen wir jetzt aber erst einmal gar nicht. Wichtig ist, dass wir unsere<br />

Datenbank haben, die als Container <strong>für</strong> die zu erstellenden Programme dient.<br />

Hinweis<br />

Wie ich bereits gesagt habe, sind <strong>LotusScript</strong>-Programme immer Teil einer<br />

<strong>Notes</strong>-Datenbank; sie können nicht frei davon existieren – und umgekehrt:<br />

Wenn man in <strong>Notes</strong> eine Anwendung mit <strong>LotusScript</strong> schreibt, dann besteht<br />

diese immer aus mindestens einer Datenbank.<br />

Wohl auch deshalb werden <strong>Notes</strong>-Datenbanken ab Version 8 auch als Anwendungen<br />

bezeichnet. Daher werde ich die beiden Begriffe in diesem Buch auch<br />

schon mal synonym gebrauchen.<br />

Trotzdem werden Sie schnell merken, dass Anwendungen aus Entwicklersicht<br />

aus einer oder mehreren Datenbanken bestehen, also begrifflich eigentlich<br />

davon zu trennen sind. Während die Anwendung mehr das Gesamtprodukt<br />

aus Benutzersicht darstellt, haben wir es als Programmierer eher mit den<br />

Datenbanken als Trägern der Applikationen zu tun.<br />

Der hauptsächliche Grund, warum Datenbanken von IBM jetzt als »Anwendungen«<br />

bezeichnet werden, liegt wahrscheinlich in der Einführung des Konzepts<br />

der Verbundanwendungen (Composite Applications).<br />

<strong>Das</strong> Ziel dabei ist es, mithilfe einer Webservice-Architektur <strong>für</strong> klare Schnittstellen<br />

zwischen Einzelapplikationen zu sorgen, die dann zu Verbundanwendungen<br />

zusammengestellt werden können. Mehr dazu finden Sie im Kapitel<br />

16, Verbundanwendungen, ab Seite 563.<br />

3.1.2 Anwendung (Datenbank) zur Programmierung öffnen<br />

Wir werden die Datenbank jetzt im Designer öffnen, um mit der Programmierung<br />

beginnen zu können. Schließen Sie dazu die Datenbank mit einem Klick auf das<br />

kleine x-förmige Kreuz auf dem Reiter LOTUSSCRIPT-PROGRAMMIERUNG. Danach<br />

sehen Sie die automatisch angelegte Kachel der Datenbank auf dem Arbeitsbereich<br />

(Kacheln dienen als ein visueller Zugang zu <strong>Notes</strong>-Datenbanken). Klicken Sie<br />

anschließend mit der rechten Maustaste auf die Kachel, und wählen Sie IN DESIG-<br />

NER ÖFFNEN aus (Abbildung 3.4).<br />

IBM SOFTWARE PRESS


34 Einführung in die <strong>LotusScript</strong>-Programmierung<br />

Abbildung 3.4 Die Datenbank im Designer öffnen<br />

Es öffnet sich dann automatisch der <strong>Domino</strong> Designer, das hauptsächliche Programmierhandwerkzeug<br />

des <strong>Notes</strong>/<strong>Domino</strong>-Programmierers. Unsere Datenbank<br />

wird in Programmierdarstellung angezeigt (Abbildung 3.5).<br />

Abbildung 3.5 Die neue Datenbank im <strong>Domino</strong> Designer, fertig zum Erstellen des ersten Programms<br />

Im linken Bereich sehen Sie eine baumartige Darstellung der einzelnen Datenbank-<br />

Elemente, die im Designer bearbeitet werden können: Rahmengruppen, Seiten,<br />

Masken usw. Vieles davon kann mit <strong>LotusScript</strong> programmiert werden.<br />

Hinweis<br />

Sie sehen, dass ich die Datenbanken respektive Anwendungen über den<br />

Arbeitsbereich verwalte. Eigentlich ist dies eine veraltete Benutzeroberfläche,<br />

die das Erscheinungsbild von <strong>Notes</strong> in der Vergangenheit sehr geprägt hat.<br />

Vor einiger Zeit wurden unter anderem die Lesezeichen eingeführt, um <strong>Notes</strong><br />

moderner erscheinen zu lassen. Für Benutzer mag dies sehr praktisch und<br />

auch ansprechender sein. Zumal die Lesezeichen unter <strong>Notes</strong> 8 in der Standardkonfiguration<br />

in ein sehr schönes ÖFFNEN-Menü überführt worden sind<br />

(Abbildung 3.6).


<strong>Das</strong> erste Programm 35<br />

Abbildung 3.6 Die Lesezeichen im neuen Eclipse-basierten Client der <strong>Notes</strong> 8-<br />

Standardkonfiguration. Sie werden jetzt als ÖFFNEN-Menü dargestellt.<br />

Für Entwickler und Administratoren zeigt sich in der Praxis, dass der gute alte<br />

Arbeitsbereich mit seinen Arbeitsbereichsseiten und Kacheln trotzdem kaum<br />

zu ersetzen ist. Die Art der Anordnung ist im ersten Moment etwas gewöhnungsbedürftig,<br />

erweist sich dann aber als sehr gut geeignet, um die Übersicht<br />

über große Mengen von Datenbanken zu behalten.<br />

Sie erreichen den Arbeitsbereich in der Standardkonfiguration (wie in Abbildung<br />

3.61.6 gezeigt) oder in der Basiskonfiguration über das Lesezeichen<br />

ANWENDUNGEN in der linken Navigationsleiste (siehe Abbildung 3.7).<br />

IBM SOFTWARE PRESS


36 Einführung in die <strong>LotusScript</strong>-Programmierung<br />

Abbildung 3.7 Öffnen Sie den Arbeitsbereich mit den Kacheln über die Lesezeichenleiste.<br />

3.1.3 Unser erstes Programm: Einen Agenten erstellen<br />

Wir werden jetzt einen sogenannten Agenten erstellen, der unser erstes Programm<br />

ausführt.<br />

Klicken Sie dazu bitte auf GEMEINSAMER CODE und AGENTEN (Abbildung 3.8).<br />

Abbildung 3.8 Schritte zum neuen Agenten<br />

Sie sehen rechts eine leere Liste, in der Sie später den neuen Agenten wiederfinden<br />

werden, den Sie jetzt bitte mit einem Klick auf die Aktion NEUER AGENT rechts oben<br />

erstellen.<br />

Es öffnet sich ein Dialog, in dem wir unserem Agenten einen fantasievollen Namen<br />

mit hohem Wiedererkennungswert geben (diejenigen unter Ihnen, die bereits eine


<strong>Das</strong> erste Programm 37<br />

andere Programmiersprache erlernt haben, werden höchstwahrscheinlich wissen,<br />

was ich damit meine), nämlich “Hello World“ (siehe Abbildung 3.9).<br />

Abbildung 3.9 Die Einstellungen <strong>für</strong> den neuen Agenten<br />

Es ist wichtig, dass wir unter LAUFZEIT das richtige ZIEL eingeben, nämlich Keines.<br />

<strong>Das</strong> ist übrigens eine Einstellung, die <strong>für</strong> viele <strong>LotusScript</strong>-Programme genau die<br />

richtige ist, da Sie damit in der Regel die meisten Möglichkeiten bei der Kodierung<br />

haben. Allerdings können Sie in diesem Fall die Dokumentauswahl durch den<br />

Agenten nicht nutzen. Diese muss dann im Script programmiert werden.<br />

Schließen Sie nun den Dialog mit dem kleinen Kreuz rechts oben. Sie werden dann<br />

den neuen Agenten wie in Abbildung 3.10 geöffnet vor sich sehen. Wir müssen nur<br />

noch die richtige Programmierart auswählen (viele <strong>Notes</strong>-Datenbankelemente<br />

können mit unterschiedlichen Sprachen programmiert werden). Schalten Sie<br />

rechts oben von EINFACHE AKTION(EN) auf LOTUSSCRIPT um.<br />

Abbildung 3.10 Programmierart bzw. -sprache auswählen (Schalten Sie von EINFACHE AKTION(EN) auf<br />

LOTUSSCRIPT um.)<br />

Jetzt sind wir schon an der Stelle, an der wir richtig in <strong>LotusScript</strong> kodieren können.<br />

(»Endlich!«, werden Sie vielleicht sagen. Aber diese wenigen Schritte werden<br />

Ihnen schnell in Fleisch und Blut übergehen.)<br />

IBM SOFTWARE PRESS


38 Einführung in die <strong>LotusScript</strong>-Programmierung<br />

Hinweis<br />

Doch halt, wozu brauchen wir eigentlich einen Agenten?<br />

Nun, <strong>LotusScript</strong> lässt sich nicht als eigenständiges Programm schreiben.<br />

<strong>LotusScript</strong> kann nicht von der Kommandozeile gestartet werden. Es muss<br />

immer in irgendwelche Datenbankbestandteile eingebettet werden.<br />

Der klassischen Vorstellung von einem »richtigen Programm« kommt dabei<br />

das Datenbankelement Agent noch am nächsten, und deswegen beginnen wir<br />

mit der Programmierung eines solchen.<br />

Einen Agenten können Sie sich als eine Hülle, einen Container oder auch als<br />

ein Rahmenwerk <strong>für</strong> Ihr <strong>LotusScript</strong>-Programm vorstellen. Wir betten das<br />

Programm dort ein und lassen es dann vom Agenten ausführen.<br />

Später werden Sie Programme auch an anderen Stellen einbauen, zum Beispiel<br />

in Masken oder Schaltflächen.<br />

Den Agenten mit <strong>LotusScript</strong>-Code versehen<br />

Wir können unseren Agenten gleich, direkt nach seiner Fertigstellung, über das<br />

Menü des <strong>Notes</strong>-Clients starten. Wenn der Agent startet, dann wird er automatisch<br />

den Code ausführen, der in seinem INITIALIZE-Abschnitt steht. Diesen Code werden<br />

wir jetzt noch schnell einfügen.<br />

Abbildung 3.11 <strong>LotusScript</strong>-Ansicht des Agenten “Hello World“<br />

Klicken Sie also bitte links in der Liste auf INITIALIZE (Abbildung 3.11), und geben<br />

Sie dann rechts Folgendes ein:<br />

Messagebox "Hello World. I’m the champion!"<br />

<strong>Das</strong> war’s schon. <strong>Das</strong> ist Ihr erstes <strong>LotusScript</strong>-Programm (Abbildung 3.12).<br />

Abbildung 3.12 <strong>Das</strong> “Hello World“-Programm


<strong>Das</strong> erste Programm 39<br />

Nach getaner Arbeit möchten wir natürlich sehen, wie dieses aufwendige und<br />

wichtige Programm in der Realität arbeitet. Dazu schließen Sie bitte den Agenten<br />

mit dem kleinen Kreuz oben in seinem Fenster-Reiter. Sie werden gefragt werden,<br />

ob Sie Ihre Änderungen speichern möchten, und dazu sagen Sie selbstverständlich<br />

ja. Anschließend können Sie Ihr fertiges Produkt in der Liste der Agenten bewundern<br />

(Abbildung 3.13).<br />

Abbildung 3.13 Der fertige “Hello World“-Agent<br />

Den Agenten starten<br />

Sie können den Agenten jetzt über das Menü mit AGENT/STARTEN laufen lassen.<br />

(Dazu muss sich der blaue Cursorbalken auf dem Agenten befinden, so wie es in<br />

Abbildung 3.13 zu sehen ist.) Oder Sie klicken mit der rechten Maustaste auf den<br />

Agenten in der Liste und wählen aus dem Kontextmenü den Punkt STARTEN aus<br />

(siehe Abbildung 3.14 und Abbildung 3.15).<br />

Abbildung 3.14 So starten Sie den Agenten über das Designer-Menü.<br />

Abbildung 3.15 So starten Sie den Agenten über das Kontextmenü.<br />

IBM SOFTWARE PRESS


40 Einführung in die <strong>LotusScript</strong>-Programmierung<br />

Egal, wie Sie den Agenten starten, als Resultat erhalten Sie folgende Ausgabe (Abbildung<br />

3.16):<br />

Abbildung 3.16 Die Ausgabe unseres ersten <strong>LotusScript</strong>-Programms<br />

3.2 Die grundlegenden Schritte zur Erstellung<br />

von <strong>LotusScript</strong>-Programmen<br />

Nachdem wir so erfolgreich waren, können wir uns erst einmal zurücklehnen und<br />

in Ruhe rekapitulieren, was wir genau gemacht haben – und wie wir diese Erkenntnisse<br />

in Zukunft verwenden können.<br />

Schritt 1<br />

Wir haben einen Agenten erstellt, der als Container <strong>für</strong> unser Programm dient.<br />

In anderen Fällen werden Sie auch Masken, Seiten, Schaltflächen und andere Elemente<br />

verwenden.<br />

Schritt 2<br />

Wir haben uns einen geeigneten »Startpunkt« <strong>für</strong> unseren Code gesucht und sind<br />

mit Sub Initialize fündig geworden.<br />

In Masken sind beliebte Startpunkte Sub PostOpen, Sub QueryClose usw. Ähnlich verhält<br />

es sich bei Seiten, Ansichten und Datenbank-Scripts. Man nennt sie auch<br />

Eventhandler (Routinen zur sogenannten Ereignisbehandlung). Weitere Details<br />

dazu finden Sie im Abschnitt 3.9, Weitere Startpunkte <strong>für</strong> <strong>LotusScript</strong>-Programme, auf<br />

Seite 66.<br />

Schritt 3<br />

Im Eventhandler Sub Initialize haben wir unseren Code eingegeben. Und das wird<br />

bei anderen Startpunkten natürlich genauso gehandhabt.<br />

Schritt 4<br />

Dann haben wir den Agenten geschlossen. Dabei wurde er gespeichert.<br />

Syntaxüberprüfung und Kompilierung<br />

Aber hier ist noch etwas mehr passiert. <strong>Das</strong> Programm wurde automatisch auf korrekte<br />

Syntax hin untersucht und kompiliert.<br />

Hätten Sie einen syntaktischen Fehler gemacht (also etwas geschrieben, was Lotus-<br />

Script nicht versteht), dann hätten Sie eine entsprechende Fehlermeldung erhal-


Die grundlegenden Schritte zur Erstellung von <strong>LotusScript</strong>-Programmen 41<br />

ten. Sie können ja den Agenten spaßeshalber noch einmal öffnen und Messagebox in<br />

Massagebox ändern (ein beliebter Rechtschreibfehler). Versuchen Sie dann, den<br />

Agenten noch einmal zu speichern. <strong>Das</strong> können Sie diesmal tun, ohne ihn zu<br />

schließen. Wählen Sie einfach im Menü DATEI/SPEICHERN aus, oder klicken Sie auf<br />

das Diskettensymbol in der Toolbar-Leiste. Auch die Verwendung von [Strg] + [S]<br />

ist möglich. Auf jeden Fall erhalten Sie die Meldung aus Abbildung 3.17.<br />

Abbildung 3.17 Die Syntaxprüfung hat im Code einen Fehler erkannt.<br />

Den Fehler hätten Sie in diesem Fall auch schon vorher sehen können, denn der<br />

<strong>LotusScript</strong>-Editor prüft die verwendeten Begriffe und Operatoren bereits während<br />

der Eingabe. Wenn er bekannte Schlüsselwörter erkennt, dann färbt er sie blau ein.<br />

Messagebox ist ein solches Schlüsselwort und wird erkannt. Nachdem wir aber das<br />

erste »e« gegen ein »a« ausgetauscht hatten, handelte es sich um keinen bekannten<br />

(eingebauten) Begriff mehr, und Massagebox wurde schwarz.<br />

Man kann also schon während der Eingabe erkennen, ob man die richtigen Schlüsselwörter<br />

verwendet.<br />

Schritt 5<br />

Zum Schluss haben wir den Agenten gestartet. Was dann passierte, ist wichtig <strong>für</strong><br />

das Grundverständnis aller <strong>LotusScript</strong>-Programme.<br />

Der <strong>Notes</strong>-Client hat beim Start die Kontrolle übernommen. Er weiß, dass in einem<br />

Agenten eine Prozedur namens Sub Initialize vorkommen muss. Eine Prozedur ist<br />

eine Funktion ohne Rückgabewert. Mehr dazu folgt später im Abschnitt 3.5, Eine<br />

eigene Prozedur schreiben. Der Client weiß das also und startet sie <strong>für</strong> uns. Damit kam<br />

dann auch unsere Codezeile Messagebox “Hello World. I’m the champion!“ zur Ausführung.<br />

Prozeduren beginnen immer mit dem Kopf Sub und enden unten mit<br />

dem Anweisungsteil End Sub. Dazwischen steht der Code, der von der Prozedur ausgeführt<br />

werden soll. In unserem Fall lautet die gesamte Prozedur:<br />

Sub Initialize<br />

Messagebox "Hello World. I’m the champion!"<br />

End Sub<br />

Wir haben allerdings nur die mittlere Zeile hingeschrieben, weil der Client wie<br />

gesagt weiß, dass ein Agent eine Prozedur Initialize haben muss, und daher den<br />

»Rahmen«, nämlich Kopf und Fuß, schon selbst hingeschrieben hat.<br />

Der Hinweis, dass das Programm beim Speichern kompiliert wurde, braucht Sie im<br />

Prinzip nicht weiter zu interessieren.<br />

IBM SOFTWARE PRESS


42 Einführung in die <strong>LotusScript</strong>-Programmierung<br />

Hinweis<br />

Falls Sie es doch genauer wissen wollen, nur so viel zur Erklärung:<br />

Der Code wird beim Kompilieren in eine andere Form gebracht; eine Form,<br />

die vom <strong>LotusScript</strong>-Interpreter verstanden werden kann.<br />

Der Interpreter ist ein internes Programm, das beim Aufruf von <strong>LotusScript</strong>-<br />

Code die Anweisungen ausführt, die der Entwickler notiert hat (wie Messagebox).<br />

Diese Form des auszuführenden Codes nennt man Objektcode.<br />

Der Objektcode wird <strong>für</strong> den Benutzer unsichtbar neben dem vom Entwickler<br />

geschriebenen Programm abgespeichert.<br />

3.3 Variablen – die temporären Speicherplätze<br />

Wenn man in Programmen mit Daten, Werten und Texten arbeitet, dann ist es<br />

nicht immer praktisch, sie direkt hinzuschreiben. Ja, in der Regel ist es gar nicht<br />

möglich. Bei unserem letzten Beispiel war das noch völlig in Ordnung. Wir haben<br />

den Text “Hello World. I’m the champion!“ einfach hingeschrieben, und Messagebox<br />

war damit zufrieden.<br />

Jetzt möchten wir aber gern eine wiederholte Ausgabe tätigen, bei der ein bestimmter<br />

Textteil immer gleich ist. Dann ist es natürlich zeitsparender, wenn wir ihn nur<br />

einmal hinzuschreiben brauchen. Dazu müssen wir ihn irgendwo speichern, damit<br />

er uns auf Wunsch immer wieder zur Verfügung steht. Da wir den Wert nur während<br />

des Programmablaufs benötigen, reicht es, ihn temporär zu speichern (also im<br />

Arbeitsspeicher statt auf der Festplatte).<br />

Die Antwort auf diese Herausforderung lautet: Variablen.<br />

Variablen<br />

Variablen sind benannte Speicherplätze, auf die während eines Programmablaufs<br />

zugegriffen werden kann. In <strong>LotusScript</strong> sind Variablen immer veränderbar,<br />

d. h., ihnen können während des Programmablaufs jederzeit neue<br />

Werte zugewiesen werden.<br />

3.3.1 Variablen deklarieren<br />

Eine Variable wird meistens mit der Anweisung Dim erstellt. Beispielsweise so:<br />

Dim strVariablenName As String<br />

Dim ist die Abkürzung des englischen Begriffs Dimension und bedeutet »Dimensionierung,<br />

Maßangabe«. Mit Dim wird also der gewünschte Speicherplatz »dimensioniert«.<br />

Man nennt diesen Vorgang auch Deklaration.<br />

Bei Programmvariablen gehört dazu nicht nur die Größe, sondern auch die Art der<br />

Daten, die dort eingelagert werden sollen. Zum einen hilft das der Speicherverwal-


Variablen – die temporären Speicherplätze 43<br />

tung im Hintergrund, sich auf das einzustellen, was da kommt, und zum anderen<br />

hilft es, mögliche logische Fehler bei der Datenzuordnung von vornherein besser<br />

zu erkennen.<br />

Achtung<br />

Variablen müssen immer vor ihrer ersten Verwendung deklariert werden. Tun<br />

Sie dies nicht, dann kann es sein, dass <strong>LotusScript</strong> dies <strong>für</strong> Sie unsichtbar im<br />

Hintergrund tut. <strong>Das</strong> sollten Sie aber unterbinden, indem Sie immer im<br />

Abschnitt (Options) Folgendes eingeben: Option Declare (oder Option Explicit,<br />

was funktional dasselbe ist). Mehr dazu finden Sie im Abschnitt 4.2 Optionen<br />

und Voreinstellungen, ab Seite 130.<br />

Die Angabe As String sagt aus, dass in dem angeforderten Speicherplatz eine Zeichenkette<br />

abgelegt werden soll (in unserem Hello World-Programm war das eine<br />

Aneinanderreihung von Buchstaben). Außerdem wird auf diese Weise klargemacht,<br />

dass über die Größe noch nicht viel gesagt werden kann. String-Variablen<br />

können nämlich während des Programmablaufs fast beliebig wachsen und auch<br />

schrumpfen.<br />

Hinweis<br />

Es gibt auch die Möglichkeit, String-Variablen mit fester Länge zu deklarieren.<br />

Außerdem gibt es natürlich auch andere Arten von Variablen, zum Beispiel<br />

zur Verwaltung von Zahlen. Man spricht dabei von verschiedenen Datentypen.<br />

Der Begriff direkt nach Dim ist der Name, der dieser Variablen gegeben wird (str-<br />

VariablenName). Unter diesem Namen kann auf die Variable und damit auf den mit<br />

ihr verbundenen Speicherplatz zugegriffen werden.<br />

Bei der Wahl des Namens ist man sehr flexibel. So kann man zum Beispiel jede Buchstabenkombination<br />

unseres Alphabets wählen, solange sich kein Begriff ergibt, der<br />

schon von der <strong>LotusScript</strong>-Sprache selbst belegt ist.<br />

In diesem Beispiel habe ich mit str ein Präfix verwandt, das dem Leser des Programms<br />

deutlich macht, dass es sich hier um eine String-Variable handelt. Auf die<br />

Funktion der Variablen hat das keinerlei Einfluss. Solche Präfixe sind aber sehr<br />

praktisch, um auch bei langen Programmen den Überblick zu behalten, was <strong>für</strong><br />

Daten in welchen Variablen abgelegt werden.<br />

Ich kann Sie nur dazu ermuntern, sich einen entsprechenden Styleguide anzugewöhnen.<br />

Verwenden Sie <strong>für</strong> Variablennamen immer Präfixe, und zwar möglichst<br />

gängige bzw. sprechende Präfixe. Auch die Namen der Variablen sollten möglichst<br />

klar <strong>für</strong> den Inhalt oder die Verwendung sprechen. <strong>Das</strong> sollten Sie auch dann tun,<br />

wenn Sie erfahrene Programmierer kennenlernen, die sich über solche Regeln hinwegsetzen.<br />

IBM SOFTWARE PRESS


44 Einführung in die <strong>LotusScript</strong>-Programmierung<br />

Datentyp-Suffixe<br />

In Basic-Sprachen wie <strong>LotusScript</strong> kann man viele Datentypen statt mit der Formulierung<br />

As Datentyp auch mit einem Suffix angeben.<br />

Für String-Variablen lautet das Suffix $, und so könnten wir die obige Deklaration<br />

auch wie folgt notieren:<br />

Dim strVariablenName$<br />

Diese Art der Deklaration hat den Vorteil, dass Sie weniger schreiben müssen und<br />

mit ein wenig Übung die manchmal lange Liste der Datendeklarationen schneller<br />

überblicken können.<br />

Beispieldeklarationen <strong>für</strong> weitere Datentypen<br />

Bei den folgenden Deklarationen sind zu Ihrer Orientierung einige Deklarationen<br />

ohne und mit Suffix gegenübergestellt:<br />

Dim iKleineGanzzahl As Integer<br />

Dim iKleineGanzzahl%<br />

Dim lngGroßeGanzzahl As Long<br />

Dim lngGroßeGanzzahl&<br />

Dim sngKleineFließkommazahl As Single<br />

Dim sngKleineFließkommazahl!<br />

Dim dblGroßeFließkommazahl As Double<br />

Dim dblGroßeFließkommazahl#<br />

Für die folgenden Deklarationen gibt es keine Suffixe:<br />

Dim byteOktett As Byte<br />

Dim bWahrheitswert As Boolean<br />

Dim vEinZiemlichBeliebigerInhalt As Variant<br />

3.3.2 Einen Wert zuweisen<br />

Einer Variablen wird ihr Wert mit dem Zuweisungsoperator = zugeordnet.<br />

Als Beispiel erstellen wir die Variable strAnzeigeText und weisen ihr die nachher<br />

mehrfach zu verwendende Zeichenkette “Hello World. I’m the champion!“ zu:<br />

Dim strAnzeigeText As String<br />

strTextteil = “Hello World. I’m the champion!“<br />

Der Name der Variablen, die den Wert aufnimmt, steht links. Der Wert steht immer<br />

rechts.<br />

Will man Variableninhalte ändern, weist man einfach einen neuen Wert zu.


Ausdrücke erstellen und verwenden 45<br />

3.3.3 Auf eine Variable zugreifen<br />

Der Zugriff auf den Wert einer Variablen ist denkbar einfach. Man übergibt an der<br />

Stelle, an der der eigentliche Wert stehen müsste, den Variablennamen. <strong>Das</strong> Programm<br />

sucht sich dann zur Laufzeit die entsprechende Speicherstelle und holt von<br />

dort die hinterlegten Daten.<br />

Zum Beispiel könnten wir mit einem Aufruf von Messagebox den Text ausgeben, der<br />

vorhin in der Variablen strTextteil gespeichert wurde:<br />

Messagebox strTextteil<br />

Komplett dargestellt, würde der Code so ausssehen:<br />

Sub Initialize<br />

Dim strAnzeigeText As String<br />

strAnzeigeText = “Hello World. I’m the champion!“<br />

Messagebox strAnzeigeText<br />

End Sub<br />

Achtung<br />

Wenn man eine Variable im Programm anspricht, deren Datentyp mit einem<br />

Suffix angegeben wurde, dann kann man das Suffix als Namensbestandteil<br />

gebrauchen, muss es aber nicht tun. Im nächsten Beispiel werden Sie beide<br />

Möglichkeiten nebeneinander sehen.<br />

Allerdings sollten Sie sich <strong>für</strong> eine davon entscheiden. Nichts ist unübersichtlicher,<br />

als wenn man solche Verfahrensweisen mitten im Code ändert! Die<br />

Mischung zeige ich hier nur einmal, um die Gleichwertigkeit zu veranschaulichen.<br />

Wenn eine Variable ohne Suffix deklariert wurde, dann muss sie in der Folge<br />

auch ohne Suffix verwendet werden.<br />

3.4 Ausdrücke erstellen und verwenden<br />

Jetzt möchten wir die Variable wie bereits angedeutet nutzen, um mehrere ähnlich<br />

lautende Ausgaben mit Messagebox zu machen, ohne die sich wiederholenden Texte<br />

jedes Mal neu hinzuschreiben. Dazu benötigen wir eine Möglichkeit, um zwei Zeichenketten<br />

aneinanderzuhängen, und das ist der Zeichenketten-Operator &.<br />

Wir kommen gleich zur Sache und schreiben:<br />

Sub Initialize<br />

Dim strAnzeigeText$<br />

strAnzeigeText$ = “Hello World. I’m the champion!“<br />

IBM SOFTWARE PRESS


46 Einführung in die <strong>LotusScript</strong>-Programmierung<br />

Messagebox strAnzeigeText & “ Gestern!”<br />

Messagebox strAnzeigeText$ & “ Heute!”<br />

Messagebox strAnzeigeText & “ Morgen!”<br />

End Sub<br />

Listing 3.1 So verwenden Sie eine Variable in Verbindung mit dem Zeichenkettenoperator &,<br />

um mehrere ähnliche Texte zu bilden.<br />

Während sich das leicht größenwahnsinnige Progrämmchen immer mehr aufbläht,<br />

wird dreimal Messagebox aufgerufen, und jedes Mal wird vom &-Operator eine<br />

Kombination aus “Hello World. I’m the champion!“ und dem sich ändernden<br />

Anhängsel “ Gestern!“, “ Morgen!“ usw. gebildet und dann als Meldung ausgegeben.<br />

Eine solche Berechnung von Werten nennt man auch Ausdruck. Der Ausdruck lautet<br />

hier im ersten Fall: strAnzeigeText & “ Gestern!”.<br />

Ausdruck<br />

Ein Ausdruck ist eine wie auch immer geartete Berechnung von Werten. Die<br />

Berechnung kann auch unter Einbeziehung von Funktionen und Objekten<br />

erfolgen.<br />

Wenn Sie noch kein so routinierter Programmierer sind, dann wird Ihnen die Definition<br />

etwas schwierig bzw. schwammig vorkommen. Die Frage ist: Wo beginnt ein<br />

Ausdruck, und wo hört er auf? Und zu den Begriffen Funktion und Objekt kommen<br />

wir erst später. Am besten ist es, Sie vergessen das Thema erst einmal wieder. Die<br />

genaue Abgrenzung dieses Begriffs ist in der Praxis des <strong>LotusScript</strong>-Entwicklers<br />

nicht so wichtig. Außerdem wird er immer mal wieder in recht harmlosen Zusammenhängen<br />

auftauchen, und dann wird die genaue Bedeutung ganz nebenbei<br />

immer klarer.<br />

Was Sie allerdings wissen sollten: Fast überall, wo ein Wert oder der Inhalt einer<br />

Variablen benötigt wird, können Sie stattdessen auch einen Ausdruck notieren.<br />

Dieser wird dann automatisch berechnet, und der sich ergebende Wert wird an seiner<br />

Stelle übergeben. <strong>Das</strong> haben Sie gerade gesehen, als wir der Variablen strAnzeigeText<br />

zunächst eine Zeichenkette, dann aber mehrfach einen Ausdruck nach der<br />

Art strAnzeigeText & “ Gestern!” zugewiesen haben.<br />

Hier haben wir eine sehr einfache Berechnung mit Zeichenketten vorgenommen.<br />

Andere Ausdrücke können Berechnungen von Zahlen- und Datumswerten (numerische<br />

Ausdrücke) und von Wahrheitswerten (boolesche Ausdrücke) einschließen.<br />

3.4.1 Numerische Ausdrücke<br />

Beispiel <strong>für</strong> eine Zahlenberechnung:<br />

Dim iErgebnis%<br />

iErgebnis = 10 * 2.5 – 3


Ausdrücke erstellen und verwenden 47<br />

Der Ausdruck ist hier: 10 * 2.5 – 3. Dieser (bzw. sein Wert) wird der Variablen iErgebnis<br />

zugeordnet. Durch die Zuordnung wird der Ausdruck automatisch berechnet.<br />

Hinweis<br />

Unser deutsches Dezimalkomma ist im Englischen ein Punkt und wird so<br />

auch von <strong>LotusScript</strong> gefordert.<br />

Vorrangregeln<br />

Bei der Berechnung von Ausdrücken gelten gewisse Vorrangregeln, die im Bereich<br />

der arithmetischen Berechnungen an den mathematischen Usus angelehnt ist.<br />

Zum Beispiel gilt »Punktrechnung von Strichrechnung«. Der Ausdruck 10 * 2.5 – 3<br />

wird also zunächst zu 25 – 3 und ergibt das Resultat 22.<br />

Wollten wir es anders haben, so müssten wir entsprechende Klammern setzen:<br />

10 * (2.5 – 3) wird ausgewertet zu 10 * (-0.5) und gibt -5.<br />

3.4.2 Boolesche Ausdrücke<br />

Boolesche Ausdrücke werden mit den Wahrheitswerten True und False und den<br />

Operatoren And, Or und Not gebildet:<br />

True And True ergibt True.<br />

True And False ergibt False.<br />

False And True ergibt False.<br />

False And False ergibt True.<br />

Not True ergibt False.<br />

Not False ergibt True.<br />

Natürlich werden die Ausdrücke in der Regel nicht buchstäblich so gebildet wie<br />

hier gezeigt. Statt der einzelnen Wahrheitswerte True und False werden Ausdrücke<br />

übergeben, die diese Werte zurückgeben. Solche Ausdrücke ergeben sich aufgrund<br />

von Vergleichen oder Rückgabewerten von Funktionen. Beispiele:<br />

1 < iWert% AND 1000 > iWert% ermittelt, ob der Wert der Integer-Variablen iWert1 zwischen<br />

1 und 1000 liegt.<br />

IsNumeric(vWert) ermittelt durch die Funktion IsNumeric, ob die Variant-Variable<br />

vWert einen numerischen Wert enthält.<br />

Auch die Ergebnisse von booleschen Ausdrücken lassen sich einer Variablen zuweisen:<br />

Dim bErgebnis As Boolean<br />

bErgebnis = 1 < iWert% AND 1000 > iWert%<br />

IBM SOFTWARE PRESS


48 Einführung in die <strong>LotusScript</strong>-Programmierung<br />

Hinweis<br />

Vor längerer Zeit gab es in <strong>LotusScript</strong> keinen eigenen Datentyp <strong>für</strong> Wahrheitswerte.<br />

Statt Boolean nahm man häufig Integer-Variablen.<br />

In diesem Fall wurde die 0 als False gewertet und jeder andere Wert als True.<br />

Intern wird nach wie vor False mit dem Wert 0 gleichgesetzt und True mit -1.<br />

Sie werden wahrscheinlich noch auf das eine oder andere Script stoßen, in<br />

dem Integer-Werte <strong>für</strong> Wahrheitswerte verwendet werden. Lassen Sie sich<br />

dadurch nicht verwirren. Mit diesem Hintergrundwissen gewappnet, können<br />

Sie mit diesen Werten praktisch genauso rechnen, als würden »echte« Wahrheitswerte<br />

vorliegen.<br />

Vorrangregeln<br />

Auch bei booleschen Ausdrücken gelten gewisse Vorrangregeln. So wird zunächst<br />

die Negation Not berechnet, dann And und schließlich Or. Auch hier lassen sich die<br />

Regeln durch Klammerungen umgehen.<br />

Not False Or True ‘ergibt True Or True und das ist True<br />

Not (False Or True) ‘ergibt Not True und das ist False<br />

3.5 Eine eigene Prozedur schreiben<br />

Nach dem Erfolg in Abschnitt 3.1, <strong>Das</strong> erste Programm, auf Seite 31, juckt es Sie<br />

sicherlich in den Fingern, etwas mehr zu tun. Als ersten Schritt werden wir eine<br />

eigene Prozedur schreiben und diese dann anschließend von der Prozedur Sub Initialize<br />

aufrufen (ausführen) lassen. Vorher sollten wir noch kurz klären, was eine<br />

Prozedur eigentlich genau ist.<br />

Prozedur<br />

Prozeduren sind benannte Programmteile, die über ihren Namen zum Zwecke<br />

der Ausführung einmal oder mehrmals aufgerufen werden können.<br />

Praktisch gesehen bedeutet diese Definition, dass Sie einen (fast) x-beliebigen Code<br />

nehmen und ihn in eine Prozedur packen können. Dadurch haben Sie die Möglichkeit,<br />

diesen Code aus einem Programm auszulagern und ihn darin mit einem einzigen<br />

Aufruf ausführen zu lassen. Dabei ist es egal, wie lang der Code in der Prozedur<br />

ist. Auch Teile aus einer Prozedur können in weitere Prozeduren ausgelagert werden.<br />

Sie werden dadurch sehr frei in der Gestaltung der Codestruktur. Sie sind gut beraten,<br />

wenn Sie dies zu Ihrem eigenen Vorteil so nutzen, dass eine möglichst klare<br />

Struktur entsteht, die die Logik der zugrunde liegenden Aufgabe gut abbildet.<br />

Wir nehmen an, wir würden es <strong>für</strong> sinnvoll halten, einen Programmteil zu haben,<br />

der bei seinem Aufruf die aktuelle Zeit ausgibt. Der aktuelle Agent ist der Agent, in<br />

dem das gerade ablaufende Script enthalten ist, mithin unser Hello World-Agent.<br />

Die zugehörige Prozedur könnte so aussehen:


Eine eigene Prozedur schreiben 49<br />

Sub ShowTime<br />

Messagebox "Wir schreiben den " & Date & ". Die Uhrzeit ist: " & Time<br />

End Sub<br />

Listing 3.2 Unsere selbst erstellte Prozedur<br />

Dieses kleine Programm arbeitet mit sogenannten Objekten. Wenn Sie damit noch<br />

keine Erfahrung haben, dann denken Sie im Moment noch nicht allzu viel darüber<br />

nach. Ich komme gleich im Abschnitt 3.8, Mit (<strong>Notes</strong>)-Objekten arbeiten, darauf<br />

zurück. Nehmen Sie den Code im Moment einfach so, wie er ist, und konzentrieren<br />

Sie sich eher darauf, wie die Prozedur selbst (sozusagen die Klammer um diesen<br />

Code) erstellt wird.<br />

3.5.1 Die Prozedur anlegen<br />

Die Prozedur wird durch direkte Eingabe in das Programmierfenster rechts vorgenommen.<br />

Dies können Sie an verschiedenen Orten tun.<br />

Zum einen können Sie den Cursor in der Sub Initialize am Ende ganz rechts von<br />

End Sub positionieren, mit [¢] einen Zeilenumbruch erzeugen und Sub ShowTime<br />

hinschreiben (Abbildung 3.18).<br />

Abbildung 3.18 Neue Prozedur durch direktes Hinschreiben erstellen<br />

Anschließend geben Sie mit [¢] noch einen Zeilenumbruch ein. Dabei wird die<br />

zugehörige Kennzeichnung des Endes (End Sub) vom <strong>LotusScript</strong>-Editor automatisch<br />

angelegt und die so erstellte leere Prozedur in ein eigenes Fenster verfrachtet,<br />

das Ihnen sofort angezeigt wird.<br />

Gleichzeitig wird die Prozedur als neuer Programmierabschnitt im Baum links vom<br />

Programmierfenster eingetragen. Wenn Sie die neue Prozedur in Zukunft öffnen<br />

und bearbeiten wollen, wählen Sie einfach ihren Namen im Abschnittsbaum aus<br />

(Abbildung 3.19).<br />

Abbildung 3.19 Darstellung der neuen Prozedur ShowTime im Designer<br />

Jetzt füllen wir die Prozedur ShowTime noch mit Inhalt, indem wir die noch fehlenden<br />

Zeilen <strong>LotusScript</strong> hineinschreiben. Dieser Teil wird auch allgemein als Rumpf<br />

der Prozedur bezeichnet (Listing 3.3: Prozedurrumpf).<br />

IBM SOFTWARE PRESS


50 Einführung in die <strong>LotusScript</strong>-Programmierung<br />

Messagebox "Wir schreiben den " & Date & ". Die Uhrzeit ist: " & Time<br />

Listing 3.3 Prozedurrumpf<br />

3.5.2 Die Prozedur aufrufen<br />

Nun können wir die Sache abschließen. Die Prozedur muss in der Sub Initialize<br />

beim Start des Agenten aufgerufen werden. Die alte Messagebox-Anweisung benötigen<br />

wir nun nicht mehr. Wir ersetzen sie also durch den Aufruf unserer eigenen<br />

Prozedur (Listing 3.4).<br />

Sub Initialize<br />

Call ShowTime<br />

End Sub<br />

Listing 3.4 Aufruf der selbst erstellten Prozedur<br />

Wie Sie sich schon denken können, ist Call die <strong>LotusScript</strong>-Anweisung, mit der Prozeduren<br />

aufgerufen werden können.<br />

Damit sind wir fertig. Der Agent kann gespeichert und geschlossen werden. Lassen<br />

Sie ihn einmal ablaufen, damit Sie die Früchte unserer gemeinsamen Arbeit genießen<br />

können, bevor wir den Prozedurrumpf aus Listing 3.3 besprechen.<br />

Abbildung 3.20 Die Meldung aus unserer selbst erstellten Prozedur<br />

3.5.3 Funktionen<br />

Prozeduren können Werte zurückgeben, die wie ein Ausdruck an Variablen zugewiesen<br />

oder im Rahmen von Berechnungen weiter ausgewertet werden können.<br />

Solche Prozeduren nennt man Funktionen. Sie werden mit dem Schlüsselwort<br />

Function statt mit Sub angelegt.<br />

Wir können die Prozedur ShowTime so umformulieren, dass sie den Text zurückgibt,<br />

anstatt ihn anzuzeigen. Wir nennen die entstehende Funktion ihrer Arbeitsweise<br />

gemäß GetTime:<br />

Function GetTime As String<br />

Dim strTimeText$<br />

strTimeText = "Wir schreiben den " & Date & _<br />

". Die Uhrzeit ist: " & Time<br />

GetTime = strTimeText<br />

End Function<br />

Listing 3.5 Die zur Funktion mutierte Prozedur aus Listing 3.4


Eine eigene Prozedur schreiben 51<br />

Hier fallen zwei Dinge auf. Erstens erhält der Funktionsname mit As String einen<br />

Zusatz wie bei einer Variablendeklaration. Damit wird der Datentyp der Rückgabe<br />

angegeben. Je nach Rückgabewert sind natürlich auch andere Deklarationen denkbar,<br />

wie Integer, Variant usw.<br />

Zweitens sehen Sie in der letzten Zeile der Funktion, dass der berechnete Wert aus<br />

strTimeText dem Namen der Funktion zugewiesen wird. Dadurch erfährt sie, welchen<br />

Wert sie ausgeben soll.<br />

Möchten wir den Wert der Funktion von unserem Agenten ausgeben lassen, so<br />

müssen wir den Aufruf ein wenig umschreiben. Denn wir müssen ja den Rückgabewert<br />

»abholen« und dann zur Ausgabe bringen:<br />

Sub Initialize<br />

Messagebox GetTime<br />

End Sub<br />

Listing 3.6 Der Aufruf von GetTime<br />

Wir können den Rückgabewert auch erst einer Variablen zuweisen und dann weitere<br />

Berechnungen vornehmen:<br />

Sub Initialize<br />

Dim strTime$<br />

Dim strPrefix$<br />

}<br />

Hinweis<br />

Es gehört zum guten Programmierstil, diese Zuweisung erst zum Schluss zu<br />

tätigen.<br />

Natürlich könnte man bei dieser kurzen Berechnung statt der Variablen str-<br />

TimeText gleich den Ausdruck zuweisen. <strong>Das</strong> wäre in diesem Fall in Ordnung,<br />

da die Zuweisung auch dann ja am Ende erfolgen würde. Die vorgenommene<br />

strikte Trennung ist aber am übersichtlichsten und soll Ihnen den Grundsatz<br />

vor Augen führen.<br />

Theoretisch kann man den Funktionsnamen sogar wie eine lokale Variable<br />

behandeln und ihren Inhalt zwischendurch abfragen, verarbeiten und erneut<br />

zuweisen. Davon ist aber auf jeden Fall abzuraten.<br />

strPrefix = {Der Agent sagt:<br />

strTime = GetTime<br />

Messagebox strPrefix & strTime<br />

End Sub<br />

Listing 3.7 Berechnung mit dem Rückgabewert von GetTime<br />

IBM SOFTWARE PRESS


52 Einführung in die <strong>LotusScript</strong>-Programmierung<br />

Wenn Sie die Erstellung des ersten Textteils (strPrefix) betrachten, wird Ihnen auffallen,<br />

dass die Zeichenkette diesmal nicht von Anführungszeichen, sondern von<br />

geschweiften Klammern umrandet ist und sich in die übernächste Zeile erstreckt.<br />

<strong>Das</strong> hat den Grund, dass wir einen doppelten Zeilenumbruch <strong>für</strong> die Ausgabe<br />

benötigen. Anstatt ihn mit den betriebssystemspezifischen Zeichen zu kodieren,<br />

schreiben wir ihn einfach hin. <strong>Das</strong> geht aber nur mit geschweiften Klammern (oder<br />

mit der noch verbleibenden Alternative, den senkrechten Strichen ||). Die Ausgabe<br />

sehen Sie in Abbildung 3.21.<br />

Abbildung 3.21 Anzeige des verarbeiteten Rückgabewertes der Funktion GetTime<br />

3.5.4 Parameter und Programmverzweigungen<br />

Allen Prozeduren können Parameter übergeben werden. Mit diesen steuern Sie das<br />

Verhalten der Prozedur.<br />

Parameter<br />

Parameter sind Variablen, die im Prozedurkopf angegeben werden (also in der<br />

Zeile, in der der Prozedurname steht). Parameter stehen innerhalb der Prozedur<br />

wie lokale Variablen zur Verfügung. Sie können abgefragt und bearbeitet<br />

werden.<br />

Wenn eine solche Prozedur aufgerufen wird, dann muss ihr <strong>für</strong> jeden Parameter ein<br />

Wert mitgegeben werden.<br />

Die Funktion GetTime gibt bislang nur deutsche Texte aus. Wenn wir in einem internationalen<br />

Umfeld arbeiten, dann benötigen wir wahrscheinlich auch eine englische<br />

Ausgabe. Um nicht <strong>für</strong> jede Sprachausgabe eine eigene Funktion schreiben<br />

zu müssen, parametrisieren wir sie und übergeben ein Kürzel, das sie anweist, eine<br />

deutsche oder eine englische Ausgabe zu generieren.<br />

Function GetTime(in_strLanguage As String) As String<br />

Dim strTimeText$<br />

If in_strLanguage = “de” Then<br />

strTimeText = "Wir schreiben den " & Date & _<br />

". Die Uhrzeit ist: " & Time<br />

Else<br />

strTimeText = "Today it is the " & Date & _<br />

". Current time: " & Time<br />

End If


Eine eigene Prozedur schreiben 53<br />

GetTime = strTimeText<br />

End Function<br />

Listing 3.8 Die parametrisierte Funktion zur Ausgabe von verschiedenen Sprachen<br />

Sie sehen, dass Parameter fast wie Variablen deklariert werden. Sie werden hinter<br />

dem Prozedurnamen als Liste aufgeführt und von runden Klammern umschlossen.<br />

Die Liste wird durch Kommata getrennt. Da wir nur einen Parameter benötigen, ist<br />

natürlich kein Komma zu sehen. Statt der Deklaration mit As String hätten wir<br />

auch hier das Suffix $ verwenden können.<br />

Im Funktionsrumpf wird der Parameter in_strLanguage von einer If...Then...<br />

Else...End If-Konstruktion ausgewertet. Dieses stellt eine bedingte Verzweigungsanweisung<br />

dar. Wenn die Bedingung hinter If den Wahrheitswert True ergibt, dann<br />

werden die unmittelbar folgenden Anweisungen bis zum Else abgearbeitet. Ergibt<br />

die Bedingung False, dann wird der Else-Zweig benutzt. Danach wird die Verarbeitung<br />

nach der End If-Klausel fortgesetzt.<br />

Der Parameter muss nun beim Aufruf durch die Sub Initialize-Prozedur mitgegeben<br />

werden. Da wir nicht wissen, welche Sprache der Aufrufer spricht, überlassen<br />

wir ihm die Auswahl. Dazu verwenden wir einen einfachen Eingabedialog, den<br />

<strong>LotusScript</strong> mit InputBox zur Verfügung stellt.<br />

Sub Initialize<br />

Dim strTime$<br />

Dim strPrefix$<br />

Dim strLanguage$<br />

strLanguage = Inputbox("Chose/Wählen Sie aus: English – en or German - de", "Sprachauswahl",<br />

"de")<br />

}<br />

Hinweis<br />

Dem Namen habe ich ein in_ vorangestellt. <strong>Das</strong> ist nicht zwingend, genauso<br />

wie das Präfix str nicht zwingend ist, aber einen guten Programmierstil ausmacht.<br />

<strong>Das</strong> Präfix in_ ist sehr praktisch, weil Sie dadurch besonders innerhalb<br />

von längeren Prozeduren den Überblick darüber behalten, welche Werte als<br />

Parameter »von außen geliefert wurden« und welche in lokalen Prozedurvariablen<br />

vorliegen.<br />

strPrefix = {Der Agent sagt:<br />

strTime = GetTime(strLanguage)<br />

Messagebox strPrefix & strTime<br />

End Sub<br />

Listing 3.9 Sprachabhängigkeit von GetTime durch Parametrisierung<br />

IBM SOFTWARE PRESS


54 Einführung in die <strong>LotusScript</strong>-Programmierung<br />

InputBox ist eine eingebaute Funktion der Sprache <strong>LotusScript</strong>. Auch sie wird durch<br />

Parameter gesteuert. Die erste Zeichenkette teilt dem Benutzer mit, was von ihm<br />

erwartet wird. Die zweite wird als Fenstertitel verwendet. Und die dritte (“de“) wird<br />

als Vorgabe oder Vorschlag schon in die Eingabezeile geschrieben.<br />

Wir haben die Bedingung in der Funktion GetTime so gewählt, dass bei der Übergabe<br />

von “de“ die deutsche Version ausgegeben wird und bei allen anderen die englische.<br />

<strong>Das</strong> macht unsere Funktion fehlerfest, »robust«, wie man in der Programmierung<br />

sagt. Es wird also auch dann ein sinnvolles Ergebnis geliefert, wenn der<br />

Benutzer irgendwelchen Unsinn übergibt oder eine Sprache, die die Funktion nicht<br />

kennt.<br />

Zur Programmierung von Verzweigungen gibt es noch andere Möglichkeiten, wie<br />

es auch verschiedene Schleifen zum wiederholten Durchlaufen eines Codes gibt.<br />

Mehr dazu finden Sie im Abschnitt 4.7, Ablaufsteuerung – Verzweigungen und Schleifen,<br />

ab Seite 167.<br />

3.6 Den Debugger verwenden<br />

Der Debugger ist eine visuelle Hilfe, um Programme Schritt-<strong>für</strong>-Schritt ablaufen zu<br />

lassen und den Fortgang der Berechnungen und die entstehenden Werte kontrollieren<br />

zu können. Er hilft, Fehler (engl. Bugs) zu finden und zu eliminieren.<br />

Debugger aktivieren<br />

Um den Debugger zu nutzen, muss er vor dem Aufruf eines Agenten oder einer<br />

Routine aktiviert werden, genauer gesagt: vor dem Laden des entsprechenden<br />

Moduls. Bei einem Agenten geschieht das wie gesagt vor dessen Start; bei einer<br />

Maske, einer Ansicht usw., passiert es, bevor dieses Element im Client geöffnet<br />

wird.<br />

Die Aktivierung erfolgt über WERKZEUGE/DEBUG LOTUSSCRIPT im Menü des Designers.<br />

Wenn links neben dem Menüpunkt ein Häkchen zu sehen ist, dann ist er aktiviert.<br />

Alternativ kann er über ein SmartIcon in der Universal-Leiste aktiviert werden.<br />

Debugger starten<br />

Sobald danach ein Modul geladen und eine seiner Routinen gestart wird, erscheint<br />

das Debugger-Fenster. In Abbildung 3.22 sehen Sie das Fenster <strong>für</strong> den zuletzt<br />

erstellten Agenten.


Den Debugger verwenden 55<br />

Abbildung 3.22 Debugger nach dem Start eines Agenten<br />

<strong>Das</strong> Programm wurde an der ersten ausgeführten Zeile angehalten (das geschieht<br />

immer). Diese wird durch einen kleinen gelben Pfeil markiert. Er zeigt an, welche<br />

Zeile als Nächstes ausgeführt werden wird.<br />

Haltepunkte<br />

Etwas weiter unten sehen Sie einen großen roten Punkt (im Buch ist er natürlich<br />

schwarz). Dieser markiert einen Haltepunkt (engl. Breakpoint).<br />

Sie haben jetzt die Wahl, das Programm einfach weiterlaufen zu lassen oder nur<br />

gezielt den nächsten Schritt auszuführen. Der nächste Schritt würde mit der oben<br />

befindlichen Schaltfläche SCHRITT AUSFÜHREN abgearbeitet. <strong>Das</strong> ist der Code, der<br />

sich in der aktuellen Zeile befindet, an deren Beginn der Pfeil postiert ist. Danach<br />

würde der Pfeil automatisch zur nächsten Zeile weiterrutschen. Manchmal ist es<br />

notwendig, jeden Schritt zu verfolgen; dann wählt man diesen Weg.<br />

Häufig gibt es aber nur eine gewisse Stelle, die näher untersucht werden soll. Dann<br />

setzt man dort einen Haltepunkt und klickt FORTFAHREN an. Auf diese Weise wird<br />

das Programm alle weiteren Schritte abarbeiten, bis es auf diesen oder einen anderen<br />

Haltepunkt stößt. Mit FORTFAHREN würden wir in unserem Beispiel also bei dem<br />

roten Punkt vor der Messagebox-Anweisung landen.<br />

Um einen Haltepunkt zu setzen, bewegt man den blauen Balken (Cursor) auf die<br />

entsprechende Zeile und klickt sie doppelt an oder drückt einmal [F9]. Möchte<br />

man einen Haltepunkt entfernen, so wiederholt man das Ganze zweimal. Wieder-<br />

IBM SOFTWARE PRESS


56 Einführung in die <strong>LotusScript</strong>-Programmierung<br />

holt man es nur einmal, dann wird der Haltepunkt nur deaktiviert. In Abbildung<br />

3.26 sehen Sie ein Beispiel da<strong>für</strong>. Dieser ist zwar vermerkt, aber nicht aktiv, sodass<br />

das Programm dort nicht halten wird. Dennoch können deaktivierte Haltepunkte<br />

über das Fenster BREAKPOINTS angesteuert werden.<br />

In Abbildung 3.22 sehen Sie im unteren Bereich vier Reiter <strong>für</strong> vier verschiedene<br />

Anzeigen. Der obere Reiter ist mit BREAKPOINTS beschriftet. Somit sehen Sie hier die<br />

gesetzten Haltepunkte. In unserem Beispiel ist es nur einer. Die Angaben sagen aus,<br />

dass er in der Routine Initialize in der 13. Zeile gesetzt ist. Wenn Sie mehrere Haltepunkte<br />

gesetzt haben und zu einem bestimmten »hinspringen« möchten, dann<br />

wählen Sie einfach die BREAKPOINTS-Seite und klicken auf den entsprechenden Haltepunkt.<br />

Dies bringt Sie an den gewünschten Ort.<br />

Mit der Anweisung Stop kann man Haltepunkte auch kodieren. Sie haben den Vorteil,<br />

dass sie mit dem Code verbunden sind und mit Bedingungen verknüpft werden<br />

können, beispielsweise so:<br />

...<br />

If strPrefix = “Blödsinn“ Then<br />

Stop<br />

End If<br />

...<br />

Stop-Anweisungen werden allerdings nicht als Haltepunkte auf der Seite BREAK-<br />

POINTS aufgeführt.<br />

Die Haltepunkte werden nur beachtet, wenn das Programm im Debug-Modus läuft.<br />

Außerdem sind die im Designer gesetzten Haltepunkte an die bookmark.nsf des Entwicklers<br />

gebunden (sie werden dort in einem Profildokument hinterlegt). Daher<br />

brauchen sie <strong>für</strong> ein Produktivprogramm nicht entfernt zu werden. Allerdings würde<br />

es keinen guten Eindruck machen, eine Reihe von Stop-Anweisungen zu hinterlassen,<br />

über die dann nachfolgende Entwickler »stolpern«. Sie sollten die Haltepunkte<br />

vor der Auslieferung Ihres Programms beseitigen.<br />

Inhalte von Variablen prüfen und verändern<br />

Die zweite Seite im unteren Bereich mit der Aufschrift VARIABLEN gibt uns einen<br />

Einblick in die Variablen und ihre Inhalte.<br />

In Abbildung 3.23 sehen Sie die drei Variablen der Initialize-Prozedur. Links<br />

erkennt man die Namen, ganz rechts die Datentypen und in der Mitte die Inhalte.<br />

Man kann den Inhalt von Variablen ändern, sodass nachfolgende Zugriffe mit<br />

angepassten Werten ausgeführt werden.


Den Debugger verwenden 57<br />

Abbildung 3.23 Inhalte der Variablen prüfen und verändern<br />

Als Beispiel führen wir eine Änderung an der Variablen strPrefix aus. Dazu wird die<br />

Variable mit der Maus angeklickt, woraufhin ihr Wert im unteren Feld NEUER WERT<br />

erscheint. Dort schreibt man den neuen Wert einfach hinein.<br />

Möchte man die Änderungen übernehmen, klickt man rechts das grüne Häkchen<br />

an. Sollen sie verworfen werden, klickt man auf das rote Kreuzchen oder geht einfach<br />

ohne Bestätigung des Häkchens weiter (Abbildung 3.24).<br />

Abbildung 3.24 Den Wert einer Variablen ändern<br />

Hier wird der Text “Der Agent sagt: “ umgeändert in “<strong>Das</strong> Programm sagt: “.<br />

Genauso geht man bei Zahlen, Datumswerten, Array-Elementen, Listen-Elementen<br />

und entsprechenden Eigenschaften von Objekten vor.<br />

Manche Eigenschaften von Objekten lassen sich nicht ändern. Dies sind dann<br />

Eigenschaften, die auch in Programmen nur gelesen werden können.<br />

IBM SOFTWARE PRESS


58 Einführung in die <strong>LotusScript</strong>-Programmierung<br />

Ausgabe überwachen<br />

Mit Print getätigte Ausgaben werden im Fenster AUSGABE angezeigt. Im “Hello World“-<br />

Agent wurde dazu noch eine Zeile eingefügt, die einen Text ausgibt (Abbildung 3.25).<br />

Abbildung 3.25 Print schreibt ins AUSGABE-Fenster.<br />

Aufrufe verfolgen und zum Navigieren verwenden<br />

Während weitere Unterroutinen aufgerufen werden, wird der Aufrufstapel verfolgt<br />

und im Fenster AUFRUFE angezeigt (Abbildung 3.26).<br />

Abbildung 3.26 Aufrufstapel verfolgen<br />

Hier sehen Sie einerseits, welche Aufrufe hintereinander getätigt wurden, um an<br />

die momentane Stelle zu gelangen.<br />

Andererseits können Sie durch Anklicken gezielt in eine der »Zwischenstationen«<br />

gelangen. Dabei kommen Sie nicht nur zu der entsprechenden Routine, sondern<br />

sehen im Fenster VARIABLEN auch die dazugehörenden Variablen mit deren aktuellen<br />

Werten.


Eingebaute Funktionen 59<br />

In unserem Beispiel bin ich in der zuletzt aufgerufenen Unterfunktion GetTime<br />

geblieben. Auf dem Stapel wird sie daher als oberste angezeigt (Abbildung 3.26).<br />

Übrigens sehen Sie auch einen deaktivierten Haltepunkt. Dieser ist zwar vermerkt,<br />

aber nicht aktiv, sodass das Programm dort nicht halten wird. Dennoch können<br />

deaktivierte Haltepunkte über das Fenster BREAKPOINTS angesteuert werden.<br />

Die übrigen Schaltflächen<br />

Die Schaltfläche SCHRITT ÜBERSPRINGEN wird verwendet, wenn man den Aufruf einer<br />

Funktion oder Prozedur überspringen möchte, ohne den darin befindlichen Code<br />

zu analysieren.<br />

Die Schaltfläche SCHRITT BEENDEN wird verwendet, wenn man den Aufruf einer<br />

Funktion oder Prozedur beenden möchte, ohne den darin befindlichen Code noch<br />

weiter zu analysieren. Hier ist man also schon hineingesprungen und möchte<br />

schnellstmöglich wieder heraus.<br />

Mit der Schaltfläche STOPPEN wird das Script an sich abgebrochen. In diesem Fall<br />

möchte man also nicht, dass das Programm weiter ausgeführt wird.<br />

Die Schaltfläche DEBUGGER SCHLIESSEN bricht das Programm ebenfalls ab. Sie deaktiviert<br />

aber gleichzeitig den Debugger, sodass folgende Programmaufrufe wieder<br />

normal ausgeführt werden.<br />

Navigation zwischen den Modulen und Routinen<br />

Unterhalb der Schaltflächen finden Sie noch die Comboboxen OBJEKT und EREIG-<br />

NIS. Mit diesen können Sie zwischen Modulen, deren Abschnitten und Ereignishandlern<br />

und anderen Routinen hin- und hernavigieren, ohne dass sie aufgerufen<br />

worden sein müssen. Darin unterscheidet sich diese Navigiermöglichkeit vom Aufrufstapel.<br />

3.7 Eingebaute Funktionen<br />

Nun haben wir schon viel über Prozeduren im Allgemeinen und über Funktionen<br />

im Speziellen gesprochen. Diese waren an einen Agenten, also ein <strong>Notes</strong>-Element<br />

gebunden. Gleichzeitig haben wir aber auch, ohne groß darüber nachzudenken,<br />

Funktionen verwendet, die in <strong>LotusScript</strong> fest eingebaut sind: MessageBox, Date, Time,<br />

InputBox.<br />

Die Sprache bietet viele solche Funktionen, die die unterschiedlichsten Dinge tun.<br />

In Kapitel 4, Sprachbefehle – nach Themen, (ab Seite 89) werden sie nach Themen<br />

getrennt im Einzelnen besprochen, sodass Sie je nach Anforderung schnell die<br />

richtigen Befehle finden werden.<br />

Anders als bei den selbst erstellten Prozeduren sind bei vielen <strong>LotusScript</strong>-Funktionen<br />

verschiedene Parameter optional. <strong>Das</strong> heißt, sie können, müssen aber nicht<br />

angegeben werden. Werden sie weggelassen, so setzt <strong>LotusScript</strong> selbst einen Wert<br />

ein, den sogenannten Vorgabewert.<br />

IBM SOFTWARE PRESS


60 Einführung in die <strong>LotusScript</strong>-Programmierung<br />

Folgt auf ausgelassene Parameter kein Parameter mehr, den Sie angeben möchten,<br />

so können Sie diese komplett inklusive Kommata weglassen. Folgt aber noch eine<br />

Wertangabe, so müssen die ausgelassenen Stellen dazwischen fast immer durch<br />

Kommata markiert werden. Nur so kann <strong>LotusScript</strong> erkennen, welchen Parameter<br />

Sie spezifizieren wollten und welche auszulassen sind.<br />

Beispielsweise kann MessageBox bis zu drei Parameter verarbeiten: Anzeigetext,<br />

Optionen und Titel. Wenn Sie nur einen Text anzeigen möchten, dann genügt folgender<br />

Aufruf:<br />

MessageBox “Dieser Text soll angezeigt werden“<br />

Möchten Sie auch einen Titel angeben, aber keine Optionen, dann sieht der Aufruf<br />

so aus:<br />

MessageBox “Dieser Text soll angezeigt werden“, , “Dies ist der Titel“<br />

3.7.1 Zwei Rückgabearten – Variant und String<br />

Viele eingebaute Funktionen existieren in zwei Varianten, deren Namen sich durch<br />

ein $-Suffix unterscheiden, zum Beispiel: Date und Date$. Der Unterschied ist, dass<br />

die Funktionen ohne Suffix das Ergebnis als Variant zurückgeben, während die mit<br />

Suffix einen String ausgeben.<br />

In der praktischen Arbeit werden Sie den Unterschied kaum merken. Daher findet<br />

man auch nur selten <strong>LotusScript</strong>-Code, in dem die Funktionen mit Suffix notiert<br />

werden.<br />

Dementsprechend habe ich auch in diesem Buch darauf verzichtet, jedes Mal beide<br />

Versionen zu erwähnen. Sollten Sie trotzdem unbedingt einen String als Rückgabewert<br />

benötigen und nicht CStr <strong>für</strong> eine Typumwandlung einsetzen wollen, so finden<br />

Sie in der Designer-Hilfe schnell die Information, ob es <strong>für</strong> eine bestimmte<br />

Funktion die Suffix-Version gibt.<br />

3.8 Mit (<strong>Notes</strong>-)Objekten arbeiten<br />

Bis jetzt haben wir noch nicht allzu viel Berührung mit <strong>Notes</strong>-Objekten gehabt.<br />

<strong>Das</strong> einzige war, dass wir einen Agenten als Container <strong>für</strong> unsere <strong>LotusScript</strong>-Programme<br />

genutzt haben. Ansonsten haben wir uns mit der Sprache <strong>LotusScript</strong> an<br />

sich beschäftigt. Da war noch keine Gelegenheit, sich mit der <strong>Notes</strong>/<strong>Domino</strong>-<br />

Umgebung zu beschäftigen.<br />

Im Prinzip sind dies zwei unterschiedliche Dinge. <strong>LotusScript</strong> ist eine Programmiersprache,<br />

die unabhängig von <strong>Notes</strong> existiert. Sie wird auch von anderen IBM<br />

Lotus-Produkten verwendet (zum Beispiel WordPro).<br />

<strong>Notes</strong>/<strong>Domino</strong> ist ein Produkt, in das auch <strong>LotusScript</strong> eingebaut wurde, um dessen<br />

Elemente mit dieser Sprache programmieren zu können. Diese Verbindung<br />

wird durch die sogenannten <strong>Notes</strong>-Klassen oder <strong>Notes</strong>-Objekte hergestellt. Praktisch<br />

gesehen, sind das Programmteile, die in <strong>LotusScript</strong> zusätzlich zur eigentlichen<br />

Sprache zur Verfügung stehen.


Mit (<strong>Notes</strong>-)Objekten arbeiten 61<br />

Bevor wir etwas mehr über Klassen und Objekte auch im allgemeinen Sinne sprechen,<br />

möchte ich Ihnen zunächst kurz die praktische Arbeit damit vorstellen. So<br />

bekommen Sie am schnellsten eine Vorstellung davon, was Klassen und Objekte<br />

<strong>für</strong> Sie als <strong>LotusScript</strong>-Programmierer bedeuten.<br />

3.8.1 Daten aus der aktuellen <strong>Notes</strong>-Sitzung abfragen (Teil 1)<br />

Eine zentrale Klasse <strong>für</strong> die Arbeit mit <strong>Notes</strong>/<strong>Domino</strong> ist <strong>Notes</strong>Session. Mit ihr erhalten<br />

wir Zugang zur aktuellen <strong>Notes</strong>-Sitzung. Man erfährt von ihr, wie der aktuelle<br />

Benutzer heißt (also die <strong>Notes</strong>-ID, mit der Ihr Programm läuft), in welcher Datenbank<br />

sich Ihr Script befindet, ob es auf dem Server oder dem Client läuft usw. Als<br />

kleine Demonstration soll das folgende Programm dienen, das uns verrät, wie der<br />

Agent heißt, in dem unser Script läuft:<br />

Sub Initialize<br />

Dim session As New <strong>Notes</strong>Session<br />

Dim agentThis As <strong>Notes</strong>Agent<br />

Dim strAgentName As String<br />

Set agentThis = session.CurrentAgent<br />

strAgentName = agentThis.Name<br />

Messagebox "Der Name dieses Agenten lautet: " & strAgentName<br />

End Sub<br />

Listing 3.10 Unsere erste Arbeit mit <strong>Notes</strong>-Objekten<br />

Die erste Anweisung lautet Dim session As New <strong>Notes</strong>Session und legt ein <strong>Notes</strong>Session-Objekt<br />

an. Mit Set agentThis = session.CurrentAgent bekommen wir Zugriff auf<br />

den Agenten, in dem das Script läuft, also auf »unseren« Agenten. Sein Name wird<br />

mit agentThis.Name ermittelt und anschließend über die Messagebox ausgegeben.<br />

Sie werden gesehen haben, dass drei neue Dinge aufgetaucht sind: die Anweisung<br />

New innerhalb der Variablendeklaration der ersten Zeile, dann das Schlüsselwort Set<br />

bei der ersten Zuweisung sowie der Punktoperator zwischen session und Current-<br />

Agent bzw. agentThis und Name. Zudem fallen noch die neuen »Datentypen« <strong>Notes</strong>Session<br />

und <strong>Notes</strong>Agent in den Deklarationszeilen auf.<br />

Bevor wir die Angelegenheit Stück <strong>für</strong> Stück durchgehen, benötigen wir noch etwas<br />

Theorie.<br />

3.8.2 Etwas Theorie – Objekte, Methoden und Eigenschaften<br />

Objekt<br />

Objekte sind benannte Programmteile, die sich ein wenig wie die Gegenstände<br />

in der realen Welt verhalten. Sie verfügen über eigene Daten (die Eigenschaften),<br />

die sie unabhängig von anderen Objekten verwalten. Sie haben<br />

Prozeduren (die Methoden), die ihre Aktionsmöglichkeiten ausmachen.<br />

IBM SOFTWARE PRESS


62 Einführung in die <strong>LotusScript</strong>-Programmierung<br />

Wenn Sie diese Definition mit der Definition der Prozedur auf Seite 48 vergleichen,<br />

dann werden Sie feststellen, dass sich die Definitionen ein wenig ähneln. Auch<br />

Objekte bieten also die Möglichkeit, eine bestimmte Menge Code auszulagern und<br />

diese bei Bedarf einfach über den Objektnamen aufzurufen. Dieser Code wird<br />

innerhalb der Klasse wie eine Prozedur formuliert und wird fast genauso mit Call<br />

aufgerufen. Solche Objekt-»Prozeduren« nennt man Methoden.<br />

Darüber hinaus haben Objekte im Allgemeinen sogenannte Eigenschaften. <strong>Das</strong> sind<br />

vereinfacht gesagt Variablen, die diverse <strong>für</strong> das Objekt relevante Daten speichern<br />

und ausgeben können. Eigenschaften werden häufig von Methoden bearbeitet,<br />

geändert und ausgegeben. Bei einem streng objektorientierten Design legt man<br />

sogar Wert darauf, dass auf Eigenschaften nur in Ausnahmefällen direkt zugegriffen<br />

weden kann.<br />

Man könnte auch sagen, dass Objekte eine Zusammenfassung von verschiedenen<br />

Prozeduren mit gemeinsamen Daten darstellen.<br />

Klasse<br />

Eine Klasse ist eine Art Schablone, mit der Objekte beschrieben und erstellt<br />

werden können.<br />

Beim Programmieren wird zunächst eine Klasse deklariert. Wenn man mit ihr<br />

arbeiten möchte, erzeugt man ein Objekt (mit New). Die in <strong>LotusScript</strong> eingebauten<br />

<strong>Notes</strong>-Klassen braucht man natürlich nicht mehr zu deklarieren.<br />

Objekte sind genaue Abbilder ihrer Klasse. Allerdings ist die Klasse nur die »Bauvorschrift«.<br />

Eine Klasse kann in einem Programm nur einmal existieren. Davon abgeleitete<br />

Objekte kann man so viele erstellen, wie man möchte bzw. wie der Arbeitsspeicher<br />

hergibt. Die Objekte sind unabhängig voneinander. Insbesondere ihre<br />

Eigenschaften sind eine »Privatangelegenheit«, in die sich kein anderes Objekt einmischen<br />

sollte. Diesen letzten Punkt kann man zwar durch schlechte Konzeption<br />

und Programmierung umgehen. Man sollte es aber nicht tun, da die Unabhängigkeit<br />

der Objekte voneinander ein wichtiges Merkmal des objektorientierten<br />

Designs (OOD) darstellt.<br />

Diese eher anschauliche Definition wird nicht jeder wissenschaftlichen Betrachtungsweise<br />

standhalten. Aber wir betreiben hier ja auch keine wissenschaftlichen<br />

Forschungen, sondern möchten mit den Objekten arbeiten.<br />

Verlassen wir also die Theorie wieder, und wir wenden uns unserem Beispiel zu.<br />

3.8.3 Daten aus der aktuellen <strong>Notes</strong>-Sitzung abfragen (Teil 2)<br />

Ohne jetzt weiter auf Details einzugehen, stellen wir fest, dass man Objekte offensichtlich<br />

mit der Syntax<br />

Dim ObjektVariable As New KlassenName


Mit (<strong>Notes</strong>-)Objekten arbeiten 63<br />

erzeugen kann. Sobald diese Anweisung abgearbeitet wurde, existiert das Objekt<br />

und kann im Programmcode verwendet werden.<br />

Der Klassenname ist die Bezeichnung <strong>für</strong> die Art des Objekts. In unserem Beispiel<br />

haben wir ein Objekt von der Art <strong>Notes</strong>Session erzeugt.<br />

Damit haben wir ein Objekt, das uns nützliche Auskünfte zur momentanen <strong>Notes</strong>-<br />

Sitzung geben kann. Beispielsweise »weiß« das Objekt, wer der gerade geöffnete<br />

Agent ist. Was es nicht weiß, ist, wie dieser Agent heißt. <strong>Das</strong> weiß er aber natürlich<br />

selbst.<br />

Deswegen haben wir das session-Objekt erst einmal nach dem geöffneten Agenten<br />

»befragt«. Dazu wird die Eigenschaft CurrentAgent mit dem »Punktoperator« angesprochen<br />

(englisch Dot), wobei das Objekt wie eine Variable mit dem Variablennamen<br />

notiert wird:<br />

session.CurrentAgent<br />

Hinweis<br />

Dazu muss man sagen, dass der Objektname in der Tat der Name einer Variablen<br />

ist. Denn beim Erzeugen mit Dim...As New... wurde zunächst eine Variable<br />

mit dem Objektnamen angelegt (hier session), dann wurde das Objekt<br />

erzeugt und im Programmspeicher abgelegt, und anschließend wurde die<br />

Adresse des Objekts in der Variablen abgelegt.<br />

Da wir <strong>für</strong> die Variable den Datentyp einer Klasse bestimmt haben (<strong>Notes</strong>Session),<br />

weiß <strong>LotusScript</strong>, dass es hier nicht einfach den Inhalt, nämlich die<br />

Objektadresse, ausgeben soll. Stattdessen sucht es automatisch das Objekt an<br />

der angegebenen Adresse und wertet dieses aus. <strong>Das</strong>s hier im Hintergrund<br />

Speicheradressen eine Rolle spielen, brauchen Sie als <strong>LotusScript</strong>-Entwickler<br />

im Prinzip nicht zu wissen. Es wird Ihnen aber verständlicher machen,<br />

warum eine Objektzuweisung ein vorangestelltes Set benötigt, während<br />

andere Variablenwerte ohne Set zugewiesen werden.<br />

In der Eigenschaft CurrentAgent befindet sich ein <strong>Notes</strong>Agent-Objekt des gerade laufenden<br />

Agenten, also »unseres« Agenten. <strong>Das</strong> Objekt wurde bereits intern von<br />

<strong>Notes</strong>Session erzeugt. Deshalb können wir es wie gezeigt einfach mit dem Punktoperator<br />

abfragen und benötigen keine zweite New-Anweisung.<br />

Wir weisen das Objekt einer Objektvariablen vom Typ <strong>Notes</strong>Agent zu. Wie schon<br />

gesagt, muss eine Objektzuweisung immer durch ein vorangestelltes Set kenntlich<br />

gemacht werden:<br />

Set agentThis = session.CurrentAgent<br />

Allerdings interessiert uns dieser Agent selbst nicht so sehr, sondern sein Name.<br />

Den erfährt man mit:<br />

strAgentName = agent.Name<br />

IBM SOFTWARE PRESS


64 Einführung in die <strong>LotusScript</strong>-Programmierung<br />

Diese Eigenschaft von <strong>Notes</strong>Agent gibt eine Zeichenkette aus, also einen String-Wert.<br />

Daher können wir sie einfach einer String-Variablen zuweisen (natürlich ohne Set,<br />

das ja nur zur Zuweisung von Objektreferenzen verwendet wird).<br />

Und den Rest kennen Sie ja bereits.<br />

In Verbindung mit <strong>Notes</strong>Session hatten wir also gesehen, wie Objekt-Eigenschaften<br />

gelesen werden. Im folgenden Abschnitt werden wir eine Objekt-Methode verwenden.<br />

3.8.4 Eine Methode des Arbeitsbereichs aufrufen<br />

Eine andere zentrale <strong>Notes</strong>-Klasse ist <strong>Notes</strong>UIWorkspace. <strong>Das</strong> »UI« im Namen deutet<br />

darauf hin, dass diese Klasse mit dem User Interface zu tun hat (also mit der Benutzerschnittstelle<br />

– das sind die Dinge, die man auf dem Bildschirm sieht).<br />

Mit dieser Klasse erhält man Zugriff auf die im UI geöffneten Elemente, z. B. ein<br />

Dokument, eine geöffnete Ansicht usw. Man kann mit ihr Dialogboxen anzeigen<br />

und Masken zur Erstellung von neuen Dokumenten öffnen. Vorhandene Dokumente<br />

können zur Bearbeitung angezeigt werden usw.<br />

Hinweis<br />

Da wir gerade über Dialogboxen sprachen: Sie werden bemerkt haben, dass es<br />

offensichtlich »an zwei Stellen« Dialogboxen gibt, denn wir hatten ja schon<br />

die <strong>LotusScript</strong>-Funktionen MessageBox und InputBox als solche kennengelernt.<br />

Hier zeigt sich wieder die Zweiteilung: einerseits die Sprache <strong>LotusScript</strong> –<br />

andererseits die von <strong>Notes</strong>/<strong>Domino</strong> zusätzlich zur Verfügung gestellten Klassen,<br />

deren Methoden sich hier und da ein wenig mit <strong>LotusScript</strong>-Funktionen<br />

überschneiden.<br />

<strong>Das</strong> ist insbesondere bei den Dialogboxen, der Arbeit mit Dateien und bei<br />

OLE-Objekten der Fall. Bei der Arbeit mit den Klassen werden Sie feststellen,<br />

dass deren Angebote meistens über die Möglichkeiten von <strong>LotusScript</strong> hinausreichen<br />

bzw. anderen Anforderungen genügen. Es hat also beides seine<br />

Berechtigung.<br />

Um zu zeigen, wie Objekt-Methoden verwendet werden, erstellen wir als Beispiel<br />

mit <strong>Notes</strong>UIWorkspace.ComposeDocument ein neues Dokument. Mit dieser Methode können<br />

Sie in irgendeiner zugänglichen Datenbank (auf der Sie Schreibrechte haben)<br />

ein Dokument mit einer der da<strong>für</strong> vorgesehenen Masken erstellen.<br />

Da ich nicht weiß, welche Datenbanken in Ihrer Umgebung zu finden sind, nehmen<br />

wir einfach Ihre Mail-Datei, die ziemlich sicher existieren wird, und erstellen<br />

darin ein neues Memo. Nun weiß ich auch nicht, wie Ihre Mail-Datei heißt. <strong>Das</strong><br />

können wir aber mit <strong>Notes</strong>Database in Erfahrung bringen. Der Code wird wieder in<br />

einen Agenten wie dem “Hello World“-Agenten geschrieben:


Mit (<strong>Notes</strong>-)Objekten arbeiten 65<br />

Sub Initialize<br />

Dim dbMail As New <strong>Notes</strong>Database("", "")<br />

Dim ws As New <strong>Notes</strong>UIWorkspace<br />

'Mail-Datei öffnen, um Server und Pfad ermitteln zu können<br />

Call dbMail.OpenMail()<br />

'Memo-Maske aus Mail-Datei <strong>für</strong> eine neue Mail öffnen<br />

Call ws.ComposeDocument(dbMail.Server, dbMail.FilePath, "Memo")<br />

End Sub<br />

Listing 3.11 Programm zur Erstellung einer neuen Mail<br />

Sie sehen, das Programm ist sehr kurz, und es wird praktisch nur mit <strong>Notes</strong>-Objekten<br />

gearbeitet.<br />

Als Erstes benötigen wir wieder ein <strong>Notes</strong>Database-Objekt. Dies steht <strong>für</strong> Datenbanken<br />

im Hintergrund, also <strong>für</strong> den nicht sichtbaren Teil. Wir möchten gern erfahren,<br />

wo sich die Mail-Datei des Benutzers befindet (also Ihre Mail-Datei, wenn Sie<br />

das Script laufen lassen). Dazu bietet uns die Klasse <strong>Notes</strong>Database die Methode Open-<br />

Mail an. Der Aufruf öffnet die Datenbank nur im Hintergrund, es wird (noch) kein<br />

Fenster sichtbar. Wir nehmen als sicher an, dass Sie eine Mail-Datei besitzen, dass<br />

alles richtig konfiguriert ist und dass Sie Zugriff auf die Datenbank haben. Dann<br />

werden in dem dbMail-Objekt nach dem Aufruf von OpenMail der Server und der<br />

Dateipfad (FilePath) vermerkt sein. Diese Angaben übergeben wir als die ersten beiden<br />

notwendigen Parameter an ComposeDocument. Diese Methode soll auch noch wissen,<br />

welche Maske sie <strong>für</strong> das neue Dokument verwenden soll, und wir geben<br />

»Memo« an. Nach ihrem Aufruf wird ein Fenster mit der Mail-Maske (»Memo«)<br />

sichtbar.<br />

Jetzt können Sie die neue Mail am Bildschirm wie jede andere füllen und absenden.<br />

In diesem Script wurde zweimal eine Objekt-Methode aufgerufen: mit <strong>Notes</strong>Database.OpenMail<br />

eine parameterlose und mit <strong>Notes</strong>UIWorkspace.ComposeDocument eine<br />

andere mit Parametern.<br />

Der Aufruf ist sehr ähnlich wie bei den Prozeduren, die Sie früher kennengelernt<br />

haben, und erfolgte mit Call.<br />

Hinweis<br />

Call kann bei allen Arten von Prozeduraufrufen auch weggelassen werden.<br />

Genauso können die runden Klammern weggelassen werden, wenn keine<br />

Parameter übergeben werden. Aus Call dbMail.OpenMail() würde dann:<br />

dbMail.OpenMail<br />

<strong>Das</strong> sieht aber fast wie die Abfrage einer Eigenschaft aus, und deshalb verwende<br />

ich bei solchen Aufrufen immer Call und setze dann in der Regel auch<br />

die Klammern. Andere entscheiden sich <strong>für</strong> die kürzere Variante. <strong>Das</strong> ist eine<br />

reine Geschmackssache.<br />

IBM SOFTWARE PRESS


66 Einführung in die <strong>LotusScript</strong>-Programmierung<br />

Der Unterschied ist nur, dass wie bei den Eigenschaften der Name der Objektvariablen<br />

davor gesetzt und mit dem Punktoperator verbunden werden muss.<br />

Wenn eine Methode einen Rückgabewert hat, kann die Zuweisung zu einer Variablen<br />

analog zu der Vorgehensweise bei Funktionen erfolgen. Häufig geben die<br />

Methoden Objekte zurück, die dann mit Set zugewiesen werden müssen. Unsere<br />

ComposeDocument-Methode gibt ein <strong>Notes</strong>UIDocument-Objekt zurück, das man <strong>für</strong> weitere<br />

Bearbeitungen nutzen kann. Die Zuweisung könnte so erfolgen:<br />

...<br />

Dim uidoc As <strong>Notes</strong>UIDocument<br />

...<br />

Set uidoc = ws.ComposeDocument(dbMail.Server, dbMail.FilePath, "Memo")<br />

...<br />

Listing 3.12 Hier wird das erstellte Dokument zur weiteren Bearbeitung als <strong>Notes</strong>UIDocument-Objekt<br />

übernommen.<br />

3.8.5 Eigenschaften ändern<br />

Eigenschaften kann man nicht nur abfragen, sie können in manchen Fällen auch<br />

geändert werden.<br />

So können wir zum Beispiel das in Listing 3.12 ergriffene <strong>Notes</strong>UIDocument verwenden,<br />

um sicherzustellen, dass das horizontale Lineal angezeigt wird:<br />

uidoc.Ruler = True<br />

Nicht änderbare Eigenschaften<br />

Es gibt natürlich auch viele Eigenschaften, bei denen eine Änderung nicht sinnvoll<br />

wäre.<br />

Zum Beispiel gibt <strong>Notes</strong>UIDocument.IsNewDoc an, ob das Dokument noch neu ist oder<br />

schon einmal gespeichert wurde. Wenn unser Programm die Eigenschaft später<br />

nach dem ersten Speichern einfach von True auf False setzen könnte, dann würde<br />

sie anschließend offensichtlichen Unsinn enthalten.<br />

Daher sind viele Eigenschaften gegen Änderungen gesperrt. Die Klassenreferenz<br />

gibt Auskunft darüber, welche Eigenschaften änderbar sind und welche nicht.<br />

3.9 Weitere Startpunkte <strong>für</strong> <strong>LotusScript</strong>-Programme<br />

Bis jetzt haben wir nur Agenten programmiert. Um Ihnen eine Richtung aufzuzeigen,<br />

wie Sie Scripts einsetzen können, folgen jetzt ein paar exemplarische Hinweise.<br />

Weitere Möglichkeiten finden Sie bei den einschlägigen Themen weiter hinten<br />

im Buch und in den Beschreibungen der Events (Ereignisse) der UI-Klassen.<br />

Wenn ich jetzt ein paar Eventhandler explizit erwähne, dann sind diese nur ein<br />

kleiner Auszug aus der Liste der programmierbaren Events.


Weitere Startpunkte <strong>für</strong> <strong>LotusScript</strong>-Programme 67<br />

3.9.1 Aktionsschaltflächen<br />

Wenn Sie auf einer Maske, einer Seite oder in einer Aktionsleiste eine Schaltfläche<br />

einbauen, dann kann diese anschließend ähnlich wie ein Agent programmiert werden.<br />

Wenn sich der Fokus auf der Schaltfläche befindet, zeigt sich das Programmierfenster<br />

unten ähnlich wie bei dem Agenten. Auch müssen wir zunächst die<br />

Sprache <strong>LotusScript</strong> auswählen (vorher wird eine Formel angezeigt) und sehen<br />

dann die einzelnen Eventhandler. Bei Schaltflächen gibt es außer den schon<br />

bekannten Sub Initialize und Sub Terminate noch Sub Click und Sub ObjectExecute.<br />

Soll der Button das Programm auf einen Klick hin ausführen, dann ist Sub Click die<br />

richtige Wahl. (Sub Initialize würde beim Laden der Maske und dem damit verbunden<br />

Initialisieren der Schaltfläche aufgerufen, was selten das ist, was wir benötigen).<br />

3.9.2 Masken, Teilmasken und Seiten<br />

Masken weisen eine Fülle von Eventhandlern auf. Seiten haben einige Eventhandler<br />

weniger, weil Seiten nicht gespeichert werden können; sie sind nicht mit einem<br />

Dokument verbunden. Auch Teilmasken verfügen über ähnliche Eventhandler wie<br />

Masken.<br />

Wenn Sie <strong>für</strong> bestimmte Fälle verhindern möchten, dass ein Dokument gespeichert<br />

wird, können Sie die Sub QuerySave-Routine bearbeiten. Sie können darin eine<br />

Prüfung vornehmen und <strong>für</strong> den Fall, dass sie negativ ausfällt, den Parameter Continue<br />

= False setzen. Dann wird die Maske die Speicherung nicht ausführen.<br />

Sollen in der Maske direkt nach dem Öffnen gewisse Aktionen durchgeführt werden<br />

(noch bevor der Benutzer eingreifen kann), so können Sie Sub PostOpen verwenden.<br />

Durch eine Maske können Sie auf die dahinterliegenden Hintergrunddokumente<br />

zugreifen (<strong>Notes</strong>UIDocument.Document) und sie ändern, oder Sie geben bestimmte Texte<br />

mit <strong>Notes</strong>UIDocument direkt in der Maske ein.<br />

Im folgenden Beispiel greifen wir im PostOpen-Eventhandler auf das Hintergrunddokument<br />

zu und geben dessen Universal-ID aus:<br />

Sub Postopen(Source As <strong>Notes</strong>uidocument)<br />

Dim docThis As <strong>Notes</strong>Document<br />

Set docThis = Source.Document<br />

Print docThis.UniversalID<br />

End Sub<br />

Listing 3.13 Zugriff auf das Hintergrunddokument<br />

Wird ein Agent bei geöffneter Maske aufgerufen, so startet man mit einem <strong>Notes</strong>-<br />

UIWorkspace-Objekt, mit dem man als CurrentDocument auf das Vordergrunddokument<br />

Zugriff erlangt und anschließend auf das Hintergrunddokument:<br />

IBM SOFTWARE PRESS


68 Einführung in die <strong>LotusScript</strong>-Programmierung<br />

Sub Initialize<br />

Dim ws As <strong>Notes</strong>UIWorkspace<br />

Dim docThis As <strong>Notes</strong>Document<br />

Set docThis = ws.CurrentDocument.Document<br />

Print docThis.UniversalID<br />

End Sub<br />

Listing 3.14 Zugriff auf das Hintergrunddokument der geöffneten Maske über das <strong>Notes</strong>UIWorkspace-Objekt<br />

3.9.3 Ansichten und Ordner<br />

Ansichten können Sie in zweierlei Hinsicht programmieren. Zum einen können Sie<br />

auch hier Eventhandler mit Programmen füllen, die ausgeführt werden, wenn eine<br />

Ansicht geöffnet oder geschlossen wird, wenn Dokumente ausgewählt und geöffnet<br />

werden usw.<br />

Zum anderen kann auch die Gestaltung von Ansichten mit <strong>LotusScript</strong> verändert<br />

werden. Dazu halten die <strong>Notes</strong>View-Klassen eine Reihe von Möglichkeiten bereit.<br />

Außerdem können Ansichten zum Durchlaufen ihrer Inhalte und zum Suchen<br />

darin verwendet werden.<br />

Die Startpunkte <strong>für</strong> die letztgenannten Aktionen können wiederum in irgendeinem<br />

passenden Eventhandler liegen (in einer Schaltfläche: Sub Click, in einem<br />

Agenten: Sub Initialize usw.).<br />

3.9.4 Datenbanken<br />

Auf das Öffnen und Schließen einer Datenbank kann mit Eventhandlern im sogenannten<br />

DATENBANK-SCRIPT in den DATENBANKRESSOURCEN aus dem Abschnitt ANDERE<br />

reagiert werden. Was man vielleicht weniger vermuten würde, ist, dass hier auch<br />

Eventhandler <strong>für</strong> die Behandlung von Drag&Drop-Operationen verborgen sind.<br />

3.9.5 Gliederungen<br />

Gliederungen können mit den Klassen <strong>Notes</strong>Outline und <strong>Notes</strong>OutlineEntry bearbeitet<br />

werden. Sie können Einträge hinzufügen, entfernen und ihre Ziele verändern.<br />

Die Startpunkte <strong>für</strong> diese Aktionen können in irgendeinem passenden Eventhandler<br />

liegen (in einer Schaltfläche: Sub Click, in einem Agenten: Sub Initialize usw.).<br />

3.10 Bibliotheken erstellen und einbinden<br />

Um große Mengen von <strong>LotusScript</strong>-Code sinnvoll zu strukturieren, bietet es sich<br />

an, sie in Bibliotheken auszulagern.<br />

Sie finden die vorhandenen Bibliotheken unter GEMEINSAMER CODE/SCRIPTBIB-<br />

LIOTHEKEN. Dort können neue Bibliotheken mit der Aktion NEUE LOTUSSCRIPT BIB-


Bibliotheken erstellen und einbinden 69<br />

LIOTHEK angelegt werden. Geben Sie ihnen sprechende Namen, die die darin abgelegten<br />

Programmteile charakterisieren. Dann ist es später leichter, die darin<br />

befindlichen Codestücke zu finden.<br />

Wenn eine Bibliothek neu angelegt wird, präsentiert sie sich zunächst wie ein noch<br />

leerer Agent (Abbildung 3.27).<br />

Abbildung 3.27 Neu angelegte <strong>LotusScript</strong>-Bibliothek<br />

Zunächst trägt sie den Namen “(unbenannt)“, was man in den Eigenschaften ändert.<br />

Spätestens beim Abspeichern wird man dazu aufgefordert.<br />

Nun wird der auszulagernde Code hier genauso abgelegt wie in anderen Modulen<br />

auch. Nur werden Sie in der Regel die beiden Routinen Sub Initialize und Sub Terminate<br />

unberührt lassen. Die erste kommt nur in Betracht, wenn Sie möchten, dass<br />

beim Laden der Bibliothek gewisse Werte voreingestellt werden, beispielsweise globale<br />

Variablen (die Sie als guter Programmierer hoffentlich nur in Ausnahmefällen<br />

verwenden werden). Sub Terminate kann zum Aufräumen beim Entladen der Bibliothek<br />

verwendet werden können.<br />

Bibliotheken werden mit der Anweisung<br />

Use strLibraryName$<br />

eingebunden. Diese muss im (Options)-Abschnitt eines anderen Moduls, also eines<br />

Agenten, einer Maske oder einer Ansicht usw. aufgeführt werden. Wenn dieses<br />

andere Modul geladen wird, dann wird die Bibliothek automatisch mitgeladen.<br />

Wird das andere Modul entladen, dann wird auch die Bibliothek entladen.<br />

Es können mehrere Use-Anweisungen untereinander geschrieben werden. Außerdem<br />

können Ketten gebildet werden, indem eine Bibliothek eine weitere angibt,<br />

die von ihr selbst geladen wird, usw.<br />

Hinweis<br />

Die Auflösung der verketteten Inhalte ist in der Vergangenheit nicht immer<br />

zuverlässig gewesen. Dies hat sich insbesondere in mysteriösen Fehlern von<br />

Hintergrundagenten bemerkbar gemacht. Deshalb verzichte ich auch heute<br />

noch auf eine Verkettung bzw. führe die verketteten Bibliotheken im ausführenden<br />

Modul (zum Beispiel einem Agenten) lückenlos auf. So kann man<br />

sicher sein, dass der <strong>LotusScript</strong>-Interpreter alle findet.<br />

IBM SOFTWARE PRESS


70 Einführung in die <strong>LotusScript</strong>-Programmierung<br />

Anschließend kann der (öffentliche) Code aus der Bibliothek wie jeder andere verwendet<br />

werden. <strong>Das</strong> heißt, Prozeduren, Funktionen, Klassendefinitionen und<br />

benutzerdefinierte Datentypen können verwendet werden, als wären sie in demselben<br />

Modul geschrieben worden. Es muss nur darauf geachtet werden, dass ein zu<br />

verwendendes Element nicht als Private deklariert wurde.<br />

3.11 Eigene zusammengesetzte Datentypen erstellen<br />

Die Anweisung Type bietet die Möglichkeit, eigene Datentypen zu erstellen. Dies<br />

beschränkt sich allerdings auf die Zusammensetzung anderer vorhandener Datentypen.<br />

Sie können nicht wie in C++ das Verhalten der erstellten Datentypen steuern.<br />

<strong>Das</strong> ist in der praktischen Arbeit mit <strong>LotusScript</strong> auch selten erforderlich. Und<br />

wenn, dann kann man sich mit der Erstellung eigener Klassen behelfen.<br />

Um einen zusammengesetzten Typ zu erstellen, schreibt man die Anweisung Type<br />

in Verbindung mit dem gewünschten Namen des Typs hin. Anschließend notiert<br />

man eine Liste von Elementen, die in dem Typ enthalten sollen. Diese werden wie<br />

Variablen ohne Dim oder Ähnliches notiert. Zum Schluss wird die Deklaration mit<br />

End Type abgeschlossen. Ein Beispiel:<br />

Type Person<br />

Vorname As String<br />

Nachname As String<br />

Geburtsjahr As Integer<br />

Ort As String<br />

End Type<br />

Diese Deklaration muss in den Abschnitt (Declarations) geschrieben werden.<br />

Eine Variable dieses Typs kann man dann im laufenden Code deklarieren wie jede<br />

andere auch. Allerdings muss man bei Zuweisungen und Auswertungen angeben,<br />

welche Elemente man ansprechen möchte. Dazu wird wie beim Ansprechen von<br />

Objekt-Eigenschaften und -Methoden der Punktoperator verwendet.<br />

Als Beispiel sehen Sie eine kleine Prozedur, die die Angaben als Parameter übernimmt<br />

und einer Variablen vom Typ Person zuweist. Anschließend werden die<br />

Daten ausgegeben:<br />

Sub FillPersonRecord(in_strFirstName$, in_strLastName$, in_strCity$,<br />

in_iYearOfBirth%)<br />

Dim tPerson As Person<br />

tPerson.Geburtsjahr = in_iYearOfBirth%<br />

tPerson.Nachname = in_strLastName<br />

tPerson.Vorname = in_strFirstName<br />

tPerson.Ort = in_strCity<br />

Print "Datensatz erzeugt <strong>für</strong> " & tPerson.Vorname & " " tPerson.Nachname<br />

End Sub<br />

Listing 3.15 Variable vom Datentyp Person erstellen und mit Inhalten füllen


Eigene Klassen und Objekte erstellen 71<br />

Führt man den folgenden Aufruf durch, dann kann man das Füllen der Typ-Elemente<br />

beobachten und erhält zum Schluss in der Statuszeile die Information<br />

“Datensatz erzeugt <strong>für</strong> Code Coder“:<br />

Call FillPersonRecord("Code", "Coder", "Kodistan", "1972")<br />

Hier sieht man auch, dass es nicht darauf ankommt, in welcher Reihenfolge die<br />

einzelnen Elemente des selbst erstellten Datentyps angesprochen werden.<br />

Solche Datenstrukturen lassen sich gut verwenden, um zusammenhängende<br />

Daten, auf denen umfangreiche Aktionen ausgeführt werden, sinnvoll zusammenzufassen.<br />

<strong>Das</strong> kann zum Beispiel in der Schnittstellenprogrammierung sehr zur<br />

Erstellung eines gut strukturierten Programms beitragen.<br />

Andere Einsatzgebiete sind die Bearbeitung von Dateien im wahlfreien Zugriffsmodus<br />

oder der Austausch von Daten mit der <strong>Notes</strong> C-API, bei dem oft zusammengesetzte<br />

Datentypen gefragt sind.<br />

3.12 Eigene Klassen und Objekte erstellen<br />

Auch eigene Klassen lassen sich erstellen, deren Objekte wie die Objekte der eingebauten<br />

<strong>Notes</strong>-Klassen verwendet werden können.<br />

Es ist sehr zu empfehlen, umfangreicheren Code nicht nur in Funktionen, sondern<br />

auch in einer Klassenstruktur zu organisieren. Mit ein bisschen Übung ist das ist<br />

nicht viel aufwendiger als das Schreiben von einfachen Prozeduren. Aber es erhöht<br />

die Lesbarkeit und Wartbarkeit Ihrer Programme enorm. Zusatz- und Änderungswünsche,<br />

die im schnellen Geschäftsleben häufig an einen Entwickler herangetragen<br />

werden, lassen sich in einer sinnvollen Klassen- und Objektstruktur häufig viel<br />

leichter und schneller umsetzen.<br />

Um denjenigen, die sich noch nicht so viel mit objektorientierter Programmierung<br />

beschäftigt haben, das Thema etwas verständlicher und schmackhafter zu machen,<br />

möchte ich Ihnen ein kurzes hypothetisches Beispiel vor Augen führen, das die<br />

Arbeitsweise mit Objekten gut veranschaulicht.<br />

Gleichzeitig werde ich Schritt <strong>für</strong> Schritt zeigen, wie in <strong>LotusScript</strong> Klassen<br />

geschrieben und Objekte davon erstellt und verwendet werden.<br />

Wir stellen uns vor, wir würden die Software <strong>für</strong> ein Auto entwickeln, und zwar <strong>für</strong><br />

ein sehr fortschrittliches. In diesem Auto wird fast alles von Software geregelt und<br />

gesteuert, es gibt kaum noch eine direkte Verbindung zwischen den Bedienungselementen<br />

des Cockpits und den ausführenden Teilen wie Lenkung, Motor, Bremsen<br />

usw. – eine Vorstellung, die sich heute bereits nach und nach realisiert.<br />

Wir schreiben also ein Programm, das wir schon mal »Auto« nennen, auch wenn<br />

wir noch nicht so genau wissen, wo wir das Wörtchen Auto dranschreiben sollen.<br />

Interessanter sind jetzt aber erst einmal die Teile. Wir nehmen uns die Lenkung vor.<br />

Wir stellen uns vor, irgendwo im Lenkgestänge befindet sich ein Motor, der in der<br />

Lage ist, per Software Befehle entgegenzunehmen. Die nötigen Befehle lauten:<br />

NachRechtsAusschlagen, NachLinksAuschlagen, GeradeZiehen.<br />

IBM SOFTWARE PRESS


72 Einführung in die <strong>LotusScript</strong>-Programmierung<br />

Jetzt könnten wir <strong>für</strong> jeden dieser Befehle eine Prozedur schreiben, die die damit<br />

verbundenen Aktionen durchführt:<br />

Sub NachRechtsAusschlagen<br />

End Sub<br />

Sub NachLinksAusschlagen<br />

End Sub<br />

Sub GeradeZiehen<br />

End Sub<br />

Wenn der Autofahrer nach rechts abbiegen möchte, ruft er Call NachRechtsAusschlagen<br />

auf, will er nach links, so führt er Call NachLinksAusschlagen aus.<br />

Wir stellen uns jetzt ein noch moderneres Auto vor, ein Auto, in dem die einzelnen<br />

Vorderräder nicht mehr mechanisch miteinander verbunden sind. Jedes Rad wird<br />

getrennt durch Software angesteuert. Auf diese Weise können die Räder schwierigen<br />

Bedingungen viel flexibler angepasst werden, als das mit einer starren Lenkachse<br />

der Fall ist. Jetzt hat jedes Rad einen eigenen Stellmotor. Jedes Rad empfängt<br />

die Befehle Call NachRechtsAusschlagen, Call NachLinksAusschlagen und Call GeradeZiehen.<br />

Natürlich möchte der Fahrer nicht jedem Rad diese Befehle einzeln mitteilen. Es<br />

gibt also ein zentrales Programm, das die Verwaltung übernimmt. Außerdem gibt<br />

es die Aufrufe Call NachRechtsAusschlagen, Call NachLinksAusschlagen und Call Gerade-<br />

Ziehen jetzt sowohl <strong>für</strong> die zentrale Lenksoftware als auch <strong>für</strong> die Rädersoftware.<br />

Und nun beginnt sich abzuzeichnen, dass unsere Lenkung softwaretechnisch<br />

schwierig werden wird. Wir müssen die Prozeduren von Lenksoftware und Rädersoftware<br />

auseinander halten. Also schreiben wir:<br />

Sub LenkungNachRechtsAusschlagen<br />

End Sub<br />

Sub LenkungNachLinksAusschlagen<br />

End Sub<br />

Sub LenkungGeradeZiehen<br />

End Sub<br />

Sub RechtesRadNachRechtsAusschlagen<br />

End Sub<br />

Sub RechtesRadNachLinksAusschlagen


Eigene Klassen und Objekte erstellen 73<br />

End Sub<br />

Sub RechtesRadGeradeZiehen<br />

End Sub<br />

Sub LinkesRadNachRechtsAusschlagen<br />

End Sub<br />

Sub LinkesRadNachLinksAusschlagen<br />

End Sub<br />

Sub LinkesRadGeradeZiehen<br />

End Sub<br />

Alle diese Prozeduren müssen wir ins Hauptprogramm einbinden und dort ansprechen.<br />

(Man könnte natürlich eine Prozedur schreiben, die die Lenkung repräsentiert<br />

und damit die Steuerung der einzelnen Räder vom Hauptprogramm auslagert.<br />

Allerdings würde dadurch das Problem nicht gelöst, dass viele Prozeduren vorhanden<br />

sind, die auch von anderen Programmteilen missbraucht werden könnten.)<br />

So wäre es, wenn wir den sogenannten funktionalen Ansatz wählen würden. <strong>Das</strong><br />

machen wir aber nicht; wir entscheiden uns natürlich <strong>für</strong> die Erstellung von Objekten,<br />

da<strong>für</strong> ist das Kapitel ja gedacht. Wenn wir die erst einmal haben (wir nennen<br />

sie hier schon einmal Lenkung und Rad), dann gestalten sich die Aufrufe sehr einfach:<br />

Call Lenkung.NachRechtsAusschlagen<br />

Call Lenkung.NachLinksAusschlagen<br />

Call RechtesRad.NachRechtsAusschlagen<br />

Call LinkesRad.NachRechtsAusschlagen<br />

Jetzt werden alle beteiligten Objekte ihre eigene Prozedur NachRechtsAusschlagen<br />

haben. Es gibt keine Namenskonflikte mehr, weil die Prozeduren den Objekten als<br />

Methoden fest zugeordnet sind. Die feste Zuordnung bringt es mit sich, dass die<br />

Prozeduren nicht mehr so leicht im falschen Zusammenhang angewendet werden<br />

können. Es müssen keine Namensungetüme zur Unterscheidung der vielen »herumliegenden«<br />

Prozeduren mehr geschaffen werden.<br />

Zunächst schreiben wir eine Klasse, die dann die Vorlage <strong>für</strong> die Räder bildet.<br />

Klassen werden in <strong>LotusScript</strong> mit der Anweisung Class erstellt (im Modul-<br />

Abschnitt (Declarations)):<br />

Class Rad<br />

Sub NachRechtsAusschlagen<br />

End Sub<br />

IBM SOFTWARE PRESS


74 Einführung in die <strong>LotusScript</strong>-Programmierung<br />

Sub NachLinksAusschlagen<br />

End Sub<br />

Sub GeradeZiehen<br />

End Sub<br />

End Class<br />

Mit der Dim-Anweisung können wir dann <strong>für</strong> jedes Rad ein Objekt dieser Klasse<br />

deklarieren:<br />

Dim radVorneRechts As Rad<br />

Dim radVorneLinks As Rad<br />

Soll das rechte Vorderrad nach links lenken, dann lautet der Aufruf:<br />

radVorneRechts.NachLinksAusschlagen<br />

Wenn Ihnen der Vorteil noch nicht ganz einleuchtet, dann haben Sie noch ein<br />

wenig Geduld, es kommt gleich besser.<br />

Es wurde ja bereits festgestellt, dass Objekte eigene Variablen besitzen können, die<br />

sogenannten Eigenschaften. In unserem Beispiel wird sich das gleich als sehr nützlich<br />

erweisen.<br />

Wenn die Software wissen soll, wie ein angeforderter Lenkausschlag umgesetzt werden<br />

soll, dann muss sie eine Information darüber haben, wie der momentane Ausschlag<br />

ist. In einem konventionellen funktionalen Softwaredesign würden wir<br />

diese Werte in einzelnen Variablen festhalten müssen (<strong>für</strong> jedes Rad eine), die dann<br />

an zentraler Stelle gepflegt werden (von der Möglichkeit, statische Variablen zu verwenden,<br />

sehen wir hier einmal ab).<br />

Im objektorientierten Design brauchen wir die Variable nur einmal <strong>für</strong> die Klasse<br />

Rad zu deklarieren, und schon sind zwei Stück verfügbar, <strong>für</strong> jedes der zwei Rad-<br />

Objekte getrennt:<br />

Class Rad<br />

MomentanerLenkausschlag As Integer<br />

...<br />

End Class<br />

Diese Eigenschaft muss jetzt natürlich noch »gefüttert« werden. Wir erstellen dazu<br />

eine Methode SetzeLenkausschlag, die das <strong>für</strong> uns übernimmt (die Eigenschaft ist<br />

nicht mit Public angelegt worden, denn wir möchten ja nicht, dass irgendwelche<br />

anderen Programme Zugriff auf den Lenkausschlag bekommen und zum Sicherheitsrisiko<br />

werden).<br />

Dabei stellen wir fest, dass die Methoden <strong>für</strong> das Rechts-, Links- und Geradeauslenken<br />

sehr verwandt sind. Daher können wir die eigentliche Lenkarbeit der neuen<br />

Methode überlassen, während die übrigen Methoden sie nur mit dem jeweils passenden<br />

Wert aufrufen.<br />

Um uns die Sache einfacher zu machen, gehen wir davon aus, dass es nur drei mögliche<br />

Werte gibt: 1 <strong>für</strong> rechts, -1 <strong>für</strong> links und 0 <strong>für</strong> geradeaus. Wir wollen dem Fah-


Eigene Klassen und Objekte erstellen 75<br />

rer nicht zumuten, sich die Zahlen zu merken, und hinterlegen sie daher in der Rad-<br />

Klasse selbst als entsprechende Eigenschaften. Wir müssen nur da<strong>für</strong> sorgen, dass<br />

sie richtig initialisiert werden. <strong>Das</strong> übernimmt die Methode New (New wird automatisch<br />

aufgerufen, wenn ein Objekt mit New neu angelegt wird):<br />

Class Rad<br />

iMomentanerLenkausschlag As Integer<br />

iRechts As Integer<br />

iLinks As Integer<br />

iGeradeaus As Integer<br />

Sub New()<br />

iRechts = 1<br />

iLinks = -1<br />

iGeradeaus = 0<br />

End Sub<br />

Sub SetzeLenkausschlag(in_iLenkrichtung%)<br />

If Not ((in_iLenkrichtung = iRechts) Or (in_iLenkrichtung = iLinks) Or _<br />

(in_iLenkrichtung = iGeradeaus)) Then Error 1999, “Ungültiger Wert“<br />

iMomentanerLenkausschlag = in_iLenkrichtung<br />

End Sub<br />

Sub NachRechtsAusschlagen<br />

Call SetzeLenkausschlag(iRechts)<br />

End Sub<br />

Sub NachLinksAusschlagen<br />

Call SetzeLenkausschlag(iLinks)<br />

End Sub<br />

Sub GeradeZiehen<br />

Call SetzeLenkausschlag(iGeradeaus)<br />

End Sub<br />

Property Get MomentaneLenkrichtung As String<br />

Dim strReturn$<br />

Select Case iMomentanerLenkausschlag<br />

Case iRechts: strReturn = “Rechts“<br />

Case iLinks: strReturn = “Links“<br />

Case iGeradeaus: strReturn = “Geradeaus“<br />

End Select<br />

End Property<br />

End Class<br />

Mit der zum Schluss hinzugefügten Property Get sorgen wir da<strong>für</strong>, dass die momentane<br />

Lenkrichtung abgefragt werden kann, ohne dass wir die Eigenschaft iMomentanerLenkausschlag<br />

öffentlich zugänglich machen müssten.<br />

IBM SOFTWARE PRESS


76 Einführung in die <strong>LotusScript</strong>-Programmierung<br />

Hinweis<br />

Eine Property (Eigenschaft) verhält sich einerseits wie eine Methode und<br />

andererseits wie eine Zuweisung mit Einbahnstraßencharakter.<br />

In einer Property können alle möglichen Anweisungen wie in einer Methode<br />

ausgeführt werden. Sie kann sogar parametrisiert werden.<br />

Auf der anderen Seite wird sie aber »von außen« wie eine Eigenschaft aufgerufen.<br />

Einer Property Get kann ein Wert zugewiesen werden, und eine Property<br />

Set kann abgefragt werden. Gibt es nur eine davon, dann kann auch<br />

nur die entsprechende Richtung verwendet werden.<br />

Auf diese Weise kann man Eigenschaften programmieren, die nur gelesen,<br />

nur beschrieben oder sowohl gelesen als auch beschrieben werden können.<br />

Jetzt benötigen wir noch das Auto, an dem die Räder befestigt werden. Da es auch<br />

Autos gibt, bei denen alle vier Räder in den Lenkvorgang einbezogen werden, montieren<br />

wir gleich vier. Normalerweise müssten wir natürlich zwei Sorten von<br />

Rädern erstellen:<br />

Class Auto<br />

Räder List As Rad<br />

Sub New()<br />

Set Räder(“VorneRechts”) = New Rad()<br />

Set Räder(“VorneLinks”) = New Rad()<br />

Set Räder(“HintenRechts”) = New Rad()<br />

Set Räder(“HintenLinks”) = New Rad()<br />

End Sub<br />

End Class<br />

Die Montage geschah in Form einer Liste, weil sich das beim Erstellen der zentralen<br />

Lenkvorrichtung als praktisch erweisen wird.<br />

Jetzt erstellen wir die Lenkung. Sie muss alle vier Räder einstellen. Die hinteren<br />

werden gegenläufig eingestellt. Dies erreichen wir durch das Voranstellen eines<br />

einfachen Minuszeichens. Der Wert <strong>für</strong> Geradeaus ist 0, die Negation davon auch;<br />

also können wir immer so vorgehen.<br />

Allerdings ist es praktischer, der Lenkung nur eine einzige Methode zum Lenken<br />

mitzugeben (es gibt ja auch nur ein Lenkrad). Dann muss der Fahrer beim Aufrufen<br />

mitteilen, in welche Richtung er möchte. Damit er das in sprechender Weise tun<br />

kann, bieten wir im die drei Eigenschaften RECHTS, LINKS und GERADEAUS an.<br />

Dazu werden entsprechende Properties erstellt. Wir können sie auch intern verwenden,<br />

wodurch wir uns die Variablen sparen, die wir <strong>für</strong> die Räder angelegt und<br />

in New initialisiert haben.<br />

Die Lenkung muss natürlich mit den Rädern in Verbindung stehen, also sehen wir<br />

vor, die Räderliste bei Erstellung des Objekts zu übergeben und intern eine Referenz<br />

festzuhalten. Diese wird dann beim Lenkvorgang abgearbeitet.


Eigene Klassen und Objekte erstellen 77<br />

Class Lenkung<br />

iMomentanerLenkausschlag As Integer<br />

lstobRäder As Variant<br />

Sub New(in_lstobRäder As Variant)<br />

lstobRäder = in_lstobRäder<br />

End Sub<br />

Sub Lenken(in_iLenkrichtung%)<br />

If Not ((in_iLenkrichtung = RECHTS) Or (in_iLenkrichtung = LINKS) Or _<br />

(in_iLenkrichtung = GERADEAUS)) Then Error 1999, “Ungültiger Wert“<br />

lstobRäder(“VorneRechts“).SetzeLenkausschlag(in_iLenkrichtung)<br />

lstobRäder(“VorneLinks“).SetzeLenkausschlag(in_iLenkrichtung)<br />

lstobRäder(“HintenRechts“).SetzeLenkausschlag(- in_iLenkrichtung)<br />

lstobRäder(“HintenLinks“).SetzeLenkausschlag(- in_iLenkrichtung)<br />

iMomentanerLenkausschlag = in_iLenkrichtung<br />

End Sub<br />

Property Get MomentaneLenkrichtung As String<br />

Dim strReturn$<br />

Select Case iMomentanerLenkausschlag<br />

Case RECHTS: strReturn = “Rechts“<br />

Case LINKS: strReturn = “Links“<br />

Case GERADEAUS: strReturn = “Geradeaus“<br />

End Select<br />

End Property<br />

Property Get RECHTS As Integer<br />

RECHTS = 1<br />

End Property<br />

Property Get LINKS As Integer<br />

LINKS = -1<br />

End Property<br />

Property Get GERADEAUS As Integer<br />

GERADEAUS = 0<br />

End Property<br />

End Class<br />

Die Lenkung wird am Auto befestigt:<br />

Class Auto<br />

lstobRäder List As Rad<br />

obLenkrad As Lenkung<br />

Sub New()<br />

Set lstobRäder(“VorneRechts”) = New Rad()<br />

IBM SOFTWARE PRESS


78 Einführung in die <strong>LotusScript</strong>-Programmierung<br />

Set lstobRäder(“VorneLinks”) = New Rad()<br />

Set lstobRäder(“HintenRechts”) = New Rad()<br />

Set lstobRäder(“HintenLinks”) = New Rad()<br />

Set obLenkrad = New Lenkung(lstobRäder)<br />

End Sub<br />

Property Get Lenkrad As Lenkung<br />

Set Lenkrad = obLenkrad<br />

End Property<br />

End Class<br />

Jetzt können wir ein Auto mit New erzeugen, auf das Lenkrad zugreifen und in die<br />

Richtungen lenken, in die wir möchten:<br />

Dim obAuto As New Auto<br />

Call obAuto.Lenkrad.Lenken(obAuto.Lenkrad.RECHTS)<br />

Call obAuto.Lenkrad.Lenken(obAuto.Lenkrad.LINKS)<br />

Call obAuto.Lenkrad.Lenken(obAuto.Lenkrad.GERADEAUS)<br />

Ein Aufruf, und es geht in die Richtung, die wir vorgeben. Die ganzen Interna (wie<br />

viele und welche Räder in welche Richtung gelenkt werden) interessieren uns nicht<br />

– so, wie es sich bei einem richtigen Auto gehört.<br />

Und genauso einfach kann sich Software bedienen lassen. Einige Vorteile dieser<br />

Programmierungsart sind:<br />

Die hohe Anschaulichkeit: <strong>Das</strong> macht das Programmieren einfacher.<br />

Es entwickelt sich auf natürliche Weise eine sinnvolle Architektur.<br />

Es werden wie von allein abgeschlossene Module (die Klassen) erstellt, die sich<br />

einzeln fortentwickeln und warten lassen.<br />

Es bilden sich klare Schnittstellen heraus, was den Überblick und die Austauschbarkeit<br />

fördert.<br />

Es wird eine hohe Wiederverwendbarkeit des Codes und von Codeteilen erreicht.<br />

Aber das war noch nicht alles. Sie werden gleich noch mehr Möglichkeiten zur<br />

Codeoptimierung kennenlernen. Außerdem wird deutlich werden, wie sich ein<br />

objektorientiertes Design mit der Zeit fortentwickeln kann, ohne dass das eigentliche<br />

Program davon betroffen ist. Der Benutzer merkt davon nichts.<br />

Vererbung<br />

Wenn wir also etwas genauer hinsehen, dann entdecken wir gewisse Gemeinsamkeiten<br />

zwischen der Rad-Klasse und der Klasse Lenkung. Beide beschäftigen sich mit<br />

der Lenkung, die eine <strong>für</strong> ein einzelnes Rad, die andere <strong>für</strong> alle Räder. <strong>Das</strong> bringt<br />

eine gewisse Redundanz mit sich, die wir jetzt mithilfe der Vererbung beseitigen.


Eigene Klassen und Objekte erstellen 79<br />

Zunächst erstellen wir eine Klasse, die die gemeinsamen Merkmale aufnimmt. Da<br />

sich der Einsatz der Properties <strong>für</strong> die Lenkrichtungen ganz gut macht, übernehmen<br />

wir diese Idee auch <strong>für</strong> die gemeinsame Klasse. Wir nennen sie Lenkbares-<br />

Objekt:<br />

Class LenkbaresObjekt<br />

iMomentanerLenkausschlag As Integer<br />

Sub Lenken(in_iLenkrichtung%)<br />

If Not ((in_iLenkrichtung = RECHTS) Or (in_iLenkrichtung = LINKS) Or _<br />

(in_iLenkrichtung = GERADEAUS)) Then Error 1999, "Ungültiger Wert"<br />

iMomentanerLenkausschlag = in_iLenkrichtung<br />

End Sub<br />

Property Get MomentaneLenkrichtung As String<br />

Dim strReturn$<br />

Select Case iMomentanerLenkausschlag<br />

Case RECHTS: strReturn = "Rechts"<br />

Case LINKS: strReturn = "Links"<br />

Case GERADEAUS: strReturn = "Geradeaus"<br />

End Select<br />

End Property<br />

Property Get RECHTS As Integer<br />

RECHTS = 1<br />

End Property<br />

Property Get LINKS As Integer<br />

LINKS = -1<br />

End Property<br />

Property Get GERADEAUS As Integer<br />

GERADEAUS = 0<br />

End Property<br />

End Class<br />

Zunächst lassen wir die Rad-Klasse mit Class Rad As LenkbaresObjekt von unserer neu<br />

erstellten Basisklasse LenkbaresObjekt erben und werfen alles raus, was nicht mehr<br />

benötigt wird. Und siehe da, die Klasse Rad wird ziemlich leer, ja sogar ganz leer.<br />

Alles, was sie benötigt, ist bereits in der Basisklasse vorhanden:<br />

Class Rad As LenkbaresObjekt<br />

End Class<br />

Auch die Methode SetLenkausschlag benötigen wir nicht mehr; sie entspricht der<br />

Methode Lenken aus der Basisklasse.<br />

IBM SOFTWARE PRESS


80 Einführung in die <strong>LotusScript</strong>-Programmierung<br />

Hinweis<br />

Theoretisch könnte man die Räder ganz durch Objekte vom Typ LenkbaresObjekt<br />

ersetzen. Aber um die Architektur klar zu gestalten, ist es besser, sie so zu<br />

belassen. Denn die Verwendung von Rad-Objekten ist näher an der Anschauung<br />

als die Verwendung von LenkbaresObjekt. Und umgekehrt wäre es nicht<br />

sehr geschickt, die Klasse LenkbaresObjekt in Rad umzubenennen, denn dann<br />

müssten wir die Klasse Lenkung von der Klasse Rad erben lassen, und auch das<br />

ist nicht sehr anschaulich. Es ist einfach so, dass die Räder und die Lenkung<br />

sehr viel gemeinsam haben, aber dennoch sehr verschieden sind. Wir können<br />

also nur die Gemeinsamkeiten in eine gemeinsame Basisklasse verlagern, aber<br />

nicht sagen, dass die eine Klasse eine direkte Ableitung von der anderen sei.<br />

Dann lassen wir also auch noch die Klasse Lenkung alle Eigenschaften und Methoden<br />

von LenkbaresObjekt erben. Alles, was vererbt wird, kann aus der Klasse Lenkung<br />

entfernt werden. <strong>Das</strong> macht auch sie wesentlich kürzer. Die SetzeLenkausschlag-Aufrufe<br />

in die Rad-Objekte benennen wir dabei in Lenken um.<br />

Class Lenkung As LenkbaresObjekt<br />

lstobRäder As Variant<br />

Sub New(in_lstobRäder As Variant)<br />

lstobRäder = in_lstobRäder<br />

End Sub<br />

Sub Lenken(in_iLenkrichtung%)<br />

If Not ((in_iLenkrichtung = RECHTS) Or (in_iLenkrichtung = LINKS) Or _<br />

(in_iLenkrichtung = GERADEAUS)) Then Error 1999, "Ungültiger Wert"<br />

lstobRäder("VorneRechts").Lenken(in_iLenkrichtung)<br />

lstobRäder("VorneLinks").Lenken(in_iLenkrichtung)<br />

lstobRäder("HintenRechts").Lenken(- in_iLenkrichtung)<br />

lstobRäder("HintenLinks").Lenken(- in_iLenkrichtung)<br />

iMomentanerLenkausschlag = in_iLenkrichtung<br />

End Sub<br />

End Class<br />

Die Methode Lenken haben wir in dieser Klasse neu formulieren müsssen, da sie bei<br />

dieser Klasse eine andere Bedeutung hat als bei den Rädern. Man nennt diese Art<br />

der Neuformulierung Methoden überschreiben. Bei <strong>LotusScript</strong> muss man darauf achten,<br />

dass die Signatur der neu formulierten Methode genau mit der Signatur der<br />

vererbten übereinstimmt (damit sind gemeint: die Art der Prozedur, der Name, der<br />

oder die Parameter und der Rückgabewert). Für diejenigen, die sich mit der objektorientierten<br />

Programmierung auskennen: Methoden von <strong>LotusScript</strong>-Klassen können<br />

überschrieben, aber nicht überladen werden.


Eigene Klassen und Objekte erstellen 81<br />

Für die Erstellung des Auto-Objekts und die Lenkaufrufe ändert sich nichts:<br />

Dim obAuto As New Auto<br />

Call obAuto.Lenkrad.Lenken(obAuto.Lenkrad.RECHTS)<br />

Call obAuto.Lenkrad.Lenken(obAuto.Lenkrad.LINKS)<br />

Call obAuto.Lenkrad.Lenken(obAuto.Lenkrad.GERADEAUS)<br />

Es gibt noch eine Verbesserungsmöglichkeit. Auch diese möchte ich Ihnen nicht<br />

vorenthalten:<br />

Die überschriebene Methode Lenken der Klasse Lenkung könnte einen Teil ihrer Arbeit<br />

der Basisklasse überlassen. Denn die Abprüfung, ob der Parameter zur Lenkrichtung<br />

zulässig ist, ist in beiden gleich, und auch das Festhalten der internen Eigenschaft<br />

iMomentanerLenkausschlag wiederholt sich.<br />

Wir können diese Schritte also entfernen, müssen nur da<strong>für</strong> sorgen, dass zu Beginn<br />

die Methode Lenken aus der Basisklasse aufgerufen wird. Dies geschieht mit dem<br />

doppelten Punktoperator in Verbindung mit dem Namen der Basisklasse, also mit<br />

der Anweisung Call LenkbaresObjekt..Lenken(in_iLenkrichtung):<br />

Class Lenkung As LenkbaresObjekt<br />

lstobRäder As Variant<br />

Sub New(in_lstobRäder As Variant)<br />

lstobRäder = in_lstobRäder<br />

End Sub<br />

Sub Lenken(in_iLenkrichtung%)<br />

Call LenkbaresObjekt..Lenken(in_iLenkrichtung)<br />

lstobRäder("VorneRechts").Lenken(in_iLenkrichtung)<br />

lstobRäder("VorneLinks").Lenken(in_iLenkrichtung)<br />

lstobRäder("HintenRechts").Lenken(- in_iLenkrichtung)<br />

lstobRäder("HintenLinks").Lenken(- in_iLenkrichtung)<br />

End Sub<br />

End Class<br />

Es ist zu empfehlen, sich den Ablauf des Programms mal im Debugger anzusehen.<br />

Dort wird uns als Objekt der obersten Ebene unser Auto-Objekt angezeigt. Gleichzeitig<br />

kann man den Aufbau der Objekte <strong>für</strong> Auto, Lenkung und Räder und die<br />

jeweiligen Zustände ansehen (repräsentiert durch die gemeinsame interne Eigenschaft<br />

iMomentanerLenkausschlag). Dazu habe ich einen Screenshot nach jedem der<br />

vier Vorgänge erstellt, sodass man zumindest den groben Ablauf sehen kann:<br />

IBM SOFTWARE PRESS


82 Einführung in die <strong>LotusScript</strong>-Programmierung<br />

Abbildung 3.28 Objektzustände der Räder und der Lenkung nach Erstellung der Variable obAuto.<br />

Alle Lenkangaben in iMomentanerLenkausschlag stehen auf GERADEAUS (0).<br />

Abbildung 3.29 Die Objektzustände nach dem Rechtslenken. Die Vorderräder stehen auf RECHTS (1).<br />

<strong>Das</strong>selbe trifft auf den in obLenkrad gespeicherten Gesamtzustand zu. Die<br />

Hinterräder stehen auf LINKS (-1). <strong>Das</strong> ist aufgrund des geforderten gegenläufigen<br />

Verhaltens korrekt.<br />

Abbildung 3.30 Die Objektzustände nach dem Linkslenken. Alle Lenkzustände haben sich ins<br />

Gegenteil verkehrt. Auch das ist korrekt.


Gültigkeitsbereiche und Module 83<br />

Abbildung 3.31 Die Objektzustände nach dem Geradeauslenken. Alle Lenkzustände<br />

(iMomemtanerLenkausschlag) sind wieder auf GERADEAUS (0).<br />

3.13 Gültigkeitsbereiche und Module<br />

Variablen haben einen begrenzten Gültigkeitsbereich. Er beginnt mit der Deklaration<br />

und erstreckt sich ab da auf einen der drei möglichen Bereiche Modul, Prozedur<br />

und benutzerdefinierte Klasse bzw. benutzerdefinierter Datentyp.<br />

Prozeduren werden im nächsten Abschnitt ausführlich behandelt. Für diesen<br />

Abschnitt genügt es zu wissen, dass eine Prozedur ein Stück Programmcode ist.<br />

Vielleicht haben Sie bei der Arbeit mit Sub Initialize schon gesehen, dass ein Agent<br />

noch einen weiteren Eventhandler (also eine spezielle Prozedur) hat, nämlich<br />

Sub Terminate. Außerdem sind noch zwei Abschnitte sichtbar: (Options) und (Declarations).<br />

Diese zwei Prozeduren bilden mit den Abschnitten zusammen ein (Programm-)<br />

Modul. Wie Sie im nächsten Abschnitt sehen werden, kann der Entwickler weitere<br />

Prozeduren anlegen. Wenn wir dies im Agenten tun, dann werden sie automatisch<br />

zu diesem einen Modul hinzugefügt.<br />

Andere Module finden wir bei Masken, Ansichten, Datenbanken usw. Module sind<br />

also in der Regel an Gestaltungselemente der Datenbanken gebunden, aber nicht<br />

immer. Eine Ausnahme sind die <strong>LotusScript</strong>-Bibliotheken. Sie stellen eigene<br />

Module dar, die in andere Module hinzugeladen werden können. Zwar werden sie<br />

in gewisser Weise auch als Gestaltungselemente bezeichnet, aber sie sind keinem<br />

»sichtbaren« Teil der Datenbank zugeordnet.<br />

Variablen, die in einer Prozedur deklariert werden, sind bis zum Ende der Prozedur<br />

gültig. Variablen, die in einem Modul deklariert werden, sind innerhalb des<br />

Moduls gültig. Variablen, die innerhalb einer Klasse oder eines benutzerdefinierten<br />

Datentyps deklariert werden, sind innerhalb des Gültigkeitsbereiches der damit<br />

angelegten Variablen gültig.<br />

Modifizierer<br />

Um die Sache nicht zu einfach werden zu lassen, gibt es auch noch die Modifizierer<br />

Public, Private und Static.<br />

IBM SOFTWARE PRESS


84 Einführung in die <strong>LotusScript</strong>-Programmierung<br />

In der Designer-Hilfe werden sie zwar nicht so genannt, sondern einfach als abgewandelte<br />

Schlüsselwörter <strong>für</strong> die Variablendeklaration behandelt (als Ergänzung zu<br />

Dim). Aber sie haben im Prinzip keine andere Funktion, als den Sichtbarkeitsbereich<br />

zu verändern.<br />

Modulebene<br />

In einem Modul kann eine Variable mit einer öffentlichen oder einer privaten<br />

Sichtbarkeit angelegt werden. Im ersten Fall sind die Variablen auch außerhalb des<br />

Moduls sichtbar, im anderen Fall nur innerhalb. Wenn Sie beispielsweise eine<br />

<strong>LotusScript</strong>-Bibliothek zu einem Maskenmodul hinzuladen (mit Use), dann sind<br />

deren Variablen <strong>für</strong> die Maskenprozeduren nur sichtbar, wenn sie in der Bibliothek<br />

als öffentlich deklariert wurden.<br />

Hiermit können wir die beiden Begriffe Gültigkeit und Sichtbarkeit noch etwas<br />

genauer fassen: Beide Modulvariablen sind gültig, solange das Modul geladen ist.<br />

Doch ist die private Modulvariable nur innerhalb des Moduls sichtbar, also zugänglich.<br />

Die öffentliche Variable ist auch außerhalb sichtbar.<br />

Die gleichen Bedingungen gelten <strong>für</strong> die Deklaration von Prozeduren, Klassen und<br />

Typen. Wird eines dieser Elemente mit Private deklariert, so ist es nur innerhalb des<br />

Moduls sichtbar.<br />

Auf diese Weise kann man Teile eines Moduls, die nur intern verwendet werden,<br />

vor dem Zugriff von außen verstecken. Nach außen zeigt man dann nur die Elemente,<br />

die in einem anderen Modul zur Anwendung kommen sollen. Diese kann<br />

man dann als die API des Moduls bezeichnen.<br />

Prozedurebene<br />

Innerhalb von Prozeduren sind Variablen immer nicht-öffentlich. Da man hier<br />

nicht zwischen privat und öffentlich entscheiden kann, gibt es in dieser Hinsicht<br />

nur eine Deklarationsmöglichkeit, und die heißt Dim. Dim legt in diesem Fall eine<br />

private Variable an, auch wenn das Schlüsselwort Private nicht zum Einsatz kommen<br />

kann.<br />

Sie können aber eine andere Modifikation durchführen, die speziell <strong>für</strong> Prozeduren<br />

gilt: Static. Mit Static wird eine statische Variable angelegt. Damit wird die Aufbewahrungsdauer<br />

des zuletzt zugewiesenen Variableninhalts verändert. Normalerweise<br />

ist der Inhalt mit dem Verlassen einer Funktion vergangen. Bei statischen<br />

Variablen wird er hingegen bis zum nächsten Aufruf der Funktion aufbewahrt.<br />

Solange das Modul mit der Funktion geladen ist, wird man also bei jedem Aufruf<br />

den zuletzt zugewiesenen Wert vorfinden.<br />

Elementvariablen von benutzerdefinierten Typen<br />

Die Elemente eines mit Type erzeugten Datentyps (also dessen Variablen) sind<br />

immer öffentlich sichtbar (solange die Variable dieses Datentyps gültig ist). Daher<br />

wird beim Aufruf von Type auch keine Anweisung vor die Deklaration geschrieben,<br />

weder Dim noch Private noch Public oder Static.


Wie geht es nun weiter? 85<br />

Eigenschaften und Methoden von Klassen<br />

Die Eigenschaften von mit Class erzeugten benutzerdefinierten Klassen bzw. der<br />

davon angelegten Objekte (also deren Variablen) sind standardmäßig privat bezüglich<br />

des Objekts. Sie sind also nur innerhalb des Objekts sichtbar. Sollen sie von<br />

außen sichtbar sein, müssen sie Public deklariert werden.<br />

Bei den Methoden (also den in den Klassen enthaltenen Prozeduren) verhält es sich<br />

genau umgekehrt. Sie sind standardmäßig öffentlich sichtbar, können aber mit<br />

Private auf den Innenbereich der Klasse bzw. der von ihr abgeleiteten Objekte<br />

beschränkt werden.<br />

3.14 Wie geht es nun weiter?<br />

Sie sind nun in die Grundzüge der <strong>Notes</strong>/<strong>Domino</strong>-Programmierung mit Lotus-<br />

Script eingeweiht. Sie sind sogar in der Lage, komplexe objektorientierte Programme<br />

mit <strong>LotusScript</strong> zu entwerfen.<br />

Nun werden Sie sich sicherlich Ihren speziellen Aufgaben zuwenden wollen, die Sie<br />

mit <strong>LotusScript</strong> lösen möchten.<br />

Um Ihnen zu helfen, schnellstmöglich die <strong>LotusScript</strong>-Funktionen und <strong>Notes</strong>-Klassen<br />

zu finden, die Ihnen dabei zur Seite stehen, sind die übrigen Ausführungen<br />

nach Themen und Stichworten angeordnet.<br />

Im <strong>LotusScript</strong>-Bereich finden Sie jeweils ein Thema mit einer mehr oder weniger<br />

langen Einführung, in der gezeigt wird, wie es mit den zur Verfügung stehenden<br />

Funktionen bearbeitet werden kann. Anschließend finden Sie dann jeweils die<br />

vollständige Liste der Funktionen, die mit Syntax und eventuellen Besonderheiten<br />

behandelt werden.<br />

Daran schließt sich ein Bereich von Kapiteln an, die einzelne Themen behandeln,<br />

die mit <strong>Notes</strong>-Klassen bearbeitet werden können. <strong>Das</strong> ist aber nicht immer ausschließlich<br />

zu verstehen. Kapitel wie 8, Datumswerte und Zeitangaben, (Seite 325)<br />

und 10, Dateien und Streams, (Seite 375) befassen sich auch sehr ausführlich mit<br />

<strong>LotusScript</strong>-Funktionen.<br />

Daran fügt sich ein großer Bereich an, in dem die <strong>Notes</strong>-Klassen alphabetisch aufgeführt<br />

sind und in der Form einer Referenz besprochen werden.<br />

Sie werden schnell merken, dass die systematische Abhandlung der <strong>LotusScript</strong>-<br />

Funktionen und der <strong>Notes</strong>-Klassen keine einfache Wiederholung der Designer-<br />

Hilfe darstellt. Wo immer es angebracht war, werden zusätzliche Hinweise gegeben,<br />

die Sie auf Fallgruben und praktische Anwendungsmöglichkeiten aufmerksam<br />

machen. Andererseits sind hier zwar meistens, aber nicht immer sämtliche syntaktischen<br />

Hinweise und Wertebereiche aufgeführt, da eben das Geben von praktischen<br />

Hinweisen im Vordergrund steht. Wenn Sie also einen Hinweis vermissen,<br />

dann sollten Sie auch die Designer-Hilfe zu Rate ziehen.<br />

Auch der sorgfältige Index soll Ihnen helfen, schnell Hinweise zu den Themen zu<br />

finden, die Sie interessieren.<br />

IBM SOFTWARE PRESS

Hurra! Ihre Datei wurde hochgeladen und ist bereit für die Veröffentlichung.

Erfolgreich gespeichert!

Leider ist etwas schief gelaufen!