Sie sind auf Seite 1von 56

Grundlagen

Teil I führt Sie auf praktische Weise zügig in die Programmierung von Notes-/
Domino mit LotusScript ein.
Sie lernen, wo und wie LotusScript-Programme erstellt und zum Laufen gebracht
werden. Es werden sämtliche grundlegenden Elemente besprochen wie Lotus-
Script-Befehle, -Variablen, -Objekte, -Module, -Prozeduren, usw.
Natürlich erfahren Sie auch in allen Einzelheiten, wie der Debugger bedient und
praktisch eingesetzt wird. Dieses Wissen ist eine wichtige Unterstützung bei der
Durchführung effektiver Tests.
Außerdem erhalten Sie eine ausführliche, anschauliche Darstellung zur objektori-
entierten Programmierung unter LotusScript. Ein gutes Verständnis dieses Punktes
wird Ihnen bei der Bildung qualitativ hochwertiger Architekturen sehr behilflich
sein.
Die Darlegung des Stoffes beginnt zunächst sehr detailliert, um Sie beim Einstieg
sicher zu begleiten und zieht dann im Tempo recht schnell an, um Sie schnellst-
möglich zu den wesentlichen Erkenntnissen zu führen, die Sie für eine erfolgreiche
Erstellung und Wartung auch komplexer Programme benötigen.

IBM SOFTWARE PRESS


Einführung in die
LotusScript-
Programmierung
Die Programmierung mit LotusScript ähnelt sehr der Programmierung mit VBA
(Visual Basic for Applications von Microsoft). Abgesehen von der engen Sprach-
verwandtschaft, werden beide in Verbindung mit grafischen Benutzeroberflächen
verwendet. Wer also Erfahrung mit der Erstellung von Makros in Microsoft-Office-
Produkten hat, wird sich mit LotusScript sehr leicht tun.
Für Programmierer, die gerade erst beginnen oder mit grafischen Benutzerober-
flächen weniger Erfahrung haben, müssen einige grundlegende Dinge kurz erläu-
tert werden, damit sie einen guten Einstieg finden.
Wir beginnen gleich praxisorientiert; Learning-by-Doing ist häufig der schnellste
Weg, um Dinge richtig zu »begreifen«. Sie können also jetzt das erste Programm
»anfassen«.

3.1 Das erste Programm


LotusScript-Programme sind immer Teil einer Notes-Datenbank; sie können nicht
frei davon existieren. Wir erstellen also zunächst einmal eine neue Datenbank (ab
Version 8 auch Anwendung genannt) im Notes-Client.

3.1.1 Neue Anwendung (Datenbank) anlegen


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

Abbildung 3.1 Das Erstellen einer neuen Anwendung (Datenbank)

IBM SOFTWARE PRESS


32 Einführung in die LotusScript-Programmierung

Im sich anschließenden Dialog geben Sie einen Titel für die Datenbank und den
Dateinamen und inklusive Pfad an. Wenn Sie den Titel eintragen, wird dieser auto-
matisch auch als Dateiname vorgeschlagen. Sie können den Dateinamen jetzt
natürlich nach Belieben verändern. Außerdem wird dem Namen die Endung .nsf
angehängt. Das ist die Standardendung für Notes-Datenbanknamen.
Ich gebe der Datenbank in meinem Beispiel den Namen LotusScript-Programmie-
rung, und zwar für TITEL und DATEINAME. Sie können es mir nachmachen oder einen
anderen Namen wählen. Alle übrigen Einstellungen lassen wir unverändert und
klicken auf OK (Abbildung 3.2).

Abbildung 3.2 Titel und Dateinamen der neuen Datenbank festlegen

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

Abbildung 3.3 Die neue Datenbank wird gleich geöffnet.


Das erste Programm 33

Sie sehen in der linken Spalte oben den Titel und darunter ein Symbol für die auto-
matisch erstellte, noch unbenannte Vorgabe-Ansicht. Diese ist im rechten Teil zu
sehen. Ihre einzige Spalte trägt im Kopf das Nummernsymbol #. Natürlich sind
noch keine Dokumente enthalten.
Diese brauchen wir jetzt aber erst einmal gar nicht. Wichtig ist, dass wir unsere
Datenbank haben, die als Container für die zu erstellenden Programme dient.

Hinweis
Wie ich bereits gesagt habe, sind LotusScript-Programme immer Teil einer
Notes-Datenbank; sie können nicht frei davon existieren – und umgekehrt:
Wenn man in Notes eine Anwendung mit LotusScript schreibt, dann besteht
diese immer aus mindestens einer Datenbank.
Wohl auch deshalb werden Notes-Datenbanken ab Version 8 auch als Anwen-
dungen bezeichnet. Daher werde ich die beiden Begriffe in diesem Buch auch
schon mal synonym gebrauchen.
Trotzdem werden Sie schnell merken, dass Anwendungen aus Entwicklersicht
aus einer oder mehreren Datenbanken bestehen, also begrifflich eigentlich
davon zu trennen sind. Während die Anwendung mehr das Gesamtprodukt
aus Benutzersicht darstellt, haben wir es als Programmierer eher mit den
Datenbanken als Trägern der Applikationen zu tun.
Der hauptsächliche Grund, warum Datenbanken von IBM jetzt als »Anwen-
dungen« bezeichnet werden, liegt wahrscheinlich in der Einführung des Kon-
zepts der Verbundanwendungen (Composite Applications).
Das Ziel dabei ist es, mithilfe einer Webservice-Architektur für klare Schnitt-
stellen zwischen Einzelapplikationen zu sorgen, die dann zu Verbundanwen-
dungen zusammengestellt werden können. Mehr dazu finden Sie im Kapitel
16, Verbundanwendungen, ab Seite 563.

3.1.2 Anwendung (Datenbank) zur Programmierung öffnen


Wir werden die Datenbank jetzt im Designer öffnen, um mit der Programmierung
beginnen zu können. Schließen Sie dazu die Datenbank mit einem Klick auf das
kleine x-förmige Kreuz auf dem Reiter LOTUSSCRIPT-PROGRAMMIERUNG. Danach
sehen Sie die automatisch angelegte Kachel der Datenbank auf dem Arbeitsbereich
(Kacheln dienen als ein visueller Zugang zu Notes-Datenbanken). Klicken Sie
anschließend mit der rechten Maustaste auf die Kachel, und wählen Sie IN DESIG-
NER ÖFFNEN aus (Abbildung 3.4).

IBM SOFTWARE PRESS


34 Einführung in die LotusScript-Programmierung

Abbildung 3.4 Die Datenbank im Designer öffnen

Es öffnet sich dann automatisch der Domino Designer, das hauptsächliche Pro-
grammierhandwerkzeug des Notes/Domino-Programmierers. Unsere Datenbank
wird in Programmierdarstellung angezeigt (Abbildung 3.5).

Abbildung 3.5 Die neue Datenbank im Domino Designer, fertig zum Erstellen des ersten Programms

Im linken Bereich sehen Sie eine baumartige Darstellung der einzelnen Datenbank-
Elemente, die im Designer bearbeitet werden können: Rahmengruppen, Seiten,
Masken usw. Vieles davon kann mit LotusScript programmiert werden.

Hinweis
Sie sehen, dass ich die Datenbanken respektive Anwendungen über den
Arbeitsbereich verwalte. Eigentlich ist dies eine veraltete Benutzeroberfläche,
die das Erscheinungsbild von Notes in der Vergangenheit sehr geprägt hat.
Vor einiger Zeit wurden unter anderem die Lesezeichen eingeführt, um Notes
moderner erscheinen zu lassen. Für Benutzer mag dies sehr praktisch und
auch ansprechender sein. Zumal die Lesezeichen unter Notes 8 in der Stan-
dardkonfiguration in ein sehr schönes ÖFFNEN-Menü überführt worden sind
(Abbildung 3.6).
Das erste Programm 35

Abbildung 3.6 Die Lesezeichen im neuen Eclipse-basierten Client der Notes 8-


Standardkonfiguration. Sie werden jetzt als ÖFFNEN-Menü dargestellt.

Für Entwickler und Administratoren zeigt sich in der Praxis, dass der gute alte
Arbeitsbereich mit seinen Arbeitsbereichsseiten und Kacheln trotzdem kaum
zu ersetzen ist. Die Art der Anordnung ist im ersten Moment etwas gewöh-
nungsbedürftig, erweist sich dann aber als sehr gut geeignet, um die Über-
sicht über große Mengen von Datenbanken zu behalten.
Sie erreichen den Arbeitsbereich in der Standardkonfiguration (wie in Abbil-
dung 3.61.6 gezeigt) oder in der Basiskonfiguration über das Lesezeichen
ANWENDUNGEN in der linken Navigationsleiste (siehe Abbildung 3.7).

IBM SOFTWARE PRESS


36 Einführung in die LotusScript-Programmierung

Abbildung 3.7 Öffnen Sie den Arbeitsbereich mit den Kacheln über die Lesezeichenleiste.

3.1.3 Unser erstes Programm: Einen Agenten erstellen


Wir werden jetzt einen sogenannten Agenten erstellen, der unser erstes Programm
ausführt.
Klicken Sie dazu bitte auf GEMEINSAMER CODE und AGENTEN (Abbildung 3.8).

Abbildung 3.8 Schritte zum neuen Agenten

Sie sehen rechts eine leere Liste, in der Sie später den neuen Agenten wiederfinden
werden, den Sie jetzt bitte mit einem Klick auf die Aktion NEUER AGENT rechts oben
erstellen.
Es öffnet sich ein Dialog, in dem wir unserem Agenten einen fantasievollen Namen
mit hohem Wiedererkennungswert geben (diejenigen unter Ihnen, die bereits eine
Das erste Programm 37

andere Programmiersprache erlernt haben, werden höchstwahrscheinlich wissen,


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

Abbildung 3.9 Die Einstellungen für den neuen Agenten

Es ist wichtig, dass wir unter LAUFZEIT das richtige ZIEL eingeben, nämlich Keines.
Das ist übrigens eine Einstellung, die für viele LotusScript-Programme genau die
richtige ist, da Sie damit in der Regel die meisten Möglichkeiten bei der Kodierung
haben. Allerdings können Sie in diesem Fall die Dokumentauswahl durch den
Agenten nicht nutzen. Diese muss dann im Script programmiert werden.
Schließen Sie nun den Dialog mit dem kleinen Kreuz rechts oben. Sie werden dann
den neuen Agenten wie in Abbildung 3.10 geöffnet vor sich sehen. Wir müssen nur
noch die richtige Programmierart auswählen (viele Notes-Datenbankelemente
können mit unterschiedlichen Sprachen programmiert werden). Schalten Sie
rechts oben von EINFACHE AKTION(EN) auf LOTUSSCRIPT um.

Abbildung 3.10 Programmierart bzw. -sprache auswählen (Schalten Sie von EINFACHE AKTION(EN) auf
LOTUSSCRIPT um.)

Jetzt sind wir schon an der Stelle, an der wir richtig in LotusScript kodieren kön-
nen. (»Endlich!«, werden Sie vielleicht sagen. Aber diese wenigen Schritte werden
Ihnen schnell in Fleisch und Blut übergehen.)

IBM SOFTWARE PRESS


38 Einführung in die LotusScript-Programmierung

Hinweis
Doch halt, wozu brauchen wir eigentlich einen Agenten?
Nun, LotusScript lässt sich nicht als eigenständiges Programm schreiben.
LotusScript kann nicht von der Kommandozeile gestartet werden. Es muss
immer in irgendwelche Datenbankbestandteile eingebettet werden.
Der klassischen Vorstellung von einem »richtigen Programm« kommt dabei
das Datenbankelement Agent noch am nächsten, und deswegen beginnen wir
mit der Programmierung eines solchen.
Einen Agenten können Sie sich als eine Hülle, einen Container oder auch als
ein Rahmenwerk für Ihr LotusScript-Programm vorstellen. Wir betten das
Programm dort ein und lassen es dann vom Agenten ausführen.
Später werden Sie Programme auch an anderen Stellen einbauen, zum Bei-
spiel in Masken oder Schaltflächen.

Den Agenten mit LotusScript-Code versehen


Wir können unseren Agenten gleich, direkt nach seiner Fertigstellung, über das
Menü des Notes-Clients starten. Wenn der Agent startet, dann wird er automatisch
den Code ausführen, der in seinem INITIALIZE-Abschnitt steht. Diesen Code werden
wir jetzt noch schnell einfügen.

Abbildung 3.11 LotusScript-Ansicht des Agenten “Hello World“

Klicken Sie also bitte links in der Liste auf INITIALIZE (Abbildung 3.11), und geben
Sie dann rechts Folgendes ein:
Messagebox "Hello World. I’m the champion!"
Das war’s schon. Das ist Ihr erstes LotusScript-Programm (Abbildung 3.12).

Abbildung 3.12 Das “Hello World“-Programm


Das erste Programm 39

Nach getaner Arbeit möchten wir natürlich sehen, wie dieses aufwendige und
wichtige Programm in der Realität arbeitet. Dazu schließen Sie bitte den Agenten
mit dem kleinen Kreuz oben in seinem Fenster-Reiter. Sie werden gefragt werden,
ob Sie Ihre Änderungen speichern möchten, und dazu sagen Sie selbstverständlich
ja. Anschließend können Sie Ihr fertiges Produkt in der Liste der Agenten bewun-
dern (Abbildung 3.13).

Abbildung 3.13 Der fertige “Hello World“-Agent

Den Agenten starten


Sie können den Agenten jetzt über das Menü mit AGENT/STARTEN laufen lassen.
(Dazu muss sich der blaue Cursorbalken auf dem Agenten befinden, so wie es in
Abbildung 3.13 zu sehen ist.) Oder Sie klicken mit der rechten Maustaste auf den
Agenten in der Liste und wählen aus dem Kontextmenü den Punkt STARTEN aus
(siehe Abbildung 3.14 und Abbildung 3.15).

Abbildung 3.14 So starten Sie den Agenten über das Designer-Menü.

Abbildung 3.15 So starten Sie den Agenten über das Kontextmenü.

IBM SOFTWARE PRESS


40 Einführung in die LotusScript-Programmierung

Egal, wie Sie den Agenten starten, als Resultat erhalten Sie folgende Ausgabe (Abbil-
dung 3.16):

Abbildung 3.16 Die Ausgabe unseres ersten LotusScript-Programms

3.2 Die grundlegenden Schritte zur Erstellung


von LotusScript-Programmen
Nachdem wir so erfolgreich waren, können wir uns erst einmal zurücklehnen und
in Ruhe rekapitulieren, was wir genau gemacht haben – und wie wir diese Erkennt-
nisse in Zukunft verwenden können.

Schritt 1
Wir haben einen Agenten erstellt, der als Container für unser Programm dient.
In anderen Fällen werden Sie auch Masken, Seiten, Schaltflächen und andere Ele-
mente verwenden.

Schritt 2
Wir haben uns einen geeigneten »Startpunkt« für unseren Code gesucht und sind
mit Sub Initialize fündig geworden.
In Masken sind beliebte Startpunkte Sub PostOpen, Sub QueryClose usw. Ähnlich ver-
hält es sich bei Seiten, Ansichten und Datenbank-Scripts. Man nennt sie auch
Eventhandler (Routinen zur sogenannten Ereignisbehandlung). Weitere Details
dazu finden Sie im Abschnitt 3.9, Weitere Startpunkte für LotusScript-Programme, auf
Seite 66.

Schritt 3
Im Eventhandler Sub Initialize haben wir unseren Code eingegeben. Und das wird
bei anderen Startpunkten natürlich genauso gehandhabt.

Schritt 4
Dann haben wir den Agenten geschlossen. Dabei wurde er gespeichert.

Syntaxüberprüfung und Kompilierung


Aber hier ist noch etwas mehr passiert. Das Programm wurde automatisch auf kor-
rekte Syntax hin untersucht und kompiliert.
Hätten Sie einen syntaktischen Fehler gemacht (also etwas geschrieben, was Lotus-
Script nicht versteht), dann hätten Sie eine entsprechende Fehlermeldung erhal-
Die grundlegenden Schritte zur Erstellung von LotusScript-Programmen 41

ten. Sie können ja den Agenten spaßeshalber noch einmal öffnen und Messagebox in
Massagebox ändern (ein beliebter Rechtschreibfehler). Versuchen Sie dann, den
Agenten noch einmal zu speichern. Das können Sie diesmal tun, ohne ihn zu
schließen. Wählen Sie einfach im Menü DATEI/SPEICHERN aus, oder klicken Sie auf
das Diskettensymbol in der Toolbar-Leiste. Auch die Verwendung von [Strg] + [S]
ist möglich. Auf jeden Fall erhalten Sie die Meldung aus Abbildung 3.17.

Abbildung 3.17 Die Syntaxprüfung hat im Code einen Fehler erkannt.

Den Fehler hätten Sie in diesem Fall auch schon vorher sehen können, denn der
LotusScript-Editor prüft die verwendeten Begriffe und Operatoren bereits während
der Eingabe. Wenn er bekannte Schlüsselwörter erkennt, dann färbt er sie blau ein.
Messagebox ist ein solches Schlüsselwort und wird erkannt. Nachdem wir aber das
erste »e« gegen ein »a« ausgetauscht hatten, handelte es sich um keinen bekannten
(eingebauten) Begriff mehr, und Massagebox wurde schwarz.
Man kann also schon während der Eingabe erkennen, ob man die richtigen Schlüs-
selwörter verwendet.

Schritt 5
Zum Schluss haben wir den Agenten gestartet. Was dann passierte, ist wichtig für
das Grundverständnis aller LotusScript-Programme.
Der Notes-Client hat beim Start die Kontrolle übernommen. Er weiß, dass in einem
Agenten eine Prozedur namens Sub Initialize vorkommen muss. Eine Prozedur ist
eine Funktion ohne Rückgabewert. Mehr dazu folgt später im Abschnitt 3.5, Eine
eigene Prozedur schreiben. Der Client weiß das also und startet sie für uns. Damit kam
dann auch unsere Codezeile Messagebox “Hello World. I’m the champion!“ zur Ausfüh-
rung.
Prozeduren beginnen immer mit dem Kopf Sub <Prozedurname> und enden unten mit
dem Anweisungsteil End Sub. Dazwischen steht der Code, der von der Prozedur aus-
geführt werden soll. In unserem Fall lautet die gesamte Prozedur:
Sub Initialize
Messagebox "Hello World. I’m the champion!"
End Sub
Wir haben allerdings nur die mittlere Zeile hingeschrieben, weil der Client wie
gesagt weiß, dass ein Agent eine Prozedur Initialize haben muss, und daher den
»Rahmen«, nämlich Kopf und Fuß, schon selbst hingeschrieben hat.
Der Hinweis, dass das Programm beim Speichern kompiliert wurde, braucht Sie im
Prinzip nicht weiter zu interessieren.

IBM SOFTWARE PRESS


42 Einführung in die LotusScript-Programmierung

Hinweis
Falls Sie es doch genauer wissen wollen, nur so viel zur Erklärung:
Der Code wird beim Kompilieren in eine andere Form gebracht; eine Form,
die vom LotusScript-Interpreter verstanden werden kann.
Der Interpreter ist ein internes Programm, das beim Aufruf von LotusScript-
Code die Anweisungen ausführt, die der Entwickler notiert hat (wie Message-
box). Diese Form des auszuführenden Codes nennt man Objektcode.
Der Objektcode wird für den Benutzer unsichtbar neben dem vom Entwickler
geschriebenen Programm abgespeichert.

3.3 Variablen – die temporären Speicherplätze


Wenn man in Programmen mit Daten, Werten und Texten arbeitet, dann ist es
nicht immer praktisch, sie direkt hinzuschreiben. Ja, in der Regel ist es gar nicht
möglich. Bei unserem letzten Beispiel war das noch völlig in Ordnung. Wir haben
den Text “Hello World. I’m the champion!“ einfach hingeschrieben, und Messagebox
war damit zufrieden.
Jetzt möchten wir aber gern eine wiederholte Ausgabe tätigen, bei der ein bestimm-
ter Textteil immer gleich ist. Dann ist es natürlich zeitsparender, wenn wir ihn nur
einmal hinzuschreiben brauchen. Dazu müssen wir ihn irgendwo speichern, damit
er uns auf Wunsch immer wieder zur Verfügung steht. Da wir den Wert nur wäh-
rend des Programmablaufs benötigen, reicht es, ihn temporär zu speichern (also im
Arbeitsspeicher statt auf der Festplatte).
Die Antwort auf diese Herausforderung lautet: Variablen.

Variablen
Variablen sind benannte Speicherplätze, auf die während eines Programm-
ablaufs zugegriffen werden kann. In LotusScript sind Variablen immer verän-
derbar, d. h., ihnen können während des Programmablaufs jederzeit neue
Werte zugewiesen werden.

3.3.1 Variablen deklarieren


Eine Variable wird meistens mit der Anweisung Dim erstellt. Beispielsweise so:
Dim strVariablenName As String
Dim ist die Abkürzung des englischen Begriffs Dimension und bedeutet »Dimensio-
nierung, Maßangabe«. Mit Dim wird also der gewünschte Speicherplatz »dimensio-
niert«. Man nennt diesen Vorgang auch Deklaration.
Bei Programmvariablen gehört dazu nicht nur die Größe, sondern auch die Art der
Daten, die dort eingelagert werden sollen. Zum einen hilft das der Speicherverwal-
Variablen – die temporären Speicherplätze 43

tung im Hintergrund, sich auf das einzustellen, was da kommt, und zum anderen
hilft es, mögliche logische Fehler bei der Datenzuordnung von vornherein besser
zu erkennen.

Achtung
Variablen müssen immer vor ihrer ersten Verwendung deklariert werden. Tun
Sie dies nicht, dann kann es sein, dass LotusScript dies für Sie unsichtbar im
Hintergrund tut. Das sollten Sie aber unterbinden, indem Sie immer im
Abschnitt (Options) Folgendes eingeben: Option Declare (oder Option Explicit,
was funktional dasselbe ist). Mehr dazu finden Sie im Abschnitt 4.2 Optionen
und Voreinstellungen, ab Seite 130.

Die Angabe As String sagt aus, dass in dem angeforderten Speicherplatz eine Zei-
chenkette abgelegt werden soll (in unserem Hello World-Programm war das eine
Aneinanderreihung von Buchstaben). Außerdem wird auf diese Weise klarge-
macht, dass über die Größe noch nicht viel gesagt werden kann. String-Variablen
können nämlich während des Programmablaufs fast beliebig wachsen und auch
schrumpfen.

Hinweis
Es gibt auch die Möglichkeit, String-Variablen mit fester Länge zu deklarieren.
Außerdem gibt es natürlich auch andere Arten von Variablen, zum Beispiel
zur Verwaltung von Zahlen. Man spricht dabei von verschiedenen Daten-
typen.

Der Begriff direkt nach Dim ist der Name, der dieser Variablen gegeben wird (str-
VariablenName). Unter diesem Namen kann auf die Variable und damit auf den mit
ihr verbundenen Speicherplatz zugegriffen werden.
Bei der Wahl des Namens ist man sehr flexibel. So kann man zum Beispiel jede Buch-
stabenkombination unseres Alphabets wählen, solange sich kein Begriff ergibt, der
schon von der LotusScript-Sprache selbst belegt ist.
In diesem Beispiel habe ich mit str ein Präfix verwandt, das dem Leser des Pro-
gramms deutlich macht, dass es sich hier um eine String-Variable handelt. Auf die
Funktion der Variablen hat das keinerlei Einfluss. Solche Präfixe sind aber sehr
praktisch, um auch bei langen Programmen den Überblick zu behalten, was für
Daten in welchen Variablen abgelegt werden.
Ich kann Sie nur dazu ermuntern, sich einen entsprechenden Styleguide anzuge-
wöhnen. Verwenden Sie für Variablennamen immer Präfixe, und zwar möglichst
gängige bzw. sprechende Präfixe. Auch die Namen der Variablen sollten möglichst
klar für den Inhalt oder die Verwendung sprechen. Das sollten Sie auch dann tun,
wenn Sie erfahrene Programmierer kennenlernen, die sich über solche Regeln hin-
wegsetzen.

IBM SOFTWARE PRESS


44 Einführung in die LotusScript-Programmierung

Datentyp-Suffixe
In Basic-Sprachen wie LotusScript kann man viele Datentypen statt mit der Formu-
lierung As Datentyp auch mit einem Suffix angeben.
Für String-Variablen lautet das Suffix $, und so könnten wir die obige Deklaration
auch wie folgt notieren:
Dim strVariablenName$
Diese Art der Deklaration hat den Vorteil, dass Sie weniger schreiben müssen und
mit ein wenig Übung die manchmal lange Liste der Datendeklarationen schneller
überblicken können.

Beispieldeklarationen für weitere Datentypen


Bei den folgenden Deklarationen sind zu Ihrer Orientierung einige Deklarationen
ohne und mit Suffix gegenübergestellt:
Dim iKleineGanzzahl As Integer
Dim iKleineGanzzahl%
Dim lngGroßeGanzzahl As Long
Dim lngGroßeGanzzahl&
Dim sngKleineFließkommazahl As Single
Dim sngKleineFließkommazahl!
Dim dblGroßeFließkommazahl As Double
Dim dblGroßeFließkommazahl#
Für die folgenden Deklarationen gibt es keine Suffixe:
Dim byteOktett As Byte
Dim bWahrheitswert As Boolean
Dim vEinZiemlichBeliebigerInhalt As Variant

3.3.2 Einen Wert zuweisen


Einer Variablen wird ihr Wert mit dem Zuweisungsoperator = zugeordnet.
Als Beispiel erstellen wir die Variable strAnzeigeText und weisen ihr die nachher
mehrfach zu verwendende Zeichenkette “Hello World. I’m the champion!“ zu:
Dim strAnzeigeText As String

strTextteil = “Hello World. I’m the champion!“


Der Name der Variablen, die den Wert aufnimmt, steht links. Der Wert steht immer
rechts.
Will man Variableninhalte ändern, weist man einfach einen neuen Wert zu.
Ausdrücke erstellen und verwenden 45

3.3.3 Auf eine Variable zugreifen


Der Zugriff auf den Wert einer Variablen ist denkbar einfach. Man übergibt an der
Stelle, an der der eigentliche Wert stehen müsste, den Variablennamen. Das Pro-
gramm sucht sich dann zur Laufzeit die entsprechende Speicherstelle und holt von
dort die hinterlegten Daten.
Zum Beispiel könnten wir mit einem Aufruf von Messagebox den Text ausgeben, der
vorhin in der Variablen strTextteil gespeichert wurde:
Messagebox strTextteil
Komplett dargestellt, würde der Code so ausssehen:
Sub Initialize
Dim strAnzeigeText As String

strAnzeigeText = “Hello World. I’m the champion!“


Messagebox strAnzeigeText
End Sub

Achtung
Wenn man eine Variable im Programm anspricht, deren Datentyp mit einem
Suffix angegeben wurde, dann kann man das Suffix als Namensbestandteil
gebrauchen, muss es aber nicht tun. Im nächsten Beispiel werden Sie beide
Möglichkeiten nebeneinander sehen.
Allerdings sollten Sie sich für eine davon entscheiden. Nichts ist unübersicht-
licher, als wenn man solche Verfahrensweisen mitten im Code ändert! Die
Mischung zeige ich hier nur einmal, um die Gleichwertigkeit zu veranschau-
lichen.
Wenn eine Variable ohne Suffix deklariert wurde, dann muss sie in der Folge
auch ohne Suffix verwendet werden.

3.4 Ausdrücke erstellen und verwenden


Jetzt möchten wir die Variable wie bereits angedeutet nutzen, um mehrere ähnlich
lautende Ausgaben mit Messagebox zu machen, ohne die sich wiederholenden Texte
jedes Mal neu hinzuschreiben. Dazu benötigen wir eine Möglichkeit, um zwei Zei-
chenketten aneinanderzuhängen, und das ist der Zeichenketten-Operator &.
Wir kommen gleich zur Sache und schreiben:
Sub Initialize
Dim strAnzeigeText$

strAnzeigeText$ = “Hello World. I’m the champion!“

IBM SOFTWARE PRESS


46 Einführung in die LotusScript-Programmierung

Messagebox strAnzeigeText & “ Gestern!”


Messagebox strAnzeigeText$ & “ Heute!”
Messagebox strAnzeigeText & “ Morgen!”
End Sub
Listing 3.1 So verwenden Sie eine Variable in Verbindung mit dem Zeichenkettenoperator &,
um mehrere ähnliche Texte zu bilden.

Während sich das leicht größenwahnsinnige Progrämmchen immer mehr auf-


bläht, wird dreimal Messagebox aufgerufen, und jedes Mal wird vom &-Operator eine
Kombination aus “Hello World. I’m the champion!“ und dem sich ändernden
Anhängsel “ Gestern!“, “ Morgen!“ usw. gebildet und dann als Meldung ausgegeben.
Eine solche Berechnung von Werten nennt man auch Ausdruck. Der Ausdruck lau-
tet hier im ersten Fall: strAnzeigeText & “ Gestern!”.

Ausdruck
Ein Ausdruck ist eine wie auch immer geartete Berechnung von Werten. Die
Berechnung kann auch unter Einbeziehung von Funktionen und Objekten
erfolgen.

Wenn Sie noch kein so routinierter Programmierer sind, dann wird Ihnen die Defi-
nition etwas schwierig bzw. schwammig vorkommen. Die Frage ist: Wo beginnt ein
Ausdruck, und wo hört er auf? Und zu den Begriffen Funktion und Objekt kommen
wir erst später. Am besten ist es, Sie vergessen das Thema erst einmal wieder. Die
genaue Abgrenzung dieses Begriffs ist in der Praxis des LotusScript-Entwicklers
nicht so wichtig. Außerdem wird er immer mal wieder in recht harmlosen Zusam-
menhängen auftauchen, und dann wird die genaue Bedeutung ganz nebenbei
immer klarer.
Was Sie allerdings wissen sollten: Fast überall, wo ein Wert oder der Inhalt einer
Variablen benötigt wird, können Sie stattdessen auch einen Ausdruck notieren.
Dieser wird dann automatisch berechnet, und der sich ergebende Wert wird an sei-
ner Stelle übergeben. Das haben Sie gerade gesehen, als wir der Variablen strAnzei-
geText zunächst eine Zeichenkette, dann aber mehrfach einen Ausdruck nach der
Art strAnzeigeText & “ Gestern!” zugewiesen haben.
Hier haben wir eine sehr einfache Berechnung mit Zeichenketten vorgenommen.
Andere Ausdrücke können Berechnungen von Zahlen- und Datumswerten (nume-
rische Ausdrücke) und von Wahrheitswerten (boolesche Ausdrücke) einschließen.

3.4.1 Numerische Ausdrücke


Beispiel für eine Zahlenberechnung:
Dim iErgebnis%

iErgebnis = 10 * 2.5 – 3
Ausdrücke erstellen und verwenden 47

Der Ausdruck ist hier: 10 * 2.5 – 3. Dieser (bzw. sein Wert) wird der Variablen iErgeb-
nis zugeordnet. Durch die Zuordnung wird der Ausdruck automatisch berechnet.

Hinweis
Unser deutsches Dezimalkomma ist im Englischen ein Punkt und wird so
auch von LotusScript gefordert.

Vorrangregeln
Bei der Berechnung von Ausdrücken gelten gewisse Vorrangregeln, die im Bereich
der arithmetischen Berechnungen an den mathematischen Usus angelehnt ist.
Zum Beispiel gilt »Punktrechnung von Strichrechnung«. Der Ausdruck 10 * 2.5 – 3
wird also zunächst zu 25 – 3 und ergibt das Resultat 22.
Wollten wir es anders haben, so müssten wir entsprechende Klammern setzen:
10 * (2.5 – 3) wird ausgewertet zu 10 * (-0.5) und gibt -5.

3.4.2 Boolesche Ausdrücke


Boolesche Ausdrücke werden mit den Wahrheitswerten True und False und den
Operatoren And, Or und Not gebildet:
True And True ergibt True.
True And False ergibt False.
False And True ergibt False.
False And False ergibt True.
Not True ergibt False.
Not False ergibt True.
Natürlich werden die Ausdrücke in der Regel nicht buchstäblich so gebildet wie
hier gezeigt. Statt der einzelnen Wahrheitswerte True und False werden Ausdrücke
übergeben, die diese Werte zurückgeben. Solche Ausdrücke ergeben sich aufgrund
von Vergleichen oder Rückgabewerten von Funktionen. Beispiele:
1 < iWert% AND 1000 > iWert% ermittelt, ob der Wert der Integer-Variablen iWert1 zwi-
schen 1 und 1000 liegt.
IsNumeric(vWert) ermittelt durch die Funktion IsNumeric, ob die Variant-Variable
vWert einen numerischen Wert enthält.
Auch die Ergebnisse von booleschen Ausdrücken lassen sich einer Variablen zuwei-
sen:
Dim bErgebnis As Boolean

bErgebnis = 1 < iWert% AND 1000 > iWert%

IBM SOFTWARE PRESS


48 Einführung in die LotusScript-Programmierung

Hinweis
Vor längerer Zeit gab es in LotusScript keinen eigenen Datentyp für Wahr-
heitswerte. Statt Boolean nahm man häufig Integer-Variablen.
In diesem Fall wurde die 0 als False gewertet und jeder andere Wert als True.
Intern wird nach wie vor False mit dem Wert 0 gleichgesetzt und True mit -1.
Sie werden wahrscheinlich noch auf das eine oder andere Script stoßen, in
dem Integer-Werte für Wahrheitswerte verwendet werden. Lassen Sie sich
dadurch nicht verwirren. Mit diesem Hintergrundwissen gewappnet, können
Sie mit diesen Werten praktisch genauso rechnen, als würden »echte« Wahr-
heitswerte vorliegen.

Vorrangregeln
Auch bei booleschen Ausdrücken gelten gewisse Vorrangregeln. So wird zunächst
die Negation Not berechnet, dann And und schließlich Or. Auch hier lassen sich die
Regeln durch Klammerungen umgehen.
Not False Or True ‘ergibt True Or True und das ist True
Not (False Or True) ‘ergibt Not True und das ist False

3.5 Eine eigene Prozedur schreiben


Nach dem Erfolg in Abschnitt 3.1, Das erste Programm, auf Seite 31, juckt es Sie
sicherlich in den Fingern, etwas mehr zu tun. Als ersten Schritt werden wir eine
eigene Prozedur schreiben und diese dann anschließend von der Prozedur Sub Ini-
tialize aufrufen (ausführen) lassen. Vorher sollten wir noch kurz klären, was eine
Prozedur eigentlich genau ist.

Prozedur
Prozeduren sind benannte Programmteile, die über ihren Namen zum Zwe-
cke der Ausführung einmal oder mehrmals aufgerufen werden können.

Praktisch gesehen bedeutet diese Definition, dass Sie einen (fast) x-beliebigen Code
nehmen und ihn in eine Prozedur packen können. Dadurch haben Sie die Möglich-
keit, diesen Code aus einem Programm auszulagern und ihn darin mit einem einzi-
gen Aufruf ausführen zu lassen. Dabei ist es egal, wie lang der Code in der Prozedur
ist. Auch Teile aus einer Prozedur können in weitere Prozeduren ausgelagert werden.
Sie werden dadurch sehr frei in der Gestaltung der Codestruktur. Sie sind gut bera-
ten, wenn Sie dies zu Ihrem eigenen Vorteil so nutzen, dass eine möglichst klare
Struktur entsteht, die die Logik der zugrunde liegenden Aufgabe gut abbildet.
Wir nehmen an, wir würden es für sinnvoll halten, einen Programmteil zu haben,
der bei seinem Aufruf die aktuelle Zeit ausgibt. Der aktuelle Agent ist der Agent, in
dem das gerade ablaufende Script enthalten ist, mithin unser Hello World-Agent.
Die zugehörige Prozedur könnte so aussehen:
Eine eigene Prozedur schreiben 49

Sub ShowTime
Messagebox "Wir schreiben den " & Date & ". Die Uhrzeit ist: " & Time
End Sub
Listing 3.2 Unsere selbst erstellte Prozedur

Dieses kleine Programm arbeitet mit sogenannten Objekten. Wenn Sie damit noch
keine Erfahrung haben, dann denken Sie im Moment noch nicht allzu viel darüber
nach. Ich komme gleich im Abschnitt 3.8, Mit (Notes)-Objekten arbeiten, darauf
zurück. Nehmen Sie den Code im Moment einfach so, wie er ist, und konzentrieren
Sie sich eher darauf, wie die Prozedur selbst (sozusagen die Klammer um diesen
Code) erstellt wird.

3.5.1 Die Prozedur anlegen


Die Prozedur wird durch direkte Eingabe in das Programmierfenster rechts vorge-
nommen. Dies können Sie an verschiedenen Orten tun.
Zum einen können Sie den Cursor in der Sub Initialize am Ende ganz rechts von
End Sub positionieren, mit [¢] einen Zeilenumbruch erzeugen und Sub ShowTime
hinschreiben (Abbildung 3.18).

Abbildung 3.18 Neue Prozedur durch direktes Hinschreiben erstellen

Anschließend geben Sie mit [¢] noch einen Zeilenumbruch ein. Dabei wird die
zugehörige Kennzeichnung des Endes (End Sub) vom LotusScript-Editor automa-
tisch angelegt und die so erstellte leere Prozedur in ein eigenes Fenster verfrachtet,
das Ihnen sofort angezeigt wird.
Gleichzeitig wird die Prozedur als neuer Programmierabschnitt im Baum links vom
Programmierfenster eingetragen. Wenn Sie die neue Prozedur in Zukunft öffnen
und bearbeiten wollen, wählen Sie einfach ihren Namen im Abschnittsbaum aus
(Abbildung 3.19).

Abbildung 3.19 Darstellung der neuen Prozedur ShowTime im Designer

Jetzt füllen wir die Prozedur ShowTime noch mit Inhalt, indem wir die noch fehlen-
den Zeilen LotusScript hineinschreiben. Dieser Teil wird auch allgemein als Rumpf
der Prozedur bezeichnet (Listing 3.3: Prozedurrumpf).

IBM SOFTWARE PRESS


50 Einführung in die LotusScript-Programmierung

Messagebox "Wir schreiben den " & Date & ". Die Uhrzeit ist: " & Time
Listing 3.3 Prozedurrumpf

3.5.2 Die Prozedur aufrufen


Nun können wir die Sache abschließen. Die Prozedur muss in der Sub Initialize
beim Start des Agenten aufgerufen werden. Die alte Messagebox-Anweisung benöti-
gen wir nun nicht mehr. Wir ersetzen sie also durch den Aufruf unserer eigenen
Prozedur (Listing 3.4).
Sub Initialize
Call ShowTime
End Sub
Listing 3.4 Aufruf der selbst erstellten Prozedur

Wie Sie sich schon denken können, ist Call die LotusScript-Anweisung, mit der Pro-
zeduren aufgerufen werden können.
Damit sind wir fertig. Der Agent kann gespeichert und geschlossen werden. Lassen
Sie ihn einmal ablaufen, damit Sie die Früchte unserer gemeinsamen Arbeit genie-
ßen können, bevor wir den Prozedurrumpf aus Listing 3.3 besprechen.

Abbildung 3.20 Die Meldung aus unserer selbst erstellten Prozedur

3.5.3 Funktionen
Prozeduren können Werte zurückgeben, die wie ein Ausdruck an Variablen zuge-
wiesen oder im Rahmen von Berechnungen weiter ausgewertet werden können.
Solche Prozeduren nennt man Funktionen. Sie werden mit dem Schlüsselwort
Function statt mit Sub angelegt.
Wir können die Prozedur ShowTime so umformulieren, dass sie den Text zurückgibt,
anstatt ihn anzuzeigen. Wir nennen die entstehende Funktion ihrer Arbeitsweise
gemäß GetTime:
Function GetTime As String
Dim strTimeText$

strTimeText = "Wir schreiben den " & Date & _


". Die Uhrzeit ist: " & Time

GetTime = strTimeText
End Function
Listing 3.5 Die zur Funktion mutierte Prozedur aus Listing 3.4
Eine eigene Prozedur schreiben 51

Hier fallen zwei Dinge auf. Erstens erhält der Funktionsname mit As String einen
Zusatz wie bei einer Variablendeklaration. Damit wird der Datentyp der Rückgabe
angegeben. Je nach Rückgabewert sind natürlich auch andere Deklarationen denk-
bar, wie Integer, Variant usw.
Zweitens sehen Sie in der letzten Zeile der Funktion, dass der berechnete Wert aus
strTimeText dem Namen der Funktion zugewiesen wird. Dadurch erfährt sie, wel-
chen Wert sie ausgeben soll.

Hinweis
Es gehört zum guten Programmierstil, diese Zuweisung erst zum Schluss zu
tätigen.
Natürlich könnte man bei dieser kurzen Berechnung statt der Variablen str-
TimeText gleich den Ausdruck zuweisen. Das wäre in diesem Fall in Ordnung,
da die Zuweisung auch dann ja am Ende erfolgen würde. Die vorgenommene
strikte Trennung ist aber am übersichtlichsten und soll Ihnen den Grundsatz
vor Augen führen.
Theoretisch kann man den Funktionsnamen sogar wie eine lokale Variable
behandeln und ihren Inhalt zwischendurch abfragen, verarbeiten und erneut
zuweisen. Davon ist aber auf jeden Fall abzuraten.

Möchten wir den Wert der Funktion von unserem Agenten ausgeben lassen, so
müssen wir den Aufruf ein wenig umschreiben. Denn wir müssen ja den Rückgabe-
wert »abholen« und dann zur Ausgabe bringen:
Sub Initialize
Messagebox GetTime
End Sub
Listing 3.6 Der Aufruf von GetTime

Wir können den Rückgabewert auch erst einer Variablen zuweisen und dann wei-
tere Berechnungen vornehmen:
Sub Initialize
Dim strTime$
Dim strPrefix$

strPrefix = {Der Agent sagt:

}
strTime = GetTime

Messagebox strPrefix & strTime


End Sub
Listing 3.7 Berechnung mit dem Rückgabewert von GetTime

IBM SOFTWARE PRESS


52 Einführung in die LotusScript-Programmierung

Wenn Sie die Erstellung des ersten Textteils (strPrefix) betrachten, wird Ihnen auf-
fallen, dass die Zeichenkette diesmal nicht von Anführungszeichen, sondern von
geschweiften Klammern umrandet ist und sich in die übernächste Zeile erstreckt.
Das hat den Grund, dass wir einen doppelten Zeilenumbruch für die Ausgabe
benötigen. Anstatt ihn mit den betriebssystemspezifischen Zeichen zu kodieren,
schreiben wir ihn einfach hin. Das geht aber nur mit geschweiften Klammern (oder
mit der noch verbleibenden Alternative, den senkrechten Strichen ||). Die Ausgabe
sehen Sie in Abbildung 3.21.

Abbildung 3.21 Anzeige des verarbeiteten Rückgabewertes der Funktion GetTime

3.5.4 Parameter und Programmverzweigungen


Allen Prozeduren können Parameter übergeben werden. Mit diesen steuern Sie das
Verhalten der Prozedur.

Parameter
Parameter sind Variablen, die im Prozedurkopf angegeben werden (also in der
Zeile, in der der Prozedurname steht). Parameter stehen innerhalb der Proze-
dur wie lokale Variablen zur Verfügung. Sie können abgefragt und bearbeitet
werden.

Wenn eine solche Prozedur aufgerufen wird, dann muss ihr für jeden Parameter ein
Wert mitgegeben werden.
Die Funktion GetTime gibt bislang nur deutsche Texte aus. Wenn wir in einem inter-
nationalen Umfeld arbeiten, dann benötigen wir wahrscheinlich auch eine eng-
lische Ausgabe. Um nicht für jede Sprachausgabe eine eigene Funktion schreiben
zu müssen, parametrisieren wir sie und übergeben ein Kürzel, das sie anweist, eine
deutsche oder eine englische Ausgabe zu generieren.
Function GetTime(in_strLanguage As String) As String
Dim strTimeText$

If in_strLanguage = “de” Then


strTimeText = "Wir schreiben den " & Date & _
". Die Uhrzeit ist: " & Time
Else
strTimeText = "Today it is the " & Date & _
". Current time: " & Time
End If
Eine eigene Prozedur schreiben 53

GetTime = strTimeText
End Function
Listing 3.8 Die parametrisierte Funktion zur Ausgabe von verschiedenen Sprachen

Sie sehen, dass Parameter fast wie Variablen deklariert werden. Sie werden hinter
dem Prozedurnamen als Liste aufgeführt und von runden Klammern umschlossen.
Die Liste wird durch Kommata getrennt. Da wir nur einen Parameter benötigen, ist
natürlich kein Komma zu sehen. Statt der Deklaration mit As String hätten wir
auch hier das Suffix $ verwenden können.

Hinweis
Dem Namen habe ich ein in_ vorangestellt. Das ist nicht zwingend, genauso
wie das Präfix str nicht zwingend ist, aber einen guten Programmierstil aus-
macht. Das Präfix in_ ist sehr praktisch, weil Sie dadurch besonders innerhalb
von längeren Prozeduren den Überblick darüber behalten, welche Werte als
Parameter »von außen geliefert wurden« und welche in lokalen Prozedurvari-
ablen vorliegen.

Im Funktionsrumpf wird der Parameter in_strLanguage von einer If...Then...


Else...End If-Konstruktion ausgewertet. Dieses stellt eine bedingte Verzweigungs-
anweisung dar. Wenn die Bedingung hinter If den Wahrheitswert True ergibt, dann
werden die unmittelbar folgenden Anweisungen bis zum Else abgearbeitet. Ergibt
die Bedingung False, dann wird der Else-Zweig benutzt. Danach wird die Verarbei-
tung nach der End If-Klausel fortgesetzt.
Der Parameter muss nun beim Aufruf durch die Sub Initialize-Prozedur mitge-
geben werden. Da wir nicht wissen, welche Sprache der Aufrufer spricht, überlas-
sen wir ihm die Auswahl. Dazu verwenden wir einen einfachen Eingabedialog, den
LotusScript mit InputBox zur Verfügung stellt.
Sub Initialize
Dim strTime$
Dim strPrefix$
Dim strLanguage$

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


auswahl", "de")

strPrefix = {Der Agent sagt:

}
strTime = GetTime(strLanguage)

Messagebox strPrefix & strTime


End Sub
Listing 3.9 Sprachabhängigkeit von GetTime durch Parametrisierung

IBM SOFTWARE PRESS


54 Einführung in die LotusScript-Programmierung

InputBox ist eine eingebaute Funktion der Sprache LotusScript. Auch sie wird durch
Parameter gesteuert. Die erste Zeichenkette teilt dem Benutzer mit, was von ihm
erwartet wird. Die zweite wird als Fenstertitel verwendet. Und die dritte (“de“) wird
als Vorgabe oder Vorschlag schon in die Eingabezeile geschrieben.
Wir haben die Bedingung in der Funktion GetTime so gewählt, dass bei der Übergabe
von “de“ die deutsche Version ausgegeben wird und bei allen anderen die eng-
lische. Das macht unsere Funktion fehlerfest, »robust«, wie man in der Program-
mierung sagt. Es wird also auch dann ein sinnvolles Ergebnis geliefert, wenn der
Benutzer irgendwelchen Unsinn übergibt oder eine Sprache, die die Funktion nicht
kennt.
Zur Programmierung von Verzweigungen gibt es noch andere Möglichkeiten, wie
es auch verschiedene Schleifen zum wiederholten Durchlaufen eines Codes gibt.
Mehr dazu finden Sie im Abschnitt 4.7, Ablaufsteuerung – Verzweigungen und Schlei-
fen, ab Seite 167.

3.6 Den Debugger verwenden


Der Debugger ist eine visuelle Hilfe, um Programme Schritt-für-Schritt ablaufen zu
lassen und den Fortgang der Berechnungen und die entstehenden Werte kontrol-
lieren zu können. Er hilft, Fehler (engl. Bugs) zu finden und zu eliminieren.

Debugger aktivieren
Um den Debugger zu nutzen, muss er vor dem Aufruf eines Agenten oder einer
Routine aktiviert werden, genauer gesagt: vor dem Laden des entsprechenden
Moduls. Bei einem Agenten geschieht das wie gesagt vor dessen Start; bei einer
Maske, einer Ansicht usw., passiert es, bevor dieses Element im Client geöffnet
wird.
Die Aktivierung erfolgt über WERKZEUGE/DEBUG LOTUSSCRIPT im Menü des Desig-
ners. Wenn links neben dem Menüpunkt ein Häkchen zu sehen ist, dann ist er akti-
viert. Alternativ kann er über ein SmartIcon in der Universal-Leiste aktiviert wer-
den.

Debugger starten
Sobald danach ein Modul geladen und eine seiner Routinen gestart wird, erscheint
das Debugger-Fenster. In Abbildung 3.22 sehen Sie das Fenster für den zuletzt
erstellten Agenten.
Den Debugger verwenden 55

Abbildung 3.22 Debugger nach dem Start eines Agenten

Das Programm wurde an der ersten ausgeführten Zeile angehalten (das geschieht
immer). Diese wird durch einen kleinen gelben Pfeil markiert. Er zeigt an, welche
Zeile als Nächstes ausgeführt werden wird.

Haltepunkte
Etwas weiter unten sehen Sie einen großen roten Punkt (im Buch ist er natürlich
schwarz). Dieser markiert einen Haltepunkt (engl. Breakpoint).
Sie haben jetzt die Wahl, das Programm einfach weiterlaufen zu lassen oder nur
gezielt den nächsten Schritt auszuführen. Der nächste Schritt würde mit der oben
befindlichen Schaltfläche SCHRITT AUSFÜHREN abgearbeitet. Das ist der Code, der
sich in der aktuellen Zeile befindet, an deren Beginn der Pfeil postiert ist. Danach
würde der Pfeil automatisch zur nächsten Zeile weiterrutschen. Manchmal ist es
notwendig, jeden Schritt zu verfolgen; dann wählt man diesen Weg.
Häufig gibt es aber nur eine gewisse Stelle, die näher untersucht werden soll. Dann
setzt man dort einen Haltepunkt und klickt FORTFAHREN an. Auf diese Weise wird
das Programm alle weiteren Schritte abarbeiten, bis es auf diesen oder einen ande-
ren Haltepunkt stößt. Mit FORTFAHREN würden wir in unserem Beispiel also bei dem
roten Punkt vor der Messagebox-Anweisung landen.
Um einen Haltepunkt zu setzen, bewegt man den blauen Balken (Cursor) auf die
entsprechende Zeile und klickt sie doppelt an oder drückt einmal [F9]. Möchte
man einen Haltepunkt entfernen, so wiederholt man das Ganze zweimal. Wieder-

IBM SOFTWARE PRESS


56 Einführung in die LotusScript-Programmierung

holt man es nur einmal, dann wird der Haltepunkt nur deaktiviert. In Abbildung
3.26 sehen Sie ein Beispiel dafür. Dieser ist zwar vermerkt, aber nicht aktiv, sodass
das Programm dort nicht halten wird. Dennoch können deaktivierte Haltepunkte
über das Fenster BREAKPOINTS angesteuert werden.
In Abbildung 3.22 sehen Sie im unteren Bereich vier Reiter für vier verschiedene
Anzeigen. Der obere Reiter ist mit BREAKPOINTS beschriftet. Somit sehen Sie hier die
gesetzten Haltepunkte. In unserem Beispiel ist es nur einer. Die Angaben sagen aus,
dass er in der Routine Initialize in der 13. Zeile gesetzt ist. Wenn Sie mehrere Hal-
tepunkte gesetzt haben und zu einem bestimmten »hinspringen« möchten, dann
wählen Sie einfach die BREAKPOINTS-Seite und klicken auf den entsprechenden Hal-
tepunkt. Dies bringt Sie an den gewünschten Ort.
Mit der Anweisung Stop kann man Haltepunkte auch kodieren. Sie haben den Vor-
teil, dass sie mit dem Code verbunden sind und mit Bedingungen verknüpft wer-
den können, beispielsweise so:
...
If strPrefix = “Blödsinn“ Then
Stop
End If
...
Stop-Anweisungen werden allerdings nicht als Haltepunkte auf der Seite BREAK-
POINTS aufgeführt.
Die Haltepunkte werden nur beachtet, wenn das Programm im Debug-Modus läuft.
Außerdem sind die im Designer gesetzten Haltepunkte an die bookmark.nsf des Ent-
wicklers gebunden (sie werden dort in einem Profildokument hinterlegt). Daher
brauchen sie für ein Produktivprogramm nicht entfernt zu werden. Allerdings wür-
de es keinen guten Eindruck machen, eine Reihe von Stop-Anweisungen zu hinter-
lassen, über die dann nachfolgende Entwickler »stolpern«. Sie sollten die Halte-
punkte vor der Auslieferung Ihres Programms beseitigen.

Inhalte von Variablen prüfen und verändern


Die zweite Seite im unteren Bereich mit der Aufschrift VARIABLEN gibt uns einen
Einblick in die Variablen und ihre Inhalte.
In Abbildung 3.23 sehen Sie die drei Variablen der Initialize-Prozedur. Links
erkennt man die Namen, ganz rechts die Datentypen und in der Mitte die Inhalte.
Man kann den Inhalt von Variablen ändern, sodass nachfolgende Zugriffe mit
angepassten Werten ausgeführt werden.
Den Debugger verwenden 57

Abbildung 3.23 Inhalte der Variablen prüfen und verändern

Als Beispiel führen wir eine Änderung an der Variablen strPrefix aus. Dazu wird die
Variable mit der Maus angeklickt, woraufhin ihr Wert im unteren Feld NEUER WERT
erscheint. Dort schreibt man den neuen Wert einfach hinein.
Möchte man die Änderungen übernehmen, klickt man rechts das grüne Häkchen
an. Sollen sie verworfen werden, klickt man auf das rote Kreuzchen oder geht ein-
fach ohne Bestätigung des Häkchens weiter (Abbildung 3.24).

Abbildung 3.24 Den Wert einer Variablen ändern

Hier wird der Text “Der Agent sagt: “ umgeändert in “Das Programm sagt: “.
Genauso geht man bei Zahlen, Datumswerten, Array-Elementen, Listen-Elementen
und entsprechenden Eigenschaften von Objekten vor.
Manche Eigenschaften von Objekten lassen sich nicht ändern. Dies sind dann
Eigenschaften, die auch in Programmen nur gelesen werden können.

IBM SOFTWARE PRESS


58 Einführung in die LotusScript-Programmierung

Ausgabe überwachen
Mit Print getätigte Ausgaben werden im Fenster AUSGABE angezeigt. Im “Hello World“-
Agent wurde dazu noch eine Zeile eingefügt, die einen Text ausgibt (Abbildung 3.25).

Abbildung 3.25 Print schreibt ins AUSGABE-Fenster.

Aufrufe verfolgen und zum Navigieren verwenden


Während weitere Unterroutinen aufgerufen werden, wird der Aufrufstapel verfolgt
und im Fenster AUFRUFE angezeigt (Abbildung 3.26).

Abbildung 3.26 Aufrufstapel verfolgen

Hier sehen Sie einerseits, welche Aufrufe hintereinander getätigt wurden, um an


die momentane Stelle zu gelangen.
Andererseits können Sie durch Anklicken gezielt in eine der »Zwischenstationen«
gelangen. Dabei kommen Sie nicht nur zu der entsprechenden Routine, sondern
sehen im Fenster VARIABLEN auch die dazugehörenden Variablen mit deren aktuel-
len Werten.
Eingebaute Funktionen 59

In unserem Beispiel bin ich in der zuletzt aufgerufenen Unterfunktion GetTime


geblieben. Auf dem Stapel wird sie daher als oberste angezeigt (Abbildung 3.26).
Übrigens sehen Sie auch einen deaktivierten Haltepunkt. Dieser ist zwar vermerkt,
aber nicht aktiv, sodass das Programm dort nicht halten wird. Dennoch können
deaktivierte Haltepunkte über das Fenster BREAKPOINTS angesteuert werden.

Die übrigen Schaltflächen


Die Schaltfläche SCHRITT ÜBERSPRINGEN wird verwendet, wenn man den Aufruf einer
Funktion oder Prozedur überspringen möchte, ohne den darin befindlichen Code
zu analysieren.
Die Schaltfläche SCHRITT BEENDEN wird verwendet, wenn man den Aufruf einer
Funktion oder Prozedur beenden möchte, ohne den darin befindlichen Code noch
weiter zu analysieren. Hier ist man also schon hineingesprungen und möchte
schnellstmöglich wieder heraus.
Mit der Schaltfläche STOPPEN wird das Script an sich abgebrochen. In diesem Fall
möchte man also nicht, dass das Programm weiter ausgeführt wird.
Die Schaltfläche DEBUGGER SCHLIESSEN bricht das Programm ebenfalls ab. Sie deak-
tiviert aber gleichzeitig den Debugger, sodass folgende Programmaufrufe wieder
normal ausgeführt werden.

Navigation zwischen den Modulen und Routinen


Unterhalb der Schaltflächen finden Sie noch die Comboboxen OBJEKT und EREIG-
NIS. Mit diesen können Sie zwischen Modulen, deren Abschnitten und Ereignis-
handlern und anderen Routinen hin- und hernavigieren, ohne dass sie aufgerufen
worden sein müssen. Darin unterscheidet sich diese Navigiermöglichkeit vom Auf-
rufstapel.

3.7 Eingebaute Funktionen


Nun haben wir schon viel über Prozeduren im Allgemeinen und über Funktionen
im Speziellen gesprochen. Diese waren an einen Agenten, also ein Notes-Element
gebunden. Gleichzeitig haben wir aber auch, ohne groß darüber nachzudenken,
Funktionen verwendet, die in LotusScript fest eingebaut sind: MessageBox, Date, Time,
InputBox.
Die Sprache bietet viele solche Funktionen, die die unterschiedlichsten Dinge tun.
In Kapitel 4, Sprachbefehle – nach Themen, (ab Seite 89) werden sie nach Themen
getrennt im Einzelnen besprochen, sodass Sie je nach Anforderung schnell die
richtigen Befehle finden werden.
Anders als bei den selbst erstellten Prozeduren sind bei vielen LotusScript-Funktio-
nen verschiedene Parameter optional. Das heißt, sie können, müssen aber nicht
angegeben werden. Werden sie weggelassen, so setzt LotusScript selbst einen Wert
ein, den sogenannten Vorgabewert.

IBM SOFTWARE PRESS


60 Einführung in die LotusScript-Programmierung

Folgt auf ausgelassene Parameter kein Parameter mehr, den Sie angeben möchten,
so können Sie diese komplett inklusive Kommata weglassen. Folgt aber noch eine
Wertangabe, so müssen die ausgelassenen Stellen dazwischen fast immer durch
Kommata markiert werden. Nur so kann LotusScript erkennen, welchen Parameter
Sie spezifizieren wollten und welche auszulassen sind.
Beispielsweise kann MessageBox bis zu drei Parameter verarbeiten: Anzeigetext,
Optionen und Titel. Wenn Sie nur einen Text anzeigen möchten, dann genügt fol-
gender Aufruf:
MessageBox “Dieser Text soll angezeigt werden“
Möchten Sie auch einen Titel angeben, aber keine Optionen, dann sieht der Aufruf
so aus:
MessageBox “Dieser Text soll angezeigt werden“, , “Dies ist der Titel“

3.7.1 Zwei Rückgabearten – Variant und String


Viele eingebaute Funktionen existieren in zwei Varianten, deren Namen sich durch
ein $-Suffix unterscheiden, zum Beispiel: Date und Date$. Der Unterschied ist, dass
die Funktionen ohne Suffix das Ergebnis als Variant zurückgeben, während die mit
Suffix einen String ausgeben.
In der praktischen Arbeit werden Sie den Unterschied kaum merken. Daher findet
man auch nur selten LotusScript-Code, in dem die Funktionen mit Suffix notiert
werden.
Dementsprechend habe ich auch in diesem Buch darauf verzichtet, jedes Mal beide
Versionen zu erwähnen. Sollten Sie trotzdem unbedingt einen String als Rückgabe-
wert benötigen und nicht CStr für eine Typumwandlung einsetzen wollen, so fin-
den Sie in der Designer-Hilfe schnell die Information, ob es für eine bestimmte
Funktion die Suffix-Version gibt.

3.8 Mit (Notes-)Objekten arbeiten


Bis jetzt haben wir noch nicht allzu viel Berührung mit Notes-Objekten gehabt.
Das einzige war, dass wir einen Agenten als Container für unsere LotusScript-Pro-
gramme genutzt haben. Ansonsten haben wir uns mit der Sprache LotusScript an
sich beschäftigt. Da war noch keine Gelegenheit, sich mit der Notes/Domino-
Umgebung zu beschäftigen.
Im Prinzip sind dies zwei unterschiedliche Dinge. LotusScript ist eine Program-
miersprache, die unabhängig von Notes existiert. Sie wird auch von anderen IBM
Lotus-Produkten verwendet (zum Beispiel WordPro).
Notes/Domino ist ein Produkt, in das auch LotusScript eingebaut wurde, um des-
sen Elemente mit dieser Sprache programmieren zu können. Diese Verbindung
wird durch die sogenannten Notes-Klassen oder Notes-Objekte hergestellt. Prak-
tisch gesehen, sind das Programmteile, die in LotusScript zusätzlich zur eigent-
lichen Sprache zur Verfügung stehen.
Mit (Notes-)Objekten arbeiten 61

Bevor wir etwas mehr über Klassen und Objekte auch im allgemeinen Sinne spre-
chen, möchte ich Ihnen zunächst kurz die praktische Arbeit damit vorstellen. So
bekommen Sie am schnellsten eine Vorstellung davon, was Klassen und Objekte
für Sie als LotusScript-Programmierer bedeuten.

3.8.1 Daten aus der aktuellen Notes-Sitzung abfragen (Teil 1)


Eine zentrale Klasse für die Arbeit mit Notes/Domino ist NotesSession. Mit ihr erhal-
ten wir Zugang zur aktuellen Notes-Sitzung. Man erfährt von ihr, wie der aktuelle
Benutzer heißt (also die Notes-ID, mit der Ihr Programm läuft), in welcher Daten-
bank sich Ihr Script befindet, ob es auf dem Server oder dem Client läuft usw. Als
kleine Demonstration soll das folgende Programm dienen, das uns verrät, wie der
Agent heißt, in dem unser Script läuft:
Sub Initialize
Dim session As New NotesSession
Dim agentThis As NotesAgent
Dim strAgentName As String

Set agentThis = session.CurrentAgent


strAgentName = agentThis.Name

Messagebox "Der Name dieses Agenten lautet: " & strAgentName


End Sub
Listing 3.10 Unsere erste Arbeit mit Notes-Objekten

Die erste Anweisung lautet Dim session As New NotesSession und legt ein NotesSes-
sion-Objekt an. Mit Set agentThis = session.CurrentAgent bekommen wir Zugriff auf
den Agenten, in dem das Script läuft, also auf »unseren« Agenten. Sein Name wird
mit agentThis.Name ermittelt und anschließend über die Messagebox ausgegeben.
Sie werden gesehen haben, dass drei neue Dinge aufgetaucht sind: die Anweisung
New innerhalb der Variablendeklaration der ersten Zeile, dann das Schlüsselwort Set
bei der ersten Zuweisung sowie der Punktoperator zwischen session und Current-
Agent bzw. agentThis und Name. Zudem fallen noch die neuen »Datentypen« NotesSes-
sion und NotesAgent in den Deklarationszeilen auf.
Bevor wir die Angelegenheit Stück für Stück durchgehen, benötigen wir noch etwas
Theorie.

3.8.2 Etwas Theorie – Objekte, Methoden und Eigenschaften

Objekt
Objekte sind benannte Programmteile, die sich ein wenig wie die Gegenstän-
de in der realen Welt verhalten. Sie verfügen über eigene Daten (die Eigen-
schaften), die sie unabhängig von anderen Objekten verwalten. Sie haben
Prozeduren (die Methoden), die ihre Aktionsmöglichkeiten ausmachen.

IBM SOFTWARE PRESS


62 Einführung in die LotusScript-Programmierung

Wenn Sie diese Definition mit der Definition der Prozedur auf Seite 48 vergleichen,
dann werden Sie feststellen, dass sich die Definitionen ein wenig ähneln. Auch
Objekte bieten also die Möglichkeit, eine bestimmte Menge Code auszulagern und
diese bei Bedarf einfach über den Objektnamen aufzurufen. Dieser Code wird
innerhalb der Klasse wie eine Prozedur formuliert und wird fast genauso mit Call
aufgerufen. Solche Objekt-»Prozeduren« nennt man Methoden.
Darüber hinaus haben Objekte im Allgemeinen sogenannte Eigenschaften. Das sind
vereinfacht gesagt Variablen, die diverse für das Objekt relevante Daten speichern
und ausgeben können. Eigenschaften werden häufig von Methoden bearbeitet,
geändert und ausgegeben. Bei einem streng objektorientierten Design legt man
sogar Wert darauf, dass auf Eigenschaften nur in Ausnahmefällen direkt zugegrif-
fen weden kann.
Man könnte auch sagen, dass Objekte eine Zusammenfassung von verschiedenen
Prozeduren mit gemeinsamen Daten darstellen.

Klasse
Eine Klasse ist eine Art Schablone, mit der Objekte beschrieben und erstellt
werden können.

Beim Programmieren wird zunächst eine Klasse deklariert. Wenn man mit ihr
arbeiten möchte, erzeugt man ein Objekt (mit New). Die in LotusScript eingebauten
Notes-Klassen braucht man natürlich nicht mehr zu deklarieren.
Objekte sind genaue Abbilder ihrer Klasse. Allerdings ist die Klasse nur die »Bauvor-
schrift«. Eine Klasse kann in einem Programm nur einmal existieren. Davon abge-
leitete Objekte kann man so viele erstellen, wie man möchte bzw. wie der Arbeits-
speicher hergibt. Die Objekte sind unabhängig voneinander. Insbesondere ihre
Eigenschaften sind eine »Privatangelegenheit«, in die sich kein anderes Objekt ein-
mischen sollte. Diesen letzten Punkt kann man zwar durch schlechte Konzeption
und Programmierung umgehen. Man sollte es aber nicht tun, da die Unabhängig-
keit der Objekte voneinander ein wichtiges Merkmal des objektorientierten
Designs (OOD) darstellt.
Diese eher anschauliche Definition wird nicht jeder wissenschaftlichen Betrach-
tungsweise standhalten. Aber wir betreiben hier ja auch keine wissenschaftlichen
Forschungen, sondern möchten mit den Objekten arbeiten.
Verlassen wir also die Theorie wieder, und wir wenden uns unserem Beispiel zu.

3.8.3 Daten aus der aktuellen Notes-Sitzung abfragen (Teil 2)


Ohne jetzt weiter auf Details einzugehen, stellen wir fest, dass man Objekte offen-
sichtlich mit der Syntax
Dim ObjektVariable As New KlassenName
Mit (Notes-)Objekten arbeiten 63

erzeugen kann. Sobald diese Anweisung abgearbeitet wurde, existiert das Objekt
und kann im Programmcode verwendet werden.
Der Klassenname ist die Bezeichnung für die Art des Objekts. In unserem Beispiel
haben wir ein Objekt von der Art NotesSession erzeugt.
Damit haben wir ein Objekt, das uns nützliche Auskünfte zur momentanen Notes-
Sitzung geben kann. Beispielsweise »weiß« das Objekt, wer der gerade geöffnete
Agent ist. Was es nicht weiß, ist, wie dieser Agent heißt. Das weiß er aber natürlich
selbst.
Deswegen haben wir das session-Objekt erst einmal nach dem geöffneten Agenten
»befragt«. Dazu wird die Eigenschaft CurrentAgent mit dem »Punktoperator« ange-
sprochen (englisch Dot), wobei das Objekt wie eine Variable mit dem Variablen-
namen notiert wird:
session.CurrentAgent

Hinweis
Dazu muss man sagen, dass der Objektname in der Tat der Name einer Vari-
ablen ist. Denn beim Erzeugen mit Dim...As New... wurde zunächst eine Vari-
able mit dem Objektnamen angelegt (hier session), dann wurde das Objekt
erzeugt und im Programmspeicher abgelegt, und anschließend wurde die
Adresse des Objekts in der Variablen abgelegt.
Da wir für die Variable den Datentyp einer Klasse bestimmt haben (NotesSes-
sion), weiß LotusScript, dass es hier nicht einfach den Inhalt, nämlich die
Objektadresse, ausgeben soll. Stattdessen sucht es automatisch das Objekt an
der angegebenen Adresse und wertet dieses aus. Dass hier im Hintergrund
Speicheradressen eine Rolle spielen, brauchen Sie als LotusScript-Entwickler
im Prinzip nicht zu wissen. Es wird Ihnen aber verständlicher machen,
warum eine Objektzuweisung ein vorangestelltes Set benötigt, während
andere Variablenwerte ohne Set zugewiesen werden.

In der Eigenschaft CurrentAgent befindet sich ein NotesAgent-Objekt des gerade lau-
fenden Agenten, also »unseres« Agenten. Das Objekt wurde bereits intern von
NotesSession erzeugt. Deshalb können wir es wie gezeigt einfach mit dem Punktope-
rator abfragen und benötigen keine zweite New-Anweisung.
Wir weisen das Objekt einer Objektvariablen vom Typ NotesAgent zu. Wie schon
gesagt, muss eine Objektzuweisung immer durch ein vorangestelltes Set kenntlich
gemacht werden:
Set agentThis = session.CurrentAgent
Allerdings interessiert uns dieser Agent selbst nicht so sehr, sondern sein Name.
Den erfährt man mit:
strAgentName = agent.Name

IBM SOFTWARE PRESS


64 Einführung in die LotusScript-Programmierung

Diese Eigenschaft von NotesAgent gibt eine Zeichenkette aus, also einen String-Wert.
Daher können wir sie einfach einer String-Variablen zuweisen (natürlich ohne Set,
das ja nur zur Zuweisung von Objektreferenzen verwendet wird).
Und den Rest kennen Sie ja bereits.
In Verbindung mit NotesSession hatten wir also gesehen, wie Objekt-Eigenschaften
gelesen werden. Im folgenden Abschnitt werden wir eine Objekt-Methode verwen-
den.

3.8.4 Eine Methode des Arbeitsbereichs aufrufen


Eine andere zentrale Notes-Klasse ist NotesUIWorkspace. Das »UI« im Namen deutet
darauf hin, dass diese Klasse mit dem User Interface zu tun hat (also mit der Benut-
zerschnittstelle – das sind die Dinge, die man auf dem Bildschirm sieht).
Mit dieser Klasse erhält man Zugriff auf die im UI geöffneten Elemente, z. B. ein
Dokument, eine geöffnete Ansicht usw. Man kann mit ihr Dialogboxen anzeigen
und Masken zur Erstellung von neuen Dokumenten öffnen. Vorhandene Doku-
mente können zur Bearbeitung angezeigt werden usw.

Hinweis
Da wir gerade über Dialogboxen sprachen: Sie werden bemerkt haben, dass es
offensichtlich »an zwei Stellen« Dialogboxen gibt, denn wir hatten ja schon
die LotusScript-Funktionen MessageBox und InputBox als solche kennengelernt.
Hier zeigt sich wieder die Zweiteilung: einerseits die Sprache LotusScript –
andererseits die von Notes/Domino zusätzlich zur Verfügung gestellten Klas-
sen, deren Methoden sich hier und da ein wenig mit LotusScript-Funktionen
überschneiden.
Das ist insbesondere bei den Dialogboxen, der Arbeit mit Dateien und bei
OLE-Objekten der Fall. Bei der Arbeit mit den Klassen werden Sie feststellen,
dass deren Angebote meistens über die Möglichkeiten von LotusScript hin-
ausreichen bzw. anderen Anforderungen genügen. Es hat also beides seine
Berechtigung.

Um zu zeigen, wie Objekt-Methoden verwendet werden, erstellen wir als Beispiel


mit NotesUIWorkspace.ComposeDocument ein neues Dokument. Mit dieser Methode kön-
nen Sie in irgendeiner zugänglichen Datenbank (auf der Sie Schreibrechte haben)
ein Dokument mit einer der dafür vorgesehenen Masken erstellen.
Da ich nicht weiß, welche Datenbanken in Ihrer Umgebung zu finden sind, neh-
men wir einfach Ihre Mail-Datei, die ziemlich sicher existieren wird, und erstellen
darin ein neues Memo. Nun weiß ich auch nicht, wie Ihre Mail-Datei heißt. Das
können wir aber mit NotesDatabase in Erfahrung bringen. Der Code wird wieder in
einen Agenten wie dem “Hello World“-Agenten geschrieben:
Mit (Notes-)Objekten arbeiten 65

Sub Initialize
Dim dbMail As New NotesDatabase("", "")
Dim ws As New NotesUIWorkspace

'Mail-Datei öffnen, um Server und Pfad ermitteln zu können


Call dbMail.OpenMail()

'Memo-Maske aus Mail-Datei für eine neue Mail öffnen


Call ws.ComposeDocument(dbMail.Server, dbMail.FilePath, "Memo")
End Sub
Listing 3.11 Programm zur Erstellung einer neuen Mail

Sie sehen, das Programm ist sehr kurz, und es wird praktisch nur mit Notes-Objek-
ten gearbeitet.
Als Erstes benötigen wir wieder ein NotesDatabase-Objekt. Dies steht für Datenban-
ken im Hintergrund, also für den nicht sichtbaren Teil. Wir möchten gern erfah-
ren, wo sich die Mail-Datei des Benutzers befindet (also Ihre Mail-Datei, wenn Sie
das Script laufen lassen). Dazu bietet uns die Klasse NotesDatabase die Methode Open-
Mail an. Der Aufruf öffnet die Datenbank nur im Hintergrund, es wird (noch) kein
Fenster sichtbar. Wir nehmen als sicher an, dass Sie eine Mail-Datei besitzen, dass
alles richtig konfiguriert ist und dass Sie Zugriff auf die Datenbank haben. Dann
werden in dem dbMail-Objekt nach dem Aufruf von OpenMail der Server und der
Dateipfad (FilePath) vermerkt sein. Diese Angaben übergeben wir als die ersten bei-
den notwendigen Parameter an ComposeDocument. Diese Methode soll auch noch wis-
sen, welche Maske sie für das neue Dokument verwenden soll, und wir geben
»Memo« an. Nach ihrem Aufruf wird ein Fenster mit der Mail-Maske (»Memo«)
sichtbar.
Jetzt können Sie die neue Mail am Bildschirm wie jede andere füllen und absenden.
In diesem Script wurde zweimal eine Objekt-Methode aufgerufen: mit NotesData-
base.OpenMail eine parameterlose und mit NotesUIWorkspace.ComposeDocument eine
andere mit Parametern.
Der Aufruf ist sehr ähnlich wie bei den Prozeduren, die Sie früher kennengelernt
haben, und erfolgte mit Call.

Hinweis
Call kann bei allen Arten von Prozeduraufrufen auch weggelassen werden.
Genauso können die runden Klammern weggelassen werden, wenn keine
Parameter übergeben werden. Aus Call dbMail.OpenMail() würde dann:
dbMail.OpenMail
Das sieht aber fast wie die Abfrage einer Eigenschaft aus, und deshalb ver-
wende ich bei solchen Aufrufen immer Call und setze dann in der Regel auch
die Klammern. Andere entscheiden sich für die kürzere Variante. Das ist eine
reine Geschmackssache.

IBM SOFTWARE PRESS


66 Einführung in die LotusScript-Programmierung

Der Unterschied ist nur, dass wie bei den Eigenschaften der Name der Objekt-
variablen davor gesetzt und mit dem Punktoperator verbunden werden muss.
Wenn eine Methode einen Rückgabewert hat, kann die Zuweisung zu einer Variab-
len analog zu der Vorgehensweise bei Funktionen erfolgen. Häufig geben die
Methoden Objekte zurück, die dann mit Set zugewiesen werden müssen. Unsere
ComposeDocument-Methode gibt ein NotesUIDocument-Objekt zurück, das man für wei-
tere Bearbeitungen nutzen kann. Die Zuweisung könnte so erfolgen:
...
Dim uidoc As NotesUIDocument
...

Set uidoc = ws.ComposeDocument(dbMail.Server, dbMail.FilePath, "Memo")


...
Listing 3.12 Hier wird das erstellte Dokument zur weiteren Bearbeitung als NotesUIDocument-Objekt
übernommen.

3.8.5 Eigenschaften ändern


Eigenschaften kann man nicht nur abfragen, sie können in manchen Fällen auch
geändert werden.
So können wir zum Beispiel das in Listing 3.12 ergriffene NotesUIDocument verwen-
den, um sicherzustellen, dass das horizontale Lineal angezeigt wird:
uidoc.Ruler = True

Nicht änderbare Eigenschaften


Es gibt natürlich auch viele Eigenschaften, bei denen eine Änderung nicht sinnvoll
wäre.
Zum Beispiel gibt NotesUIDocument.IsNewDoc an, ob das Dokument noch neu ist oder
schon einmal gespeichert wurde. Wenn unser Programm die Eigenschaft später
nach dem ersten Speichern einfach von True auf False setzen könnte, dann würde
sie anschließend offensichtlichen Unsinn enthalten.
Daher sind viele Eigenschaften gegen Änderungen gesperrt. Die Klassenreferenz
gibt Auskunft darüber, welche Eigenschaften änderbar sind und welche nicht.

3.9 Weitere Startpunkte für LotusScript-Programme


Bis jetzt haben wir nur Agenten programmiert. Um Ihnen eine Richtung aufzuzei-
gen, wie Sie Scripts einsetzen können, folgen jetzt ein paar exemplarische Hin-
weise. Weitere Möglichkeiten finden Sie bei den einschlägigen Themen weiter hin-
ten im Buch und in den Beschreibungen der Events (Ereignisse) der UI-Klassen.
Wenn ich jetzt ein paar Eventhandler explizit erwähne, dann sind diese nur ein
kleiner Auszug aus der Liste der programmierbaren Events.
Weitere Startpunkte für LotusScript-Programme 67

3.9.1 Aktionsschaltflächen
Wenn Sie auf einer Maske, einer Seite oder in einer Aktionsleiste eine Schaltfläche
einbauen, dann kann diese anschließend ähnlich wie ein Agent programmiert wer-
den. Wenn sich der Fokus auf der Schaltfläche befindet, zeigt sich das Program-
mierfenster unten ähnlich wie bei dem Agenten. Auch müssen wir zunächst die
Sprache LotusScript auswählen (vorher wird eine Formel angezeigt) und sehen
dann die einzelnen Eventhandler. Bei Schaltflächen gibt es außer den schon
bekannten Sub Initialize und Sub Terminate noch Sub Click und Sub ObjectExecute.
Soll der Button das Programm auf einen Klick hin ausführen, dann ist Sub Click die
richtige Wahl. (Sub Initialize würde beim Laden der Maske und dem damit ver-
bunden Initialisieren der Schaltfläche aufgerufen, was selten das ist, was wir benö-
tigen).

3.9.2 Masken, Teilmasken und Seiten


Masken weisen eine Fülle von Eventhandlern auf. Seiten haben einige Eventhand-
ler weniger, weil Seiten nicht gespeichert werden können; sie sind nicht mit einem
Dokument verbunden. Auch Teilmasken verfügen über ähnliche Eventhandler wie
Masken.
Wenn Sie für bestimmte Fälle verhindern möchten, dass ein Dokument gespeichert
wird, können Sie die Sub QuerySave-Routine bearbeiten. Sie können darin eine
Prüfung vornehmen und für den Fall, dass sie negativ ausfällt, den Parameter Con-
tinue = False setzen. Dann wird die Maske die Speicherung nicht ausführen.
Sollen in der Maske direkt nach dem Öffnen gewisse Aktionen durchgeführt wer-
den (noch bevor der Benutzer eingreifen kann), so können Sie Sub PostOpen verwen-
den.
Durch eine Maske können Sie auf die dahinterliegenden Hintergrunddokumente
zugreifen (NotesUIDocument.Document) und sie ändern, oder Sie geben bestimmte Texte
mit NotesUIDocument direkt in der Maske ein.
Im folgenden Beispiel greifen wir im PostOpen-Eventhandler auf das Hintergrund-
dokument zu und geben dessen Universal-ID aus:
Sub Postopen(Source As Notesuidocument)
Dim docThis As NotesDocument
Set docThis = Source.Document

Print docThis.UniversalID
End Sub
Listing 3.13 Zugriff auf das Hintergrunddokument

Wird ein Agent bei geöffneter Maske aufgerufen, so startet man mit einem Notes-
UIWorkspace-Objekt, mit dem man als CurrentDocument auf das Vordergrunddokument
Zugriff erlangt und anschließend auf das Hintergrunddokument:

IBM SOFTWARE PRESS


68 Einführung in die LotusScript-Programmierung

Sub Initialize
Dim ws As NotesUIWorkspace
Dim docThis As NotesDocument

Set docThis = ws.CurrentDocument.Document

Print docThis.UniversalID
End Sub
Listing 3.14 Zugriff auf das Hintergrunddokument der geöffneten Maske über das NotesUIWork-
space-Objekt

3.9.3 Ansichten und Ordner


Ansichten können Sie in zweierlei Hinsicht programmieren. Zum einen können Sie
auch hier Eventhandler mit Programmen füllen, die ausgeführt werden, wenn eine
Ansicht geöffnet oder geschlossen wird, wenn Dokumente ausgewählt und geöff-
net werden usw.
Zum anderen kann auch die Gestaltung von Ansichten mit LotusScript verändert
werden. Dazu halten die NotesView-Klassen eine Reihe von Möglichkeiten bereit.
Außerdem können Ansichten zum Durchlaufen ihrer Inhalte und zum Suchen
darin verwendet werden.
Die Startpunkte für die letztgenannten Aktionen können wiederum in irgend-
einem passenden Eventhandler liegen (in einer Schaltfläche: Sub Click, in einem
Agenten: Sub Initialize usw.).

3.9.4 Datenbanken
Auf das Öffnen und Schließen einer Datenbank kann mit Eventhandlern im soge-
nannten DATENBANK-SCRIPT in den DATENBANKRESSOURCEN aus dem Abschnitt ANDERE
reagiert werden. Was man vielleicht weniger vermuten würde, ist, dass hier auch
Eventhandler für die Behandlung von Drag&Drop-Operationen verborgen sind.

3.9.5 Gliederungen
Gliederungen können mit den Klassen NotesOutline und NotesOutlineEntry bearbei-
tet werden. Sie können Einträge hinzufügen, entfernen und ihre Ziele verändern.
Die Startpunkte für diese Aktionen können in irgendeinem passenden Eventhand-
ler liegen (in einer Schaltfläche: Sub Click, in einem Agenten: Sub Initialize usw.).

3.10 Bibliotheken erstellen und einbinden


Um große Mengen von LotusScript-Code sinnvoll zu strukturieren, bietet es sich
an, sie in Bibliotheken auszulagern.
Sie finden die vorhandenen Bibliotheken unter GEMEINSAMER CODE/SCRIPTBIB-
LIOTHEKEN. Dort können neue Bibliotheken mit der Aktion NEUE LOTUSSCRIPT BIB-
Bibliotheken erstellen und einbinden 69

LIOTHEK angelegt werden. Geben Sie ihnen sprechende Namen, die die darin abge-
legten Programmteile charakterisieren. Dann ist es später leichter, die darin
befindlichen Codestücke zu finden.
Wenn eine Bibliothek neu angelegt wird, präsentiert sie sich zunächst wie ein noch
leerer Agent (Abbildung 3.27).

Abbildung 3.27 Neu angelegte LotusScript-Bibliothek

Zunächst trägt sie den Namen “(unbenannt)“, was man in den Eigenschaften ändert.
Spätestens beim Abspeichern wird man dazu aufgefordert.
Nun wird der auszulagernde Code hier genauso abgelegt wie in anderen Modulen
auch. Nur werden Sie in der Regel die beiden Routinen Sub Initialize und Sub Ter-
minate unberührt lassen. Die erste kommt nur in Betracht, wenn Sie möchten, dass
beim Laden der Bibliothek gewisse Werte voreingestellt werden, beispielsweise glo-
bale Variablen (die Sie als guter Programmierer hoffentlich nur in Ausnahmefällen
verwenden werden). Sub Terminate kann zum Aufräumen beim Entladen der Biblio-
thek verwendet werden können.
Bibliotheken werden mit der Anweisung
Use strLibraryName$
eingebunden. Diese muss im (Options)-Abschnitt eines anderen Moduls, also eines
Agenten, einer Maske oder einer Ansicht usw. aufgeführt werden. Wenn dieses
andere Modul geladen wird, dann wird die Bibliothek automatisch mitgeladen.
Wird das andere Modul entladen, dann wird auch die Bibliothek entladen.
Es können mehrere Use-Anweisungen untereinander geschrieben werden. Außer-
dem können Ketten gebildet werden, indem eine Bibliothek eine weitere angibt,
die von ihr selbst geladen wird, usw.

Hinweis
Die Auflösung der verketteten Inhalte ist in der Vergangenheit nicht immer
zuverlässig gewesen. Dies hat sich insbesondere in mysteriösen Fehlern von
Hintergrundagenten bemerkbar gemacht. Deshalb verzichte ich auch heute
noch auf eine Verkettung bzw. führe die verketteten Bibliotheken im ausfüh-
renden Modul (zum Beispiel einem Agenten) lückenlos auf. So kann man
sicher sein, dass der LotusScript-Interpreter alle findet.

IBM SOFTWARE PRESS


70 Einführung in die LotusScript-Programmierung

Anschließend kann der (öffentliche) Code aus der Bibliothek wie jeder andere ver-
wendet werden. Das heißt, Prozeduren, Funktionen, Klassendefinitionen und
benutzerdefinierte Datentypen können verwendet werden, als wären sie in demsel-
ben Modul geschrieben worden. Es muss nur darauf geachtet werden, dass ein zu
verwendendes Element nicht als Private deklariert wurde.

3.11 Eigene zusammengesetzte Datentypen erstellen


Die Anweisung Type bietet die Möglichkeit, eigene Datentypen zu erstellen. Dies
beschränkt sich allerdings auf die Zusammensetzung anderer vorhandener Daten-
typen. Sie können nicht wie in C++ das Verhalten der erstellten Datentypen steu-
ern. Das ist in der praktischen Arbeit mit LotusScript auch selten erforderlich. Und
wenn, dann kann man sich mit der Erstellung eigener Klassen behelfen.
Um einen zusammengesetzten Typ zu erstellen, schreibt man die Anweisung Type
in Verbindung mit dem gewünschten Namen des Typs hin. Anschließend notiert
man eine Liste von Elementen, die in dem Typ enthalten sollen. Diese werden wie
Variablen ohne Dim oder Ähnliches notiert. Zum Schluss wird die Deklaration mit
End Type abgeschlossen. Ein Beispiel:
Type Person
Vorname As String
Nachname As String
Geburtsjahr As Integer
Ort As String
End Type
Diese Deklaration muss in den Abschnitt (Declarations) geschrieben werden.
Eine Variable dieses Typs kann man dann im laufenden Code deklarieren wie jede
andere auch. Allerdings muss man bei Zuweisungen und Auswertungen angeben,
welche Elemente man ansprechen möchte. Dazu wird wie beim Ansprechen von
Objekt-Eigenschaften und -Methoden der Punktoperator verwendet.
Als Beispiel sehen Sie eine kleine Prozedur, die die Angaben als Parameter über-
nimmt und einer Variablen vom Typ Person zuweist. Anschließend werden die
Daten ausgegeben:
Sub FillPersonRecord(in_strFirstName$, in_strLastName$, in_strCity$,
in_iYearOfBirth%)
Dim tPerson As Person

tPerson.Geburtsjahr = in_iYearOfBirth%
tPerson.Nachname = in_strLastName
tPerson.Vorname = in_strFirstName
tPerson.Ort = in_strCity

Print "Datensatz erzeugt für " & tPerson.Vorname & " " tPerson.Nachname
End Sub
Listing 3.15 Variable vom Datentyp Person erstellen und mit Inhalten füllen
Eigene Klassen und Objekte erstellen 71

Führt man den folgenden Aufruf durch, dann kann man das Füllen der Typ-Ele-
mente beobachten und erhält zum Schluss in der Statuszeile die Information
“Datensatz erzeugt für Code Coder“:
Call FillPersonRecord("Code", "Coder", "Kodistan", "1972")
Hier sieht man auch, dass es nicht darauf ankommt, in welcher Reihenfolge die
einzelnen Elemente des selbst erstellten Datentyps angesprochen werden.
Solche Datenstrukturen lassen sich gut verwenden, um zusammenhängende
Daten, auf denen umfangreiche Aktionen ausgeführt werden, sinnvoll zusammen-
zufassen. Das kann zum Beispiel in der Schnittstellenprogrammierung sehr zur
Erstellung eines gut strukturierten Programms beitragen.
Andere Einsatzgebiete sind die Bearbeitung von Dateien im wahlfreien Zugriffs-
modus oder der Austausch von Daten mit der Notes C-API, bei dem oft zusammen-
gesetzte Datentypen gefragt sind.

3.12 Eigene Klassen und Objekte erstellen


Auch eigene Klassen lassen sich erstellen, deren Objekte wie die Objekte der einge-
bauten Notes-Klassen verwendet werden können.
Es ist sehr zu empfehlen, umfangreicheren Code nicht nur in Funktionen, sondern
auch in einer Klassenstruktur zu organisieren. Mit ein bisschen Übung ist das ist
nicht viel aufwendiger als das Schreiben von einfachen Prozeduren. Aber es erhöht
die Lesbarkeit und Wartbarkeit Ihrer Programme enorm. Zusatz- und Änderungs-
wünsche, die im schnellen Geschäftsleben häufig an einen Entwickler herangetra-
gen werden, lassen sich in einer sinnvollen Klassen- und Objektstruktur häufig viel
leichter und schneller umsetzen.
Um denjenigen, die sich noch nicht so viel mit objektorientierter Programmierung
beschäftigt haben, das Thema etwas verständlicher und schmackhafter zu machen,
möchte ich Ihnen ein kurzes hypothetisches Beispiel vor Augen führen, das die
Arbeitsweise mit Objekten gut veranschaulicht.
Gleichzeitig werde ich Schritt für Schritt zeigen, wie in LotusScript Klassen
geschrieben und Objekte davon erstellt und verwendet werden.
Wir stellen uns vor, wir würden die Software für ein Auto entwickeln, und zwar für
ein sehr fortschrittliches. In diesem Auto wird fast alles von Software geregelt und
gesteuert, es gibt kaum noch eine direkte Verbindung zwischen den Bedienungs-
elementen des Cockpits und den ausführenden Teilen wie Lenkung, Motor, Brem-
sen usw. – eine Vorstellung, die sich heute bereits nach und nach realisiert.
Wir schreiben also ein Programm, das wir schon mal »Auto« nennen, auch wenn
wir noch nicht so genau wissen, wo wir das Wörtchen Auto dranschreiben sollen.
Interessanter sind jetzt aber erst einmal die Teile. Wir nehmen uns die Lenkung vor.
Wir stellen uns vor, irgendwo im Lenkgestänge befindet sich ein Motor, der in der
Lage ist, per Software Befehle entgegenzunehmen. Die nötigen Befehle lauten:
NachRechtsAusschlagen, NachLinksAuschlagen, GeradeZiehen.

IBM SOFTWARE PRESS


72 Einführung in die LotusScript-Programmierung

Jetzt könnten wir für jeden dieser Befehle eine Prozedur schreiben, die die damit
verbundenen Aktionen durchführt:
Sub NachRechtsAusschlagen

End Sub

Sub NachLinksAusschlagen

End Sub
Sub GeradeZiehen

End Sub
Wenn der Autofahrer nach rechts abbiegen möchte, ruft er Call NachRechtsAusschla-
gen auf, will er nach links, so führt er Call NachLinksAusschlagen aus.
Wir stellen uns jetzt ein noch moderneres Auto vor, ein Auto, in dem die einzelnen
Vorderräder nicht mehr mechanisch miteinander verbunden sind. Jedes Rad wird
getrennt durch Software angesteuert. Auf diese Weise können die Räder schwieri-
gen Bedingungen viel flexibler angepasst werden, als das mit einer starren Lenk-
achse der Fall ist. Jetzt hat jedes Rad einen eigenen Stellmotor. Jedes Rad empfängt
die Befehle Call NachRechtsAusschlagen, Call NachLinksAusschlagen und Call GeradeZie-
hen.
Natürlich möchte der Fahrer nicht jedem Rad diese Befehle einzeln mitteilen. Es
gibt also ein zentrales Programm, das die Verwaltung übernimmt. Außerdem gibt
es die Aufrufe Call NachRechtsAusschlagen, Call NachLinksAusschlagen und Call Gerade-
Ziehen jetzt sowohl für die zentrale Lenksoftware als auch für die Rädersoftware.
Und nun beginnt sich abzuzeichnen, dass unsere Lenkung softwaretechnisch
schwierig werden wird. Wir müssen die Prozeduren von Lenksoftware und Räder-
software auseinander halten. Also schreiben wir:
Sub LenkungNachRechtsAusschlagen

End Sub

Sub LenkungNachLinksAusschlagen

End Sub
Sub LenkungGeradeZiehen

End Sub
Sub RechtesRadNachRechtsAusschlagen

End Sub

Sub RechtesRadNachLinksAusschlagen
Eigene Klassen und Objekte erstellen 73

End Sub
Sub RechtesRadGeradeZiehen

End Sub
Sub LinkesRadNachRechtsAusschlagen

End Sub

Sub LinkesRadNachLinksAusschlagen

End Sub
Sub LinkesRadGeradeZiehen

End Sub

Alle diese Prozeduren müssen wir ins Hauptprogramm einbinden und dort anspre-
chen. (Man könnte natürlich eine Prozedur schreiben, die die Lenkung repräsen-
tiert und damit die Steuerung der einzelnen Räder vom Hauptprogramm auslagert.
Allerdings würde dadurch das Problem nicht gelöst, dass viele Prozeduren vorhan-
den sind, die auch von anderen Programmteilen missbraucht werden könnten.)
So wäre es, wenn wir den sogenannten funktionalen Ansatz wählen würden. Das
machen wir aber nicht; wir entscheiden uns natürlich für die Erstellung von Objek-
ten, dafür ist das Kapitel ja gedacht. Wenn wir die erst einmal haben (wir nennen
sie hier schon einmal Lenkung und Rad), dann gestalten sich die Aufrufe sehr einfach:
Call Lenkung.NachRechtsAusschlagen
Call Lenkung.NachLinksAusschlagen
Call RechtesRad.NachRechtsAusschlagen
Call LinkesRad.NachRechtsAusschlagen
Jetzt werden alle beteiligten Objekte ihre eigene Prozedur NachRechtsAusschlagen
haben. Es gibt keine Namenskonflikte mehr, weil die Prozeduren den Objekten als
Methoden fest zugeordnet sind. Die feste Zuordnung bringt es mit sich, dass die
Prozeduren nicht mehr so leicht im falschen Zusammenhang angewendet werden
können. Es müssen keine Namensungetüme zur Unterscheidung der vielen »her-
umliegenden« Prozeduren mehr geschaffen werden.
Zunächst schreiben wir eine Klasse, die dann die Vorlage für die Räder bildet.
Klassen werden in LotusScript mit der Anweisung Class erstellt (im Modul-
Abschnitt (Declarations)):
Class Rad
Sub NachRechtsAusschlagen

End Sub

IBM SOFTWARE PRESS


74 Einführung in die LotusScript-Programmierung

Sub NachLinksAusschlagen

End Sub
Sub GeradeZiehen

End Sub
End Class
Mit der Dim-Anweisung können wir dann für jedes Rad ein Objekt dieser Klasse
deklarieren:
Dim radVorneRechts As Rad
Dim radVorneLinks As Rad
Soll das rechte Vorderrad nach links lenken, dann lautet der Aufruf:
radVorneRechts.NachLinksAusschlagen
Wenn Ihnen der Vorteil noch nicht ganz einleuchtet, dann haben Sie noch ein
wenig Geduld, es kommt gleich besser.
Es wurde ja bereits festgestellt, dass Objekte eigene Variablen besitzen können, die
sogenannten Eigenschaften. In unserem Beispiel wird sich das gleich als sehr nütz-
lich erweisen.
Wenn die Software wissen soll, wie ein angeforderter Lenkausschlag umgesetzt wer-
den soll, dann muss sie eine Information darüber haben, wie der momentane Aus-
schlag ist. In einem konventionellen funktionalen Softwaredesign würden wir
diese Werte in einzelnen Variablen festhalten müssen (für jedes Rad eine), die dann
an zentraler Stelle gepflegt werden (von der Möglichkeit, statische Variablen zu ver-
wenden, sehen wir hier einmal ab).
Im objektorientierten Design brauchen wir die Variable nur einmal für die Klasse
Rad zu deklarieren, und schon sind zwei Stück verfügbar, für jedes der zwei Rad-
Objekte getrennt:
Class Rad
MomentanerLenkausschlag As Integer
...
End Class
Diese Eigenschaft muss jetzt natürlich noch »gefüttert« werden. Wir erstellen dazu
eine Methode SetzeLenkausschlag, die das für uns übernimmt (die Eigenschaft ist
nicht mit Public angelegt worden, denn wir möchten ja nicht, dass irgendwelche
anderen Programme Zugriff auf den Lenkausschlag bekommen und zum Sicher-
heitsrisiko werden).
Dabei stellen wir fest, dass die Methoden für das Rechts-, Links- und Geradeauslen-
ken sehr verwandt sind. Daher können wir die eigentliche Lenkarbeit der neuen
Methode überlassen, während die übrigen Methoden sie nur mit dem jeweils pas-
senden Wert aufrufen.
Um uns die Sache einfacher zu machen, gehen wir davon aus, dass es nur drei mög-
liche Werte gibt: 1 für rechts, -1 für links und 0 für geradeaus. Wir wollen dem Fah-
Eigene Klassen und Objekte erstellen 75

rer nicht zumuten, sich die Zahlen zu merken, und hinterlegen sie daher in der Rad-
Klasse selbst als entsprechende Eigenschaften. Wir müssen nur dafür sorgen, dass
sie richtig initialisiert werden. Das übernimmt die Methode New (New wird automa-
tisch aufgerufen, wenn ein Objekt mit New neu angelegt wird):
Class Rad
iMomentanerLenkausschlag As Integer

iRechts As Integer
iLinks As Integer
iGeradeaus As Integer

Sub New()
iRechts = 1
iLinks = -1
iGeradeaus = 0
End Sub

Sub SetzeLenkausschlag(in_iLenkrichtung%)
If Not ((in_iLenkrichtung = iRechts) Or (in_iLenkrichtung = iLinks) Or _
(in_iLenkrichtung = iGeradeaus)) Then Error 1999, “Ungültiger Wert“
iMomentanerLenkausschlag = in_iLenkrichtung
End Sub

Sub NachRechtsAusschlagen
Call SetzeLenkausschlag(iRechts)
End Sub

Sub NachLinksAusschlagen
Call SetzeLenkausschlag(iLinks)
End Sub
Sub GeradeZiehen
Call SetzeLenkausschlag(iGeradeaus)
End Sub

Property Get MomentaneLenkrichtung As String


Dim strReturn$
Select Case iMomentanerLenkausschlag
Case iRechts: strReturn = “Rechts“
Case iLinks: strReturn = “Links“
Case iGeradeaus: strReturn = “Geradeaus“
End Select
End Property
End Class
Mit der zum Schluss hinzugefügten Property Get sorgen wir dafür, dass die momen-
tane Lenkrichtung abgefragt werden kann, ohne dass wir die Eigenschaft iMomenta-
nerLenkausschlag öffentlich zugänglich machen müssten.

IBM SOFTWARE PRESS


76 Einführung in die LotusScript-Programmierung

Hinweis
Eine Property (Eigenschaft) verhält sich einerseits wie eine Methode und
andererseits wie eine Zuweisung mit Einbahnstraßencharakter.
In einer Property können alle möglichen Anweisungen wie in einer Methode
ausgeführt werden. Sie kann sogar parametrisiert werden.
Auf der anderen Seite wird sie aber »von außen« wie eine Eigenschaft aufge-
rufen. Einer Property Get kann ein Wert zugewiesen werden, und eine Pro-
perty Set kann abgefragt werden. Gibt es nur eine davon, dann kann auch
nur die entsprechende Richtung verwendet werden.
Auf diese Weise kann man Eigenschaften programmieren, die nur gelesen,
nur beschrieben oder sowohl gelesen als auch beschrieben werden können.

Jetzt benötigen wir noch das Auto, an dem die Räder befestigt werden. Da es auch
Autos gibt, bei denen alle vier Räder in den Lenkvorgang einbezogen werden, mon-
tieren wir gleich vier. Normalerweise müssten wir natürlich zwei Sorten von
Rädern erstellen:
Class Auto
Räder List As Rad

Sub New()
Set Räder(“VorneRechts”) = New Rad()
Set Räder(“VorneLinks”) = New Rad()
Set Räder(“HintenRechts”) = New Rad()
Set Räder(“HintenLinks”) = New Rad()
End Sub
End Class
Die Montage geschah in Form einer Liste, weil sich das beim Erstellen der zentralen
Lenkvorrichtung als praktisch erweisen wird.
Jetzt erstellen wir die Lenkung. Sie muss alle vier Räder einstellen. Die hinteren
werden gegenläufig eingestellt. Dies erreichen wir durch das Voranstellen eines
einfachen Minuszeichens. Der Wert für Geradeaus ist 0, die Negation davon auch;
also können wir immer so vorgehen.
Allerdings ist es praktischer, der Lenkung nur eine einzige Methode zum Lenken
mitzugeben (es gibt ja auch nur ein Lenkrad). Dann muss der Fahrer beim Aufrufen
mitteilen, in welche Richtung er möchte. Damit er das in sprechender Weise tun
kann, bieten wir im die drei Eigenschaften RECHTS, LINKS und GERADEAUS an.
Dazu werden entsprechende Properties erstellt. Wir können sie auch intern ver-
wenden, wodurch wir uns die Variablen sparen, die wir für die Räder angelegt und
in New initialisiert haben.
Die Lenkung muss natürlich mit den Rädern in Verbindung stehen, also sehen wir
vor, die Räderliste bei Erstellung des Objekts zu übergeben und intern eine Referenz
festzuhalten. Diese wird dann beim Lenkvorgang abgearbeitet.
Eigene Klassen und Objekte erstellen 77

Class Lenkung
iMomentanerLenkausschlag As Integer
lstobRäder As Variant

Sub New(in_lstobRäder As Variant)


lstobRäder = in_lstobRäder
End Sub

Sub Lenken(in_iLenkrichtung%)
If Not ((in_iLenkrichtung = RECHTS) Or (in_iLenkrichtung = LINKS) Or _
(in_iLenkrichtung = GERADEAUS)) Then Error 1999, “Ungültiger Wert“

lstobRäder(“VorneRechts“).SetzeLenkausschlag(in_iLenkrichtung)
lstobRäder(“VorneLinks“).SetzeLenkausschlag(in_iLenkrichtung)
lstobRäder(“HintenRechts“).SetzeLenkausschlag(- in_iLenkrichtung)
lstobRäder(“HintenLinks“).SetzeLenkausschlag(- in_iLenkrichtung)

iMomentanerLenkausschlag = in_iLenkrichtung
End Sub

Property Get MomentaneLenkrichtung As String


Dim strReturn$
Select Case iMomentanerLenkausschlag
Case RECHTS: strReturn = “Rechts“
Case LINKS: strReturn = “Links“
Case GERADEAUS: strReturn = “Geradeaus“
End Select
End Property

Property Get RECHTS As Integer


RECHTS = 1
End Property

Property Get LINKS As Integer


LINKS = -1
End Property

Property Get GERADEAUS As Integer


GERADEAUS = 0
End Property
End Class
Die Lenkung wird am Auto befestigt:
Class Auto
lstobRäder List As Rad
obLenkrad As Lenkung

Sub New()
Set lstobRäder(“VorneRechts”) = New Rad()

IBM SOFTWARE PRESS


78 Einführung in die LotusScript-Programmierung

Set lstobRäder(“VorneLinks”) = New Rad()


Set lstobRäder(“HintenRechts”) = New Rad()
Set lstobRäder(“HintenLinks”) = New Rad()

Set obLenkrad = New Lenkung(lstobRäder)


End Sub

Property Get Lenkrad As Lenkung


Set Lenkrad = obLenkrad
End Property
End Class
Jetzt können wir ein Auto mit New erzeugen, auf das Lenkrad zugreifen und in die
Richtungen lenken, in die wir möchten:
Dim obAuto As New Auto

Call obAuto.Lenkrad.Lenken(obAuto.Lenkrad.RECHTS)
Call obAuto.Lenkrad.Lenken(obAuto.Lenkrad.LINKS)
Call obAuto.Lenkrad.Lenken(obAuto.Lenkrad.GERADEAUS)
Ein Aufruf, und es geht in die Richtung, die wir vorgeben. Die ganzen Interna (wie
viele und welche Räder in welche Richtung gelenkt werden) interessieren uns nicht
– so, wie es sich bei einem richtigen Auto gehört.
Und genauso einfach kann sich Software bedienen lassen. Einige Vorteile dieser
Programmierungsart sind:
 Die hohe Anschaulichkeit: Das macht das Programmieren einfacher.
 Es entwickelt sich auf natürliche Weise eine sinnvolle Architektur.
 Es werden wie von allein abgeschlossene Module (die Klassen) erstellt, die sich
einzeln fortentwickeln und warten lassen.
 Es bilden sich klare Schnittstellen heraus, was den Überblick und die Austausch-
barkeit fördert.
 Es wird eine hohe Wiederverwendbarkeit des Codes und von Codeteilen er-
reicht.
Aber das war noch nicht alles. Sie werden gleich noch mehr Möglichkeiten zur
Codeoptimierung kennenlernen. Außerdem wird deutlich werden, wie sich ein
objektorientiertes Design mit der Zeit fortentwickeln kann, ohne dass das eigent-
liche Program davon betroffen ist. Der Benutzer merkt davon nichts.

Vererbung
Wenn wir also etwas genauer hinsehen, dann entdecken wir gewisse Gemeinsam-
keiten zwischen der Rad-Klasse und der Klasse Lenkung. Beide beschäftigen sich mit
der Lenkung, die eine für ein einzelnes Rad, die andere für alle Räder. Das bringt
eine gewisse Redundanz mit sich, die wir jetzt mithilfe der Vererbung beseitigen.
Eigene Klassen und Objekte erstellen 79

Zunächst erstellen wir eine Klasse, die die gemeinsamen Merkmale aufnimmt. Da
sich der Einsatz der Properties für die Lenkrichtungen ganz gut macht, überneh-
men wir diese Idee auch für die gemeinsame Klasse. Wir nennen sie Lenkbares-
Objekt:
Class LenkbaresObjekt
iMomentanerLenkausschlag As Integer

Sub Lenken(in_iLenkrichtung%)
If Not ((in_iLenkrichtung = RECHTS) Or (in_iLenkrichtung = LINKS) Or _
(in_iLenkrichtung = GERADEAUS)) Then Error 1999, "Ungültiger Wert"

iMomentanerLenkausschlag = in_iLenkrichtung
End Sub

Property Get MomentaneLenkrichtung As String


Dim strReturn$
Select Case iMomentanerLenkausschlag
Case RECHTS: strReturn = "Rechts"
Case LINKS: strReturn = "Links"
Case GERADEAUS: strReturn = "Geradeaus"
End Select
End Property

Property Get RECHTS As Integer


RECHTS = 1
End Property

Property Get LINKS As Integer


LINKS = -1
End Property

Property Get GERADEAUS As Integer


GERADEAUS = 0
End Property
End Class
Zunächst lassen wir die Rad-Klasse mit Class Rad As LenkbaresObjekt von unserer neu
erstellten Basisklasse LenkbaresObjekt erben und werfen alles raus, was nicht mehr
benötigt wird. Und siehe da, die Klasse Rad wird ziemlich leer, ja sogar ganz leer.
Alles, was sie benötigt, ist bereits in der Basisklasse vorhanden:
Class Rad As LenkbaresObjekt
End Class
Auch die Methode SetLenkausschlag benötigen wir nicht mehr; sie entspricht der
Methode Lenken aus der Basisklasse.

IBM SOFTWARE PRESS


80 Einführung in die LotusScript-Programmierung

Hinweis
Theoretisch könnte man die Räder ganz durch Objekte vom Typ LenkbaresOb-
jekt ersetzen. Aber um die Architektur klar zu gestalten, ist es besser, sie so zu
belassen. Denn die Verwendung von Rad-Objekten ist näher an der Anschau-
ung als die Verwendung von LenkbaresObjekt. Und umgekehrt wäre es nicht
sehr geschickt, die Klasse LenkbaresObjekt in Rad umzubenennen, denn dann
müssten wir die Klasse Lenkung von der Klasse Rad erben lassen, und auch das
ist nicht sehr anschaulich. Es ist einfach so, dass die Räder und die Lenkung
sehr viel gemeinsam haben, aber dennoch sehr verschieden sind. Wir können
also nur die Gemeinsamkeiten in eine gemeinsame Basisklasse verlagern, aber
nicht sagen, dass die eine Klasse eine direkte Ableitung von der anderen sei.

Dann lassen wir also auch noch die Klasse Lenkung alle Eigenschaften und Metho-
den von LenkbaresObjekt erben. Alles, was vererbt wird, kann aus der Klasse Lenkung
entfernt werden. Das macht auch sie wesentlich kürzer. Die SetzeLenkausschlag-Auf-
rufe in die Rad-Objekte benennen wir dabei in Lenken um.
Class Lenkung As LenkbaresObjekt
lstobRäder As Variant

Sub New(in_lstobRäder As Variant)


lstobRäder = in_lstobRäder
End Sub

Sub Lenken(in_iLenkrichtung%)
If Not ((in_iLenkrichtung = RECHTS) Or (in_iLenkrichtung = LINKS) Or _
(in_iLenkrichtung = GERADEAUS)) Then Error 1999, "Ungültiger Wert"

lstobRäder("VorneRechts").Lenken(in_iLenkrichtung)
lstobRäder("VorneLinks").Lenken(in_iLenkrichtung)
lstobRäder("HintenRechts").Lenken(- in_iLenkrichtung)
lstobRäder("HintenLinks").Lenken(- in_iLenkrichtung)

iMomentanerLenkausschlag = in_iLenkrichtung
End Sub
End Class
Die Methode Lenken haben wir in dieser Klasse neu formulieren müsssen, da sie bei
dieser Klasse eine andere Bedeutung hat als bei den Rädern. Man nennt diese Art
der Neuformulierung Methoden überschreiben. Bei LotusScript muss man darauf ach-
ten, dass die Signatur der neu formulierten Methode genau mit der Signatur der
vererbten übereinstimmt (damit sind gemeint: die Art der Prozedur, der Name, der
oder die Parameter und der Rückgabewert). Für diejenigen, die sich mit der objekt-
orientierten Programmierung auskennen: Methoden von LotusScript-Klassen kön-
nen überschrieben, aber nicht überladen werden.
Eigene Klassen und Objekte erstellen 81

Für die Erstellung des Auto-Objekts und die Lenkaufrufe ändert sich nichts:
Dim obAuto As New Auto

Call obAuto.Lenkrad.Lenken(obAuto.Lenkrad.RECHTS)
Call obAuto.Lenkrad.Lenken(obAuto.Lenkrad.LINKS)
Call obAuto.Lenkrad.Lenken(obAuto.Lenkrad.GERADEAUS)
Es gibt noch eine Verbesserungsmöglichkeit. Auch diese möchte ich Ihnen nicht
vorenthalten:
Die überschriebene Methode Lenken der Klasse Lenkung könnte einen Teil ihrer Arbeit
der Basisklasse überlassen. Denn die Abprüfung, ob der Parameter zur Lenkrich-
tung zulässig ist, ist in beiden gleich, und auch das Festhalten der internen Eigen-
schaft iMomentanerLenkausschlag wiederholt sich.
Wir können diese Schritte also entfernen, müssen nur dafür sorgen, dass zu Beginn
die Methode Lenken aus der Basisklasse aufgerufen wird. Dies geschieht mit dem
doppelten Punktoperator in Verbindung mit dem Namen der Basisklasse, also mit
der Anweisung Call LenkbaresObjekt..Lenken(in_iLenkrichtung):
Class Lenkung As LenkbaresObjekt
lstobRäder As Variant

Sub New(in_lstobRäder As Variant)


lstobRäder = in_lstobRäder
End Sub

Sub Lenken(in_iLenkrichtung%)
Call LenkbaresObjekt..Lenken(in_iLenkrichtung)

lstobRäder("VorneRechts").Lenken(in_iLenkrichtung)
lstobRäder("VorneLinks").Lenken(in_iLenkrichtung)
lstobRäder("HintenRechts").Lenken(- in_iLenkrichtung)
lstobRäder("HintenLinks").Lenken(- in_iLenkrichtung)
End Sub
End Class
Es ist zu empfehlen, sich den Ablauf des Programms mal im Debugger anzusehen.
Dort wird uns als Objekt der obersten Ebene unser Auto-Objekt angezeigt. Gleich-
zeitig kann man den Aufbau der Objekte für Auto, Lenkung und Räder und die
jeweiligen Zustände ansehen (repräsentiert durch die gemeinsame interne Eigen-
schaft iMomentanerLenkausschlag). Dazu habe ich einen Screenshot nach jedem der
vier Vorgänge erstellt, sodass man zumindest den groben Ablauf sehen kann:

IBM SOFTWARE PRESS


82 Einführung in die LotusScript-Programmierung

Abbildung 3.28 Objektzustände der Räder und der Lenkung nach Erstellung der Variable obAuto.
Alle Lenkangaben in iMomentanerLenkausschlag stehen auf GERADEAUS (0).

Abbildung 3.29 Die Objektzustände nach dem Rechtslenken. Die Vorderräder stehen auf RECHTS (1).
Dasselbe trifft auf den in obLenkrad gespeicherten Gesamtzustand zu. Die
Hinterräder stehen auf LINKS (-1). Das ist aufgrund des geforderten gegenläufigen
Verhaltens korrekt.

Abbildung 3.30 Die Objektzustände nach dem Linkslenken. Alle Lenkzustände haben sich ins
Gegenteil verkehrt. Auch das ist korrekt.
Gültigkeitsbereiche und Module 83

Abbildung 3.31 Die Objektzustände nach dem Geradeauslenken. Alle Lenkzustände


(iMomemtanerLenkausschlag) sind wieder auf GERADEAUS (0).

3.13 Gültigkeitsbereiche und Module


Variablen haben einen begrenzten Gültigkeitsbereich. Er beginnt mit der Deklara-
tion und erstreckt sich ab da auf einen der drei möglichen Bereiche Modul, Prozedur
und benutzerdefinierte Klasse bzw. benutzerdefinierter Datentyp.
Prozeduren werden im nächsten Abschnitt ausführlich behandelt. Für diesen
Abschnitt genügt es zu wissen, dass eine Prozedur ein Stück Programmcode ist.
Vielleicht haben Sie bei der Arbeit mit Sub Initialize schon gesehen, dass ein Agent
noch einen weiteren Eventhandler (also eine spezielle Prozedur) hat, nämlich
Sub Terminate. Außerdem sind noch zwei Abschnitte sichtbar: (Options) und (Decla-
rations).
Diese zwei Prozeduren bilden mit den Abschnitten zusammen ein (Programm-)
Modul. Wie Sie im nächsten Abschnitt sehen werden, kann der Entwickler weitere
Prozeduren anlegen. Wenn wir dies im Agenten tun, dann werden sie automatisch
zu diesem einen Modul hinzugefügt.
Andere Module finden wir bei Masken, Ansichten, Datenbanken usw. Module sind
also in der Regel an Gestaltungselemente der Datenbanken gebunden, aber nicht
immer. Eine Ausnahme sind die LotusScript-Bibliotheken. Sie stellen eigene
Module dar, die in andere Module hinzugeladen werden können. Zwar werden sie
in gewisser Weise auch als Gestaltungselemente bezeichnet, aber sie sind keinem
»sichtbaren« Teil der Datenbank zugeordnet.
Variablen, die in einer Prozedur deklariert werden, sind bis zum Ende der Prozedur
gültig. Variablen, die in einem Modul deklariert werden, sind innerhalb des
Moduls gültig. Variablen, die innerhalb einer Klasse oder eines benutzerdefinierten
Datentyps deklariert werden, sind innerhalb des Gültigkeitsbereiches der damit
angelegten Variablen gültig.

Modifizierer
Um die Sache nicht zu einfach werden zu lassen, gibt es auch noch die Modifizierer
Public, Private und Static.

IBM SOFTWARE PRESS


84 Einführung in die LotusScript-Programmierung

In der Designer-Hilfe werden sie zwar nicht so genannt, sondern einfach als abge-
wandelte Schlüsselwörter für die Variablendeklaration behandelt (als Ergänzung zu
Dim). Aber sie haben im Prinzip keine andere Funktion, als den Sichtbarkeitsbereich
zu verändern.

Modulebene
In einem Modul kann eine Variable mit einer öffentlichen oder einer privaten
Sichtbarkeit angelegt werden. Im ersten Fall sind die Variablen auch außerhalb des
Moduls sichtbar, im anderen Fall nur innerhalb. Wenn Sie beispielsweise eine
LotusScript-Bibliothek zu einem Maskenmodul hinzuladen (mit Use), dann sind
deren Variablen für die Maskenprozeduren nur sichtbar, wenn sie in der Bibliothek
als öffentlich deklariert wurden.
Hiermit können wir die beiden Begriffe Gültigkeit und Sichtbarkeit noch etwas
genauer fassen: Beide Modulvariablen sind gültig, solange das Modul geladen ist.
Doch ist die private Modulvariable nur innerhalb des Moduls sichtbar, also zugäng-
lich. Die öffentliche Variable ist auch außerhalb sichtbar.
Die gleichen Bedingungen gelten für die Deklaration von Prozeduren, Klassen und
Typen. Wird eines dieser Elemente mit Private deklariert, so ist es nur innerhalb des
Moduls sichtbar.
Auf diese Weise kann man Teile eines Moduls, die nur intern verwendet werden,
vor dem Zugriff von außen verstecken. Nach außen zeigt man dann nur die Ele-
mente, die in einem anderen Modul zur Anwendung kommen sollen. Diese kann
man dann als die API des Moduls bezeichnen.

Prozedurebene
Innerhalb von Prozeduren sind Variablen immer nicht-öffentlich. Da man hier
nicht zwischen privat und öffentlich entscheiden kann, gibt es in dieser Hinsicht
nur eine Deklarationsmöglichkeit, und die heißt Dim. Dim legt in diesem Fall eine
private Variable an, auch wenn das Schlüsselwort Private nicht zum Einsatz kom-
men kann.
Sie können aber eine andere Modifikation durchführen, die speziell für Prozeduren
gilt: Static. Mit Static wird eine statische Variable angelegt. Damit wird die Aufbe-
wahrungsdauer des zuletzt zugewiesenen Variableninhalts verändert. Normaler-
weise ist der Inhalt mit dem Verlassen einer Funktion vergangen. Bei statischen
Variablen wird er hingegen bis zum nächsten Aufruf der Funktion aufbewahrt.
Solange das Modul mit der Funktion geladen ist, wird man also bei jedem Aufruf
den zuletzt zugewiesenen Wert vorfinden.

Elementvariablen von benutzerdefinierten Typen


Die Elemente eines mit Type erzeugten Datentyps (also dessen Variablen) sind
immer öffentlich sichtbar (solange die Variable dieses Datentyps gültig ist). Daher
wird beim Aufruf von Type auch keine Anweisung vor die Deklaration geschrieben,
weder Dim noch Private noch Public oder Static.
Wie geht es nun weiter? 85

Eigenschaften und Methoden von Klassen


Die Eigenschaften von mit Class erzeugten benutzerdefinierten Klassen bzw. der
davon angelegten Objekte (also deren Variablen) sind standardmäßig privat bezüg-
lich des Objekts. Sie sind also nur innerhalb des Objekts sichtbar. Sollen sie von
außen sichtbar sein, müssen sie Public deklariert werden.
Bei den Methoden (also den in den Klassen enthaltenen Prozeduren) verhält es sich
genau umgekehrt. Sie sind standardmäßig öffentlich sichtbar, können aber mit
Private auf den Innenbereich der Klasse bzw. der von ihr abgeleiteten Objekte
beschränkt werden.

3.14 Wie geht es nun weiter?


Sie sind nun in die Grundzüge der Notes/Domino-Programmierung mit Lotus-
Script eingeweiht. Sie sind sogar in der Lage, komplexe objektorientierte Pro-
gramme mit LotusScript zu entwerfen.
Nun werden Sie sich sicherlich Ihren speziellen Aufgaben zuwenden wollen, die Sie
mit LotusScript lösen möchten.
Um Ihnen zu helfen, schnellstmöglich die LotusScript-Funktionen und Notes-Klas-
sen zu finden, die Ihnen dabei zur Seite stehen, sind die übrigen Ausführungen
nach Themen und Stichworten angeordnet.
Im LotusScript-Bereich finden Sie jeweils ein Thema mit einer mehr oder weniger
langen Einführung, in der gezeigt wird, wie es mit den zur Verfügung stehenden
Funktionen bearbeitet werden kann. Anschließend finden Sie dann jeweils die
vollständige Liste der Funktionen, die mit Syntax und eventuellen Besonderheiten
behandelt werden.
Daran schließt sich ein Bereich von Kapiteln an, die einzelne Themen behandeln,
die mit Notes-Klassen bearbeitet werden können. Das ist aber nicht immer aus-
schließlich zu verstehen. Kapitel wie 8, Datumswerte und Zeitangaben, (Seite 325)
und 10, Dateien und Streams, (Seite 375) befassen sich auch sehr ausführlich mit
LotusScript-Funktionen.
Daran fügt sich ein großer Bereich an, in dem die Notes-Klassen alphabetisch auf-
geführt sind und in der Form einer Referenz besprochen werden.
Sie werden schnell merken, dass die systematische Abhandlung der LotusScript-
Funktionen und der Notes-Klassen keine einfache Wiederholung der Designer-
Hilfe darstellt. Wo immer es angebracht war, werden zusätzliche Hinweise gegeben,
die Sie auf Fallgruben und praktische Anwendungsmöglichkeiten aufmerksam
machen. Andererseits sind hier zwar meistens, aber nicht immer sämtliche syntak-
tischen Hinweise und Wertebereiche aufgeführt, da eben das Geben von prakti-
schen Hinweisen im Vordergrund steht. Wenn Sie also einen Hinweis vermissen,
dann sollten Sie auch die Designer-Hilfe zu Rate ziehen.
Auch der sorgfältige Index soll Ihnen helfen, schnell Hinweise zu den Themen zu
finden, die Sie interessieren.

IBM SOFTWARE PRESS