Das LotusScript-Entwicklerbuch für Notes/Domino 8 - Addison-Wesley
Das LotusScript-Entwicklerbuch für Notes/Domino 8 - Addison-Wesley
Das LotusScript-Entwicklerbuch für Notes/Domino 8 - Addison-Wesley
Sie wollen auch ein ePaper? Erhöhen Sie die Reichweite Ihrer Titel.
YUMPU macht aus Druck-PDFs automatisch weboptimierte ePaper, die Google liebt.
Grundlagen<br />
Teil I führt Sie auf praktische Weise zügig in die Programmierung von <strong>Notes</strong>-/<br />
<strong>Domino</strong> mit <strong>LotusScript</strong> ein.<br />
Sie lernen, wo und wie <strong>LotusScript</strong>-Programme erstellt und zum Laufen gebracht<br />
werden. Es werden sämtliche grundlegenden Elemente besprochen wie Lotus-<br />
Script-Befehle, -Variablen, -Objekte, -Module, -Prozeduren, usw.<br />
Natürlich erfahren Sie auch in allen Einzelheiten, wie der Debugger bedient und<br />
praktisch eingesetzt wird. Dieses Wissen ist eine wichtige Unterstützung bei der<br />
Durchführung effektiver Tests.<br />
Außerdem erhalten Sie eine ausführliche, anschauliche Darstellung zur objektorientierten<br />
Programmierung unter <strong>LotusScript</strong>. Ein gutes Verständnis dieses Punktes<br />
wird Ihnen bei der Bildung qualitativ hochwertiger Architekturen sehr behilflich<br />
sein.<br />
Die Darlegung des Stoffes beginnt zunächst sehr detailliert, um Sie beim Einstieg<br />
sicher zu begleiten und zieht dann im Tempo recht schnell an, um Sie schnellstmöglich<br />
zu den wesentlichen Erkenntnissen zu führen, die Sie <strong>für</strong> eine erfolgreiche<br />
Erstellung und Wartung auch komplexer Programme benötigen.<br />
IBM SOFTWARE PRESS
Einführung in die<br />
<strong>LotusScript</strong>-<br />
Programmierung<br />
Die Programmierung mit <strong>LotusScript</strong> ähnelt sehr der Programmierung mit VBA<br />
(Visual Basic for Applications von Microsoft). Abgesehen von der engen Sprachverwandtschaft,<br />
werden beide in Verbindung mit grafischen Benutzeroberflächen<br />
verwendet. Wer also Erfahrung mit der Erstellung von Makros in Microsoft-Office-<br />
Produkten hat, wird sich mit <strong>LotusScript</strong> sehr leicht tun.<br />
Für Programmierer, die gerade erst beginnen oder mit grafischen Benutzeroberflächen<br />
weniger Erfahrung haben, müssen einige grundlegende Dinge kurz erläutert<br />
werden, damit sie einen guten Einstieg finden.<br />
Wir beginnen gleich praxisorientiert; Learning-by-Doing ist häufig der schnellste<br />
Weg, um Dinge richtig zu »begreifen«. Sie können also jetzt das erste Programm<br />
»anfassen«.<br />
3.1 <strong>Das</strong> erste Programm<br />
<strong>LotusScript</strong>-Programme sind immer Teil einer <strong>Notes</strong>-Datenbank; sie können nicht<br />
frei davon existieren. Wir erstellen also zunächst einmal eine neue Datenbank (ab<br />
Version 8 auch Anwendung genannt) im <strong>Notes</strong>-Client.<br />
3.1.1 Neue Anwendung (Datenbank) anlegen<br />
Wählen Sie dazu im Menü DATEI/ANWENDUNG/NEU... (Abbildung 3.1).<br />
Abbildung 3.1 <strong>Das</strong> Erstellen einer neuen Anwendung (Datenbank)<br />
IBM SOFTWARE PRESS
32 Einführung in die <strong>LotusScript</strong>-Programmierung<br />
Im sich anschließenden Dialog geben Sie einen Titel <strong>für</strong> die Datenbank und den<br />
Dateinamen und inklusive Pfad an. Wenn Sie den Titel eintragen, wird dieser automatisch<br />
auch als Dateiname vorgeschlagen. Sie können den Dateinamen jetzt<br />
natürlich nach Belieben verändern. Außerdem wird dem Namen die Endung .nsf<br />
angehängt. <strong>Das</strong> ist die Standardendung <strong>für</strong> <strong>Notes</strong>-Datenbanknamen.<br />
Ich gebe der Datenbank in meinem Beispiel den Namen <strong>LotusScript</strong>-Programmierung,<br />
und zwar <strong>für</strong> TITEL und DATEINAME. Sie können es mir nachmachen oder einen<br />
anderen Namen wählen. Alle übrigen Einstellungen lassen wir unverändert und<br />
klicken auf OK (Abbildung 3.2).<br />
Abbildung 3.2 Titel und Dateinamen der neuen Datenbank festlegen<br />
Sofort wird die Datenbank erstellt und auch gleich geöffnet (Abbildung 3.3).<br />
Abbildung 3.3 Die neue Datenbank wird gleich geöffnet.
<strong>Das</strong> erste Programm 33<br />
Sie sehen in der linken Spalte oben den Titel und darunter ein Symbol <strong>für</strong> die automatisch<br />
erstellte, noch unbenannte Vorgabe-Ansicht. Diese ist im rechten Teil zu<br />
sehen. Ihre einzige Spalte trägt im Kopf das Nummernsymbol #. Natürlich sind<br />
noch keine Dokumente enthalten.<br />
Diese brauchen wir jetzt aber erst einmal gar nicht. Wichtig ist, dass wir unsere<br />
Datenbank haben, die als Container <strong>für</strong> die zu erstellenden Programme dient.<br />
Hinweis<br />
Wie ich bereits gesagt habe, sind <strong>LotusScript</strong>-Programme immer Teil einer<br />
<strong>Notes</strong>-Datenbank; sie können nicht frei davon existieren – und umgekehrt:<br />
Wenn man in <strong>Notes</strong> eine Anwendung mit <strong>LotusScript</strong> schreibt, dann besteht<br />
diese immer aus mindestens einer Datenbank.<br />
Wohl auch deshalb werden <strong>Notes</strong>-Datenbanken ab Version 8 auch als Anwendungen<br />
bezeichnet. Daher werde ich die beiden Begriffe in diesem Buch auch<br />
schon mal synonym gebrauchen.<br />
Trotzdem werden Sie schnell merken, dass Anwendungen aus Entwicklersicht<br />
aus einer oder mehreren Datenbanken bestehen, also begrifflich eigentlich<br />
davon zu trennen sind. Während die Anwendung mehr das Gesamtprodukt<br />
aus Benutzersicht darstellt, haben wir es als Programmierer eher mit den<br />
Datenbanken als Trägern der Applikationen zu tun.<br />
Der hauptsächliche Grund, warum Datenbanken von IBM jetzt als »Anwendungen«<br />
bezeichnet werden, liegt wahrscheinlich in der Einführung des Konzepts<br />
der Verbundanwendungen (Composite Applications).<br />
<strong>Das</strong> Ziel dabei ist es, mithilfe einer Webservice-Architektur <strong>für</strong> klare Schnittstellen<br />
zwischen Einzelapplikationen zu sorgen, die dann zu Verbundanwendungen<br />
zusammengestellt werden können. Mehr dazu finden Sie im Kapitel<br />
16, Verbundanwendungen, ab Seite 563.<br />
3.1.2 Anwendung (Datenbank) zur Programmierung öffnen<br />
Wir werden die Datenbank jetzt im Designer öffnen, um mit der Programmierung<br />
beginnen zu können. Schließen Sie dazu die Datenbank mit einem Klick auf das<br />
kleine x-förmige Kreuz auf dem Reiter LOTUSSCRIPT-PROGRAMMIERUNG. Danach<br />
sehen Sie die automatisch angelegte Kachel der Datenbank auf dem Arbeitsbereich<br />
(Kacheln dienen als ein visueller Zugang zu <strong>Notes</strong>-Datenbanken). Klicken Sie<br />
anschließend mit der rechten Maustaste auf die Kachel, und wählen Sie IN DESIG-<br />
NER ÖFFNEN aus (Abbildung 3.4).<br />
IBM SOFTWARE PRESS
34 Einführung in die <strong>LotusScript</strong>-Programmierung<br />
Abbildung 3.4 Die Datenbank im Designer öffnen<br />
Es öffnet sich dann automatisch der <strong>Domino</strong> Designer, das hauptsächliche Programmierhandwerkzeug<br />
des <strong>Notes</strong>/<strong>Domino</strong>-Programmierers. Unsere Datenbank<br />
wird in Programmierdarstellung angezeigt (Abbildung 3.5).<br />
Abbildung 3.5 Die neue Datenbank im <strong>Domino</strong> Designer, fertig zum Erstellen des ersten Programms<br />
Im linken Bereich sehen Sie eine baumartige Darstellung der einzelnen Datenbank-<br />
Elemente, die im Designer bearbeitet werden können: Rahmengruppen, Seiten,<br />
Masken usw. Vieles davon kann mit <strong>LotusScript</strong> programmiert werden.<br />
Hinweis<br />
Sie sehen, dass ich die Datenbanken respektive Anwendungen über den<br />
Arbeitsbereich verwalte. Eigentlich ist dies eine veraltete Benutzeroberfläche,<br />
die das Erscheinungsbild von <strong>Notes</strong> in der Vergangenheit sehr geprägt hat.<br />
Vor einiger Zeit wurden unter anderem die Lesezeichen eingeführt, um <strong>Notes</strong><br />
moderner erscheinen zu lassen. Für Benutzer mag dies sehr praktisch und<br />
auch ansprechender sein. Zumal die Lesezeichen unter <strong>Notes</strong> 8 in der Standardkonfiguration<br />
in ein sehr schönes ÖFFNEN-Menü überführt worden sind<br />
(Abbildung 3.6).
<strong>Das</strong> erste Programm 35<br />
Abbildung 3.6 Die Lesezeichen im neuen Eclipse-basierten Client der <strong>Notes</strong> 8-<br />
Standardkonfiguration. Sie werden jetzt als ÖFFNEN-Menü dargestellt.<br />
Für Entwickler und Administratoren zeigt sich in der Praxis, dass der gute alte<br />
Arbeitsbereich mit seinen Arbeitsbereichsseiten und Kacheln trotzdem kaum<br />
zu ersetzen ist. Die Art der Anordnung ist im ersten Moment etwas gewöhnungsbedürftig,<br />
erweist sich dann aber als sehr gut geeignet, um die Übersicht<br />
über große Mengen von Datenbanken zu behalten.<br />
Sie erreichen den Arbeitsbereich in der Standardkonfiguration (wie in Abbildung<br />
3.61.6 gezeigt) oder in der Basiskonfiguration über das Lesezeichen<br />
ANWENDUNGEN in der linken Navigationsleiste (siehe Abbildung 3.7).<br />
IBM SOFTWARE PRESS
36 Einführung in die <strong>LotusScript</strong>-Programmierung<br />
Abbildung 3.7 Öffnen Sie den Arbeitsbereich mit den Kacheln über die Lesezeichenleiste.<br />
3.1.3 Unser erstes Programm: Einen Agenten erstellen<br />
Wir werden jetzt einen sogenannten Agenten erstellen, der unser erstes Programm<br />
ausführt.<br />
Klicken Sie dazu bitte auf GEMEINSAMER CODE und AGENTEN (Abbildung 3.8).<br />
Abbildung 3.8 Schritte zum neuen Agenten<br />
Sie sehen rechts eine leere Liste, in der Sie später den neuen Agenten wiederfinden<br />
werden, den Sie jetzt bitte mit einem Klick auf die Aktion NEUER AGENT rechts oben<br />
erstellen.<br />
Es öffnet sich ein Dialog, in dem wir unserem Agenten einen fantasievollen Namen<br />
mit hohem Wiedererkennungswert geben (diejenigen unter Ihnen, die bereits eine
<strong>Das</strong> erste Programm 37<br />
andere Programmiersprache erlernt haben, werden höchstwahrscheinlich wissen,<br />
was ich damit meine), nämlich “Hello World“ (siehe Abbildung 3.9).<br />
Abbildung 3.9 Die Einstellungen <strong>für</strong> den neuen Agenten<br />
Es ist wichtig, dass wir unter LAUFZEIT das richtige ZIEL eingeben, nämlich Keines.<br />
<strong>Das</strong> ist übrigens eine Einstellung, die <strong>für</strong> viele <strong>LotusScript</strong>-Programme genau die<br />
richtige ist, da Sie damit in der Regel die meisten Möglichkeiten bei der Kodierung<br />
haben. Allerdings können Sie in diesem Fall die Dokumentauswahl durch den<br />
Agenten nicht nutzen. Diese muss dann im Script programmiert werden.<br />
Schließen Sie nun den Dialog mit dem kleinen Kreuz rechts oben. Sie werden dann<br />
den neuen Agenten wie in Abbildung 3.10 geöffnet vor sich sehen. Wir müssen nur<br />
noch die richtige Programmierart auswählen (viele <strong>Notes</strong>-Datenbankelemente<br />
können mit unterschiedlichen Sprachen programmiert werden). Schalten Sie<br />
rechts oben von EINFACHE AKTION(EN) auf LOTUSSCRIPT um.<br />
Abbildung 3.10 Programmierart bzw. -sprache auswählen (Schalten Sie von EINFACHE AKTION(EN) auf<br />
LOTUSSCRIPT um.)<br />
Jetzt sind wir schon an der Stelle, an der wir richtig in <strong>LotusScript</strong> kodieren können.<br />
(»Endlich!«, werden Sie vielleicht sagen. Aber diese wenigen Schritte werden<br />
Ihnen schnell in Fleisch und Blut übergehen.)<br />
IBM SOFTWARE PRESS
38 Einführung in die <strong>LotusScript</strong>-Programmierung<br />
Hinweis<br />
Doch halt, wozu brauchen wir eigentlich einen Agenten?<br />
Nun, <strong>LotusScript</strong> lässt sich nicht als eigenständiges Programm schreiben.<br />
<strong>LotusScript</strong> kann nicht von der Kommandozeile gestartet werden. Es muss<br />
immer in irgendwelche Datenbankbestandteile eingebettet werden.<br />
Der klassischen Vorstellung von einem »richtigen Programm« kommt dabei<br />
das Datenbankelement Agent noch am nächsten, und deswegen beginnen wir<br />
mit der Programmierung eines solchen.<br />
Einen Agenten können Sie sich als eine Hülle, einen Container oder auch als<br />
ein Rahmenwerk <strong>für</strong> Ihr <strong>LotusScript</strong>-Programm vorstellen. Wir betten das<br />
Programm dort ein und lassen es dann vom Agenten ausführen.<br />
Später werden Sie Programme auch an anderen Stellen einbauen, zum Beispiel<br />
in Masken oder Schaltflächen.<br />
Den Agenten mit <strong>LotusScript</strong>-Code versehen<br />
Wir können unseren Agenten gleich, direkt nach seiner Fertigstellung, über das<br />
Menü des <strong>Notes</strong>-Clients starten. Wenn der Agent startet, dann wird er automatisch<br />
den Code ausführen, der in seinem INITIALIZE-Abschnitt steht. Diesen Code werden<br />
wir jetzt noch schnell einfügen.<br />
Abbildung 3.11 <strong>LotusScript</strong>-Ansicht des Agenten “Hello World“<br />
Klicken Sie also bitte links in der Liste auf INITIALIZE (Abbildung 3.11), und geben<br />
Sie dann rechts Folgendes ein:<br />
Messagebox "Hello World. I’m the champion!"<br />
<strong>Das</strong> war’s schon. <strong>Das</strong> ist Ihr erstes <strong>LotusScript</strong>-Programm (Abbildung 3.12).<br />
Abbildung 3.12 <strong>Das</strong> “Hello World“-Programm
<strong>Das</strong> erste Programm 39<br />
Nach getaner Arbeit möchten wir natürlich sehen, wie dieses aufwendige und<br />
wichtige Programm in der Realität arbeitet. Dazu schließen Sie bitte den Agenten<br />
mit dem kleinen Kreuz oben in seinem Fenster-Reiter. Sie werden gefragt werden,<br />
ob Sie Ihre Änderungen speichern möchten, und dazu sagen Sie selbstverständlich<br />
ja. Anschließend können Sie Ihr fertiges Produkt in der Liste der Agenten bewundern<br />
(Abbildung 3.13).<br />
Abbildung 3.13 Der fertige “Hello World“-Agent<br />
Den Agenten starten<br />
Sie können den Agenten jetzt über das Menü mit AGENT/STARTEN laufen lassen.<br />
(Dazu muss sich der blaue Cursorbalken auf dem Agenten befinden, so wie es in<br />
Abbildung 3.13 zu sehen ist.) Oder Sie klicken mit der rechten Maustaste auf den<br />
Agenten in der Liste und wählen aus dem Kontextmenü den Punkt STARTEN aus<br />
(siehe Abbildung 3.14 und Abbildung 3.15).<br />
Abbildung 3.14 So starten Sie den Agenten über das Designer-Menü.<br />
Abbildung 3.15 So starten Sie den Agenten über das Kontextmenü.<br />
IBM SOFTWARE PRESS
40 Einführung in die <strong>LotusScript</strong>-Programmierung<br />
Egal, wie Sie den Agenten starten, als Resultat erhalten Sie folgende Ausgabe (Abbildung<br />
3.16):<br />
Abbildung 3.16 Die Ausgabe unseres ersten <strong>LotusScript</strong>-Programms<br />
3.2 Die grundlegenden Schritte zur Erstellung<br />
von <strong>LotusScript</strong>-Programmen<br />
Nachdem wir so erfolgreich waren, können wir uns erst einmal zurücklehnen und<br />
in Ruhe rekapitulieren, was wir genau gemacht haben – und wie wir diese Erkenntnisse<br />
in Zukunft verwenden können.<br />
Schritt 1<br />
Wir haben einen Agenten erstellt, der als Container <strong>für</strong> unser Programm dient.<br />
In anderen Fällen werden Sie auch Masken, Seiten, Schaltflächen und andere Elemente<br />
verwenden.<br />
Schritt 2<br />
Wir haben uns einen geeigneten »Startpunkt« <strong>für</strong> unseren Code gesucht und sind<br />
mit Sub Initialize fündig geworden.<br />
In Masken sind beliebte Startpunkte Sub PostOpen, Sub QueryClose usw. Ähnlich verhält<br />
es sich bei Seiten, Ansichten und Datenbank-Scripts. Man nennt sie auch<br />
Eventhandler (Routinen zur sogenannten Ereignisbehandlung). Weitere Details<br />
dazu finden Sie im Abschnitt 3.9, Weitere Startpunkte <strong>für</strong> <strong>LotusScript</strong>-Programme, auf<br />
Seite 66.<br />
Schritt 3<br />
Im Eventhandler Sub Initialize haben wir unseren Code eingegeben. Und das wird<br />
bei anderen Startpunkten natürlich genauso gehandhabt.<br />
Schritt 4<br />
Dann haben wir den Agenten geschlossen. Dabei wurde er gespeichert.<br />
Syntaxüberprüfung und Kompilierung<br />
Aber hier ist noch etwas mehr passiert. <strong>Das</strong> Programm wurde automatisch auf korrekte<br />
Syntax hin untersucht und kompiliert.<br />
Hätten Sie einen syntaktischen Fehler gemacht (also etwas geschrieben, was Lotus-<br />
Script nicht versteht), dann hätten Sie eine entsprechende Fehlermeldung erhal-
Die grundlegenden Schritte zur Erstellung von <strong>LotusScript</strong>-Programmen 41<br />
ten. Sie können ja den Agenten spaßeshalber noch einmal öffnen und Messagebox in<br />
Massagebox ändern (ein beliebter Rechtschreibfehler). Versuchen Sie dann, den<br />
Agenten noch einmal zu speichern. <strong>Das</strong> können Sie diesmal tun, ohne ihn zu<br />
schließen. Wählen Sie einfach im Menü DATEI/SPEICHERN aus, oder klicken Sie auf<br />
das Diskettensymbol in der Toolbar-Leiste. Auch die Verwendung von [Strg] + [S]<br />
ist möglich. Auf jeden Fall erhalten Sie die Meldung aus Abbildung 3.17.<br />
Abbildung 3.17 Die Syntaxprüfung hat im Code einen Fehler erkannt.<br />
Den Fehler hätten Sie in diesem Fall auch schon vorher sehen können, denn der<br />
<strong>LotusScript</strong>-Editor prüft die verwendeten Begriffe und Operatoren bereits während<br />
der Eingabe. Wenn er bekannte Schlüsselwörter erkennt, dann färbt er sie blau ein.<br />
Messagebox ist ein solches Schlüsselwort und wird erkannt. Nachdem wir aber das<br />
erste »e« gegen ein »a« ausgetauscht hatten, handelte es sich um keinen bekannten<br />
(eingebauten) Begriff mehr, und Massagebox wurde schwarz.<br />
Man kann also schon während der Eingabe erkennen, ob man die richtigen Schlüsselwörter<br />
verwendet.<br />
Schritt 5<br />
Zum Schluss haben wir den Agenten gestartet. Was dann passierte, ist wichtig <strong>für</strong><br />
das Grundverständnis aller <strong>LotusScript</strong>-Programme.<br />
Der <strong>Notes</strong>-Client hat beim Start die Kontrolle übernommen. Er weiß, dass in einem<br />
Agenten eine Prozedur namens Sub Initialize vorkommen muss. Eine Prozedur ist<br />
eine Funktion ohne Rückgabewert. Mehr dazu folgt später im Abschnitt 3.5, Eine<br />
eigene Prozedur schreiben. Der Client weiß das also und startet sie <strong>für</strong> uns. Damit kam<br />
dann auch unsere Codezeile Messagebox “Hello World. I’m the champion!“ zur Ausführung.<br />
Prozeduren beginnen immer mit dem Kopf Sub und enden unten mit<br />
dem Anweisungsteil End Sub. Dazwischen steht der Code, der von der Prozedur ausgeführt<br />
werden soll. In unserem Fall lautet die gesamte Prozedur:<br />
Sub Initialize<br />
Messagebox "Hello World. I’m the champion!"<br />
End Sub<br />
Wir haben allerdings nur die mittlere Zeile hingeschrieben, weil der Client wie<br />
gesagt weiß, dass ein Agent eine Prozedur Initialize haben muss, und daher den<br />
»Rahmen«, nämlich Kopf und Fuß, schon selbst hingeschrieben hat.<br />
Der Hinweis, dass das Programm beim Speichern kompiliert wurde, braucht Sie im<br />
Prinzip nicht weiter zu interessieren.<br />
IBM SOFTWARE PRESS
42 Einführung in die <strong>LotusScript</strong>-Programmierung<br />
Hinweis<br />
Falls Sie es doch genauer wissen wollen, nur so viel zur Erklärung:<br />
Der Code wird beim Kompilieren in eine andere Form gebracht; eine Form,<br />
die vom <strong>LotusScript</strong>-Interpreter verstanden werden kann.<br />
Der Interpreter ist ein internes Programm, das beim Aufruf von <strong>LotusScript</strong>-<br />
Code die Anweisungen ausführt, die der Entwickler notiert hat (wie Messagebox).<br />
Diese Form des auszuführenden Codes nennt man Objektcode.<br />
Der Objektcode wird <strong>für</strong> den Benutzer unsichtbar neben dem vom Entwickler<br />
geschriebenen Programm abgespeichert.<br />
3.3 Variablen – die temporären Speicherplätze<br />
Wenn man in Programmen mit Daten, Werten und Texten arbeitet, dann ist es<br />
nicht immer praktisch, sie direkt hinzuschreiben. Ja, in der Regel ist es gar nicht<br />
möglich. Bei unserem letzten Beispiel war das noch völlig in Ordnung. Wir haben<br />
den Text “Hello World. I’m the champion!“ einfach hingeschrieben, und Messagebox<br />
war damit zufrieden.<br />
Jetzt möchten wir aber gern eine wiederholte Ausgabe tätigen, bei der ein bestimmter<br />
Textteil immer gleich ist. Dann ist es natürlich zeitsparender, wenn wir ihn nur<br />
einmal hinzuschreiben brauchen. Dazu müssen wir ihn irgendwo speichern, damit<br />
er uns auf Wunsch immer wieder zur Verfügung steht. Da wir den Wert nur während<br />
des Programmablaufs benötigen, reicht es, ihn temporär zu speichern (also im<br />
Arbeitsspeicher statt auf der Festplatte).<br />
Die Antwort auf diese Herausforderung lautet: Variablen.<br />
Variablen<br />
Variablen sind benannte Speicherplätze, auf die während eines Programmablaufs<br />
zugegriffen werden kann. In <strong>LotusScript</strong> sind Variablen immer veränderbar,<br />
d. h., ihnen können während des Programmablaufs jederzeit neue<br />
Werte zugewiesen werden.<br />
3.3.1 Variablen deklarieren<br />
Eine Variable wird meistens mit der Anweisung Dim erstellt. Beispielsweise so:<br />
Dim strVariablenName As String<br />
Dim ist die Abkürzung des englischen Begriffs Dimension und bedeutet »Dimensionierung,<br />
Maßangabe«. Mit Dim wird also der gewünschte Speicherplatz »dimensioniert«.<br />
Man nennt diesen Vorgang auch Deklaration.<br />
Bei Programmvariablen gehört dazu nicht nur die Größe, sondern auch die Art der<br />
Daten, die dort eingelagert werden sollen. Zum einen hilft das der Speicherverwal-
Variablen – die temporären Speicherplätze 43<br />
tung im Hintergrund, sich auf das einzustellen, was da kommt, und zum anderen<br />
hilft es, mögliche logische Fehler bei der Datenzuordnung von vornherein besser<br />
zu erkennen.<br />
Achtung<br />
Variablen müssen immer vor ihrer ersten Verwendung deklariert werden. Tun<br />
Sie dies nicht, dann kann es sein, dass <strong>LotusScript</strong> dies <strong>für</strong> Sie unsichtbar im<br />
Hintergrund tut. <strong>Das</strong> sollten Sie aber unterbinden, indem Sie immer im<br />
Abschnitt (Options) Folgendes eingeben: Option Declare (oder Option Explicit,<br />
was funktional dasselbe ist). Mehr dazu finden Sie im Abschnitt 4.2 Optionen<br />
und Voreinstellungen, ab Seite 130.<br />
Die Angabe As String sagt aus, dass in dem angeforderten Speicherplatz eine Zeichenkette<br />
abgelegt werden soll (in unserem Hello World-Programm war das eine<br />
Aneinanderreihung von Buchstaben). Außerdem wird auf diese Weise klargemacht,<br />
dass über die Größe noch nicht viel gesagt werden kann. String-Variablen<br />
können nämlich während des Programmablaufs fast beliebig wachsen und auch<br />
schrumpfen.<br />
Hinweis<br />
Es gibt auch die Möglichkeit, String-Variablen mit fester Länge zu deklarieren.<br />
Außerdem gibt es natürlich auch andere Arten von Variablen, zum Beispiel<br />
zur Verwaltung von Zahlen. Man spricht dabei von verschiedenen Datentypen.<br />
Der Begriff direkt nach Dim ist der Name, der dieser Variablen gegeben wird (str-<br />
VariablenName). Unter diesem Namen kann auf die Variable und damit auf den mit<br />
ihr verbundenen Speicherplatz zugegriffen werden.<br />
Bei der Wahl des Namens ist man sehr flexibel. So kann man zum Beispiel jede Buchstabenkombination<br />
unseres Alphabets wählen, solange sich kein Begriff ergibt, der<br />
schon von der <strong>LotusScript</strong>-Sprache selbst belegt ist.<br />
In diesem Beispiel habe ich mit str ein Präfix verwandt, das dem Leser des Programms<br />
deutlich macht, dass es sich hier um eine String-Variable handelt. Auf die<br />
Funktion der Variablen hat das keinerlei Einfluss. Solche Präfixe sind aber sehr<br />
praktisch, um auch bei langen Programmen den Überblick zu behalten, was <strong>für</strong><br />
Daten in welchen Variablen abgelegt werden.<br />
Ich kann Sie nur dazu ermuntern, sich einen entsprechenden Styleguide anzugewöhnen.<br />
Verwenden Sie <strong>für</strong> Variablennamen immer Präfixe, und zwar möglichst<br />
gängige bzw. sprechende Präfixe. Auch die Namen der Variablen sollten möglichst<br />
klar <strong>für</strong> den Inhalt oder die Verwendung sprechen. <strong>Das</strong> sollten Sie auch dann tun,<br />
wenn Sie erfahrene Programmierer kennenlernen, die sich über solche Regeln hinwegsetzen.<br />
IBM SOFTWARE PRESS
44 Einführung in die <strong>LotusScript</strong>-Programmierung<br />
Datentyp-Suffixe<br />
In Basic-Sprachen wie <strong>LotusScript</strong> kann man viele Datentypen statt mit der Formulierung<br />
As Datentyp auch mit einem Suffix angeben.<br />
Für String-Variablen lautet das Suffix $, und so könnten wir die obige Deklaration<br />
auch wie folgt notieren:<br />
Dim strVariablenName$<br />
Diese Art der Deklaration hat den Vorteil, dass Sie weniger schreiben müssen und<br />
mit ein wenig Übung die manchmal lange Liste der Datendeklarationen schneller<br />
überblicken können.<br />
Beispieldeklarationen <strong>für</strong> weitere Datentypen<br />
Bei den folgenden Deklarationen sind zu Ihrer Orientierung einige Deklarationen<br />
ohne und mit Suffix gegenübergestellt:<br />
Dim iKleineGanzzahl As Integer<br />
Dim iKleineGanzzahl%<br />
Dim lngGroßeGanzzahl As Long<br />
Dim lngGroßeGanzzahl&<br />
Dim sngKleineFließkommazahl As Single<br />
Dim sngKleineFließkommazahl!<br />
Dim dblGroßeFließkommazahl As Double<br />
Dim dblGroßeFließkommazahl#<br />
Für die folgenden Deklarationen gibt es keine Suffixe:<br />
Dim byteOktett As Byte<br />
Dim bWahrheitswert As Boolean<br />
Dim vEinZiemlichBeliebigerInhalt As Variant<br />
3.3.2 Einen Wert zuweisen<br />
Einer Variablen wird ihr Wert mit dem Zuweisungsoperator = zugeordnet.<br />
Als Beispiel erstellen wir die Variable strAnzeigeText und weisen ihr die nachher<br />
mehrfach zu verwendende Zeichenkette “Hello World. I’m the champion!“ zu:<br />
Dim strAnzeigeText As String<br />
strTextteil = “Hello World. I’m the champion!“<br />
Der Name der Variablen, die den Wert aufnimmt, steht links. Der Wert steht immer<br />
rechts.<br />
Will man Variableninhalte ändern, weist man einfach einen neuen Wert zu.
Ausdrücke erstellen und verwenden 45<br />
3.3.3 Auf eine Variable zugreifen<br />
Der Zugriff auf den Wert einer Variablen ist denkbar einfach. Man übergibt an der<br />
Stelle, an der der eigentliche Wert stehen müsste, den Variablennamen. <strong>Das</strong> Programm<br />
sucht sich dann zur Laufzeit die entsprechende Speicherstelle und holt von<br />
dort die hinterlegten Daten.<br />
Zum Beispiel könnten wir mit einem Aufruf von Messagebox den Text ausgeben, der<br />
vorhin in der Variablen strTextteil gespeichert wurde:<br />
Messagebox strTextteil<br />
Komplett dargestellt, würde der Code so ausssehen:<br />
Sub Initialize<br />
Dim strAnzeigeText As String<br />
strAnzeigeText = “Hello World. I’m the champion!“<br />
Messagebox strAnzeigeText<br />
End Sub<br />
Achtung<br />
Wenn man eine Variable im Programm anspricht, deren Datentyp mit einem<br />
Suffix angegeben wurde, dann kann man das Suffix als Namensbestandteil<br />
gebrauchen, muss es aber nicht tun. Im nächsten Beispiel werden Sie beide<br />
Möglichkeiten nebeneinander sehen.<br />
Allerdings sollten Sie sich <strong>für</strong> eine davon entscheiden. Nichts ist unübersichtlicher,<br />
als wenn man solche Verfahrensweisen mitten im Code ändert! Die<br />
Mischung zeige ich hier nur einmal, um die Gleichwertigkeit zu veranschaulichen.<br />
Wenn eine Variable ohne Suffix deklariert wurde, dann muss sie in der Folge<br />
auch ohne Suffix verwendet werden.<br />
3.4 Ausdrücke erstellen und verwenden<br />
Jetzt möchten wir die Variable wie bereits angedeutet nutzen, um mehrere ähnlich<br />
lautende Ausgaben mit Messagebox zu machen, ohne die sich wiederholenden Texte<br />
jedes Mal neu hinzuschreiben. Dazu benötigen wir eine Möglichkeit, um zwei Zeichenketten<br />
aneinanderzuhängen, und das ist der Zeichenketten-Operator &.<br />
Wir kommen gleich zur Sache und schreiben:<br />
Sub Initialize<br />
Dim strAnzeigeText$<br />
strAnzeigeText$ = “Hello World. I’m the champion!“<br />
IBM SOFTWARE PRESS
46 Einführung in die <strong>LotusScript</strong>-Programmierung<br />
Messagebox strAnzeigeText & “ Gestern!”<br />
Messagebox strAnzeigeText$ & “ Heute!”<br />
Messagebox strAnzeigeText & “ Morgen!”<br />
End Sub<br />
Listing 3.1 So verwenden Sie eine Variable in Verbindung mit dem Zeichenkettenoperator &,<br />
um mehrere ähnliche Texte zu bilden.<br />
Während sich das leicht größenwahnsinnige Progrämmchen immer mehr aufbläht,<br />
wird dreimal Messagebox aufgerufen, und jedes Mal wird vom &-Operator eine<br />
Kombination aus “Hello World. I’m the champion!“ und dem sich ändernden<br />
Anhängsel “ Gestern!“, “ Morgen!“ usw. gebildet und dann als Meldung ausgegeben.<br />
Eine solche Berechnung von Werten nennt man auch Ausdruck. Der Ausdruck lautet<br />
hier im ersten Fall: strAnzeigeText & “ Gestern!”.<br />
Ausdruck<br />
Ein Ausdruck ist eine wie auch immer geartete Berechnung von Werten. Die<br />
Berechnung kann auch unter Einbeziehung von Funktionen und Objekten<br />
erfolgen.<br />
Wenn Sie noch kein so routinierter Programmierer sind, dann wird Ihnen die Definition<br />
etwas schwierig bzw. schwammig vorkommen. Die Frage ist: Wo beginnt ein<br />
Ausdruck, und wo hört er auf? Und zu den Begriffen Funktion und Objekt kommen<br />
wir erst später. Am besten ist es, Sie vergessen das Thema erst einmal wieder. Die<br />
genaue Abgrenzung dieses Begriffs ist in der Praxis des <strong>LotusScript</strong>-Entwicklers<br />
nicht so wichtig. Außerdem wird er immer mal wieder in recht harmlosen Zusammenhängen<br />
auftauchen, und dann wird die genaue Bedeutung ganz nebenbei<br />
immer klarer.<br />
Was Sie allerdings wissen sollten: Fast überall, wo ein Wert oder der Inhalt einer<br />
Variablen benötigt wird, können Sie stattdessen auch einen Ausdruck notieren.<br />
Dieser wird dann automatisch berechnet, und der sich ergebende Wert wird an seiner<br />
Stelle übergeben. <strong>Das</strong> haben Sie gerade gesehen, als wir der Variablen strAnzeigeText<br />
zunächst eine Zeichenkette, dann aber mehrfach einen Ausdruck nach der<br />
Art strAnzeigeText & “ Gestern!” zugewiesen haben.<br />
Hier haben wir eine sehr einfache Berechnung mit Zeichenketten vorgenommen.<br />
Andere Ausdrücke können Berechnungen von Zahlen- und Datumswerten (numerische<br />
Ausdrücke) und von Wahrheitswerten (boolesche Ausdrücke) einschließen.<br />
3.4.1 Numerische Ausdrücke<br />
Beispiel <strong>für</strong> eine Zahlenberechnung:<br />
Dim iErgebnis%<br />
iErgebnis = 10 * 2.5 – 3
Ausdrücke erstellen und verwenden 47<br />
Der Ausdruck ist hier: 10 * 2.5 – 3. Dieser (bzw. sein Wert) wird der Variablen iErgebnis<br />
zugeordnet. Durch die Zuordnung wird der Ausdruck automatisch berechnet.<br />
Hinweis<br />
Unser deutsches Dezimalkomma ist im Englischen ein Punkt und wird so<br />
auch von <strong>LotusScript</strong> gefordert.<br />
Vorrangregeln<br />
Bei der Berechnung von Ausdrücken gelten gewisse Vorrangregeln, die im Bereich<br />
der arithmetischen Berechnungen an den mathematischen Usus angelehnt ist.<br />
Zum Beispiel gilt »Punktrechnung von Strichrechnung«. Der Ausdruck 10 * 2.5 – 3<br />
wird also zunächst zu 25 – 3 und ergibt das Resultat 22.<br />
Wollten wir es anders haben, so müssten wir entsprechende Klammern setzen:<br />
10 * (2.5 – 3) wird ausgewertet zu 10 * (-0.5) und gibt -5.<br />
3.4.2 Boolesche Ausdrücke<br />
Boolesche Ausdrücke werden mit den Wahrheitswerten True und False und den<br />
Operatoren And, Or und Not gebildet:<br />
True And True ergibt True.<br />
True And False ergibt False.<br />
False And True ergibt False.<br />
False And False ergibt True.<br />
Not True ergibt False.<br />
Not False ergibt True.<br />
Natürlich werden die Ausdrücke in der Regel nicht buchstäblich so gebildet wie<br />
hier gezeigt. Statt der einzelnen Wahrheitswerte True und False werden Ausdrücke<br />
übergeben, die diese Werte zurückgeben. Solche Ausdrücke ergeben sich aufgrund<br />
von Vergleichen oder Rückgabewerten von Funktionen. Beispiele:<br />
1 < iWert% AND 1000 > iWert% ermittelt, ob der Wert der Integer-Variablen iWert1 zwischen<br />
1 und 1000 liegt.<br />
IsNumeric(vWert) ermittelt durch die Funktion IsNumeric, ob die Variant-Variable<br />
vWert einen numerischen Wert enthält.<br />
Auch die Ergebnisse von booleschen Ausdrücken lassen sich einer Variablen zuweisen:<br />
Dim bErgebnis As Boolean<br />
bErgebnis = 1 < iWert% AND 1000 > iWert%<br />
IBM SOFTWARE PRESS
48 Einführung in die <strong>LotusScript</strong>-Programmierung<br />
Hinweis<br />
Vor längerer Zeit gab es in <strong>LotusScript</strong> keinen eigenen Datentyp <strong>für</strong> Wahrheitswerte.<br />
Statt Boolean nahm man häufig Integer-Variablen.<br />
In diesem Fall wurde die 0 als False gewertet und jeder andere Wert als True.<br />
Intern wird nach wie vor False mit dem Wert 0 gleichgesetzt und True mit -1.<br />
Sie werden wahrscheinlich noch auf das eine oder andere Script stoßen, in<br />
dem Integer-Werte <strong>für</strong> Wahrheitswerte verwendet werden. Lassen Sie sich<br />
dadurch nicht verwirren. Mit diesem Hintergrundwissen gewappnet, können<br />
Sie mit diesen Werten praktisch genauso rechnen, als würden »echte« Wahrheitswerte<br />
vorliegen.<br />
Vorrangregeln<br />
Auch bei booleschen Ausdrücken gelten gewisse Vorrangregeln. So wird zunächst<br />
die Negation Not berechnet, dann And und schließlich Or. Auch hier lassen sich die<br />
Regeln durch Klammerungen umgehen.<br />
Not False Or True ‘ergibt True Or True und das ist True<br />
Not (False Or True) ‘ergibt Not True und das ist False<br />
3.5 Eine eigene Prozedur schreiben<br />
Nach dem Erfolg in Abschnitt 3.1, <strong>Das</strong> erste Programm, auf Seite 31, juckt es Sie<br />
sicherlich in den Fingern, etwas mehr zu tun. Als ersten Schritt werden wir eine<br />
eigene Prozedur schreiben und diese dann anschließend von der Prozedur Sub Initialize<br />
aufrufen (ausführen) lassen. Vorher sollten wir noch kurz klären, was eine<br />
Prozedur eigentlich genau ist.<br />
Prozedur<br />
Prozeduren sind benannte Programmteile, die über ihren Namen zum Zwecke<br />
der Ausführung einmal oder mehrmals aufgerufen werden können.<br />
Praktisch gesehen bedeutet diese Definition, dass Sie einen (fast) x-beliebigen Code<br />
nehmen und ihn in eine Prozedur packen können. Dadurch haben Sie die Möglichkeit,<br />
diesen Code aus einem Programm auszulagern und ihn darin mit einem einzigen<br />
Aufruf ausführen zu lassen. Dabei ist es egal, wie lang der Code in der Prozedur<br />
ist. Auch Teile aus einer Prozedur können in weitere Prozeduren ausgelagert werden.<br />
Sie werden dadurch sehr frei in der Gestaltung der Codestruktur. Sie sind gut beraten,<br />
wenn Sie dies zu Ihrem eigenen Vorteil so nutzen, dass eine möglichst klare<br />
Struktur entsteht, die die Logik der zugrunde liegenden Aufgabe gut abbildet.<br />
Wir nehmen an, wir würden es <strong>für</strong> sinnvoll halten, einen Programmteil zu haben,<br />
der bei seinem Aufruf die aktuelle Zeit ausgibt. Der aktuelle Agent ist der Agent, in<br />
dem das gerade ablaufende Script enthalten ist, mithin unser Hello World-Agent.<br />
Die zugehörige Prozedur könnte so aussehen:
Eine eigene Prozedur schreiben 49<br />
Sub ShowTime<br />
Messagebox "Wir schreiben den " & Date & ". Die Uhrzeit ist: " & Time<br />
End Sub<br />
Listing 3.2 Unsere selbst erstellte Prozedur<br />
Dieses kleine Programm arbeitet mit sogenannten Objekten. Wenn Sie damit noch<br />
keine Erfahrung haben, dann denken Sie im Moment noch nicht allzu viel darüber<br />
nach. Ich komme gleich im Abschnitt 3.8, Mit (<strong>Notes</strong>)-Objekten arbeiten, darauf<br />
zurück. Nehmen Sie den Code im Moment einfach so, wie er ist, und konzentrieren<br />
Sie sich eher darauf, wie die Prozedur selbst (sozusagen die Klammer um diesen<br />
Code) erstellt wird.<br />
3.5.1 Die Prozedur anlegen<br />
Die Prozedur wird durch direkte Eingabe in das Programmierfenster rechts vorgenommen.<br />
Dies können Sie an verschiedenen Orten tun.<br />
Zum einen können Sie den Cursor in der Sub Initialize am Ende ganz rechts von<br />
End Sub positionieren, mit [¢] einen Zeilenumbruch erzeugen und Sub ShowTime<br />
hinschreiben (Abbildung 3.18).<br />
Abbildung 3.18 Neue Prozedur durch direktes Hinschreiben erstellen<br />
Anschließend geben Sie mit [¢] noch einen Zeilenumbruch ein. Dabei wird die<br />
zugehörige Kennzeichnung des Endes (End Sub) vom <strong>LotusScript</strong>-Editor automatisch<br />
angelegt und die so erstellte leere Prozedur in ein eigenes Fenster verfrachtet,<br />
das Ihnen sofort angezeigt wird.<br />
Gleichzeitig wird die Prozedur als neuer Programmierabschnitt im Baum links vom<br />
Programmierfenster eingetragen. Wenn Sie die neue Prozedur in Zukunft öffnen<br />
und bearbeiten wollen, wählen Sie einfach ihren Namen im Abschnittsbaum aus<br />
(Abbildung 3.19).<br />
Abbildung 3.19 Darstellung der neuen Prozedur ShowTime im Designer<br />
Jetzt füllen wir die Prozedur ShowTime noch mit Inhalt, indem wir die noch fehlenden<br />
Zeilen <strong>LotusScript</strong> hineinschreiben. Dieser Teil wird auch allgemein als Rumpf<br />
der Prozedur bezeichnet (Listing 3.3: Prozedurrumpf).<br />
IBM SOFTWARE PRESS
50 Einführung in die <strong>LotusScript</strong>-Programmierung<br />
Messagebox "Wir schreiben den " & Date & ". Die Uhrzeit ist: " & Time<br />
Listing 3.3 Prozedurrumpf<br />
3.5.2 Die Prozedur aufrufen<br />
Nun können wir die Sache abschließen. Die Prozedur muss in der Sub Initialize<br />
beim Start des Agenten aufgerufen werden. Die alte Messagebox-Anweisung benötigen<br />
wir nun nicht mehr. Wir ersetzen sie also durch den Aufruf unserer eigenen<br />
Prozedur (Listing 3.4).<br />
Sub Initialize<br />
Call ShowTime<br />
End Sub<br />
Listing 3.4 Aufruf der selbst erstellten Prozedur<br />
Wie Sie sich schon denken können, ist Call die <strong>LotusScript</strong>-Anweisung, mit der Prozeduren<br />
aufgerufen werden können.<br />
Damit sind wir fertig. Der Agent kann gespeichert und geschlossen werden. Lassen<br />
Sie ihn einmal ablaufen, damit Sie die Früchte unserer gemeinsamen Arbeit genießen<br />
können, bevor wir den Prozedurrumpf aus Listing 3.3 besprechen.<br />
Abbildung 3.20 Die Meldung aus unserer selbst erstellten Prozedur<br />
3.5.3 Funktionen<br />
Prozeduren können Werte zurückgeben, die wie ein Ausdruck an Variablen zugewiesen<br />
oder im Rahmen von Berechnungen weiter ausgewertet werden können.<br />
Solche Prozeduren nennt man Funktionen. Sie werden mit dem Schlüsselwort<br />
Function statt mit Sub angelegt.<br />
Wir können die Prozedur ShowTime so umformulieren, dass sie den Text zurückgibt,<br />
anstatt ihn anzuzeigen. Wir nennen die entstehende Funktion ihrer Arbeitsweise<br />
gemäß GetTime:<br />
Function GetTime As String<br />
Dim strTimeText$<br />
strTimeText = "Wir schreiben den " & Date & _<br />
". Die Uhrzeit ist: " & Time<br />
GetTime = strTimeText<br />
End Function<br />
Listing 3.5 Die zur Funktion mutierte Prozedur aus Listing 3.4
Eine eigene Prozedur schreiben 51<br />
Hier fallen zwei Dinge auf. Erstens erhält der Funktionsname mit As String einen<br />
Zusatz wie bei einer Variablendeklaration. Damit wird der Datentyp der Rückgabe<br />
angegeben. Je nach Rückgabewert sind natürlich auch andere Deklarationen denkbar,<br />
wie Integer, Variant usw.<br />
Zweitens sehen Sie in der letzten Zeile der Funktion, dass der berechnete Wert aus<br />
strTimeText dem Namen der Funktion zugewiesen wird. Dadurch erfährt sie, welchen<br />
Wert sie ausgeben soll.<br />
Möchten wir den Wert der Funktion von unserem Agenten ausgeben lassen, so<br />
müssen wir den Aufruf ein wenig umschreiben. Denn wir müssen ja den Rückgabewert<br />
»abholen« und dann zur Ausgabe bringen:<br />
Sub Initialize<br />
Messagebox GetTime<br />
End Sub<br />
Listing 3.6 Der Aufruf von GetTime<br />
Wir können den Rückgabewert auch erst einer Variablen zuweisen und dann weitere<br />
Berechnungen vornehmen:<br />
Sub Initialize<br />
Dim strTime$<br />
Dim strPrefix$<br />
}<br />
Hinweis<br />
Es gehört zum guten Programmierstil, diese Zuweisung erst zum Schluss zu<br />
tätigen.<br />
Natürlich könnte man bei dieser kurzen Berechnung statt der Variablen str-<br />
TimeText gleich den Ausdruck zuweisen. <strong>Das</strong> wäre in diesem Fall in Ordnung,<br />
da die Zuweisung auch dann ja am Ende erfolgen würde. Die vorgenommene<br />
strikte Trennung ist aber am übersichtlichsten und soll Ihnen den Grundsatz<br />
vor Augen führen.<br />
Theoretisch kann man den Funktionsnamen sogar wie eine lokale Variable<br />
behandeln und ihren Inhalt zwischendurch abfragen, verarbeiten und erneut<br />
zuweisen. Davon ist aber auf jeden Fall abzuraten.<br />
strPrefix = {Der Agent sagt:<br />
strTime = GetTime<br />
Messagebox strPrefix & strTime<br />
End Sub<br />
Listing 3.7 Berechnung mit dem Rückgabewert von GetTime<br />
IBM SOFTWARE PRESS
52 Einführung in die <strong>LotusScript</strong>-Programmierung<br />
Wenn Sie die Erstellung des ersten Textteils (strPrefix) betrachten, wird Ihnen auffallen,<br />
dass die Zeichenkette diesmal nicht von Anführungszeichen, sondern von<br />
geschweiften Klammern umrandet ist und sich in die übernächste Zeile erstreckt.<br />
<strong>Das</strong> hat den Grund, dass wir einen doppelten Zeilenumbruch <strong>für</strong> die Ausgabe<br />
benötigen. Anstatt ihn mit den betriebssystemspezifischen Zeichen zu kodieren,<br />
schreiben wir ihn einfach hin. <strong>Das</strong> geht aber nur mit geschweiften Klammern (oder<br />
mit der noch verbleibenden Alternative, den senkrechten Strichen ||). Die Ausgabe<br />
sehen Sie in Abbildung 3.21.<br />
Abbildung 3.21 Anzeige des verarbeiteten Rückgabewertes der Funktion GetTime<br />
3.5.4 Parameter und Programmverzweigungen<br />
Allen Prozeduren können Parameter übergeben werden. Mit diesen steuern Sie das<br />
Verhalten der Prozedur.<br />
Parameter<br />
Parameter sind Variablen, die im Prozedurkopf angegeben werden (also in der<br />
Zeile, in der der Prozedurname steht). Parameter stehen innerhalb der Prozedur<br />
wie lokale Variablen zur Verfügung. Sie können abgefragt und bearbeitet<br />
werden.<br />
Wenn eine solche Prozedur aufgerufen wird, dann muss ihr <strong>für</strong> jeden Parameter ein<br />
Wert mitgegeben werden.<br />
Die Funktion GetTime gibt bislang nur deutsche Texte aus. Wenn wir in einem internationalen<br />
Umfeld arbeiten, dann benötigen wir wahrscheinlich auch eine englische<br />
Ausgabe. Um nicht <strong>für</strong> jede Sprachausgabe eine eigene Funktion schreiben<br />
zu müssen, parametrisieren wir sie und übergeben ein Kürzel, das sie anweist, eine<br />
deutsche oder eine englische Ausgabe zu generieren.<br />
Function GetTime(in_strLanguage As String) As String<br />
Dim strTimeText$<br />
If in_strLanguage = “de” Then<br />
strTimeText = "Wir schreiben den " & Date & _<br />
". Die Uhrzeit ist: " & Time<br />
Else<br />
strTimeText = "Today it is the " & Date & _<br />
". Current time: " & Time<br />
End If
Eine eigene Prozedur schreiben 53<br />
GetTime = strTimeText<br />
End Function<br />
Listing 3.8 Die parametrisierte Funktion zur Ausgabe von verschiedenen Sprachen<br />
Sie sehen, dass Parameter fast wie Variablen deklariert werden. Sie werden hinter<br />
dem Prozedurnamen als Liste aufgeführt und von runden Klammern umschlossen.<br />
Die Liste wird durch Kommata getrennt. Da wir nur einen Parameter benötigen, ist<br />
natürlich kein Komma zu sehen. Statt der Deklaration mit As String hätten wir<br />
auch hier das Suffix $ verwenden können.<br />
Im Funktionsrumpf wird der Parameter in_strLanguage von einer If...Then...<br />
Else...End If-Konstruktion ausgewertet. Dieses stellt eine bedingte Verzweigungsanweisung<br />
dar. Wenn die Bedingung hinter If den Wahrheitswert True ergibt, dann<br />
werden die unmittelbar folgenden Anweisungen bis zum Else abgearbeitet. Ergibt<br />
die Bedingung False, dann wird der Else-Zweig benutzt. Danach wird die Verarbeitung<br />
nach der End If-Klausel fortgesetzt.<br />
Der Parameter muss nun beim Aufruf durch die Sub Initialize-Prozedur mitgegeben<br />
werden. Da wir nicht wissen, welche Sprache der Aufrufer spricht, überlassen<br />
wir ihm die Auswahl. Dazu verwenden wir einen einfachen Eingabedialog, den<br />
<strong>LotusScript</strong> mit InputBox zur Verfügung stellt.<br />
Sub Initialize<br />
Dim strTime$<br />
Dim strPrefix$<br />
Dim strLanguage$<br />
strLanguage = Inputbox("Chose/Wählen Sie aus: English – en or German - de", "Sprachauswahl",<br />
"de")<br />
}<br />
Hinweis<br />
Dem Namen habe ich ein in_ vorangestellt. <strong>Das</strong> ist nicht zwingend, genauso<br />
wie das Präfix str nicht zwingend ist, aber einen guten Programmierstil ausmacht.<br />
<strong>Das</strong> Präfix in_ ist sehr praktisch, weil Sie dadurch besonders innerhalb<br />
von längeren Prozeduren den Überblick darüber behalten, welche Werte als<br />
Parameter »von außen geliefert wurden« und welche in lokalen Prozedurvariablen<br />
vorliegen.<br />
strPrefix = {Der Agent sagt:<br />
strTime = GetTime(strLanguage)<br />
Messagebox strPrefix & strTime<br />
End Sub<br />
Listing 3.9 Sprachabhängigkeit von GetTime durch Parametrisierung<br />
IBM SOFTWARE PRESS
54 Einführung in die <strong>LotusScript</strong>-Programmierung<br />
InputBox ist eine eingebaute Funktion der Sprache <strong>LotusScript</strong>. Auch sie wird durch<br />
Parameter gesteuert. Die erste Zeichenkette teilt dem Benutzer mit, was von ihm<br />
erwartet wird. Die zweite wird als Fenstertitel verwendet. Und die dritte (“de“) wird<br />
als Vorgabe oder Vorschlag schon in die Eingabezeile geschrieben.<br />
Wir haben die Bedingung in der Funktion GetTime so gewählt, dass bei der Übergabe<br />
von “de“ die deutsche Version ausgegeben wird und bei allen anderen die englische.<br />
<strong>Das</strong> macht unsere Funktion fehlerfest, »robust«, wie man in der Programmierung<br />
sagt. Es wird also auch dann ein sinnvolles Ergebnis geliefert, wenn der<br />
Benutzer irgendwelchen Unsinn übergibt oder eine Sprache, die die Funktion nicht<br />
kennt.<br />
Zur Programmierung von Verzweigungen gibt es noch andere Möglichkeiten, wie<br />
es auch verschiedene Schleifen zum wiederholten Durchlaufen eines Codes gibt.<br />
Mehr dazu finden Sie im Abschnitt 4.7, Ablaufsteuerung – Verzweigungen und Schleifen,<br />
ab Seite 167.<br />
3.6 Den Debugger verwenden<br />
Der Debugger ist eine visuelle Hilfe, um Programme Schritt-<strong>für</strong>-Schritt ablaufen zu<br />
lassen und den Fortgang der Berechnungen und die entstehenden Werte kontrollieren<br />
zu können. Er hilft, Fehler (engl. Bugs) zu finden und zu eliminieren.<br />
Debugger aktivieren<br />
Um den Debugger zu nutzen, muss er vor dem Aufruf eines Agenten oder einer<br />
Routine aktiviert werden, genauer gesagt: vor dem Laden des entsprechenden<br />
Moduls. Bei einem Agenten geschieht das wie gesagt vor dessen Start; bei einer<br />
Maske, einer Ansicht usw., passiert es, bevor dieses Element im Client geöffnet<br />
wird.<br />
Die Aktivierung erfolgt über WERKZEUGE/DEBUG LOTUSSCRIPT im Menü des Designers.<br />
Wenn links neben dem Menüpunkt ein Häkchen zu sehen ist, dann ist er aktiviert.<br />
Alternativ kann er über ein SmartIcon in der Universal-Leiste aktiviert werden.<br />
Debugger starten<br />
Sobald danach ein Modul geladen und eine seiner Routinen gestart wird, erscheint<br />
das Debugger-Fenster. In Abbildung 3.22 sehen Sie das Fenster <strong>für</strong> den zuletzt<br />
erstellten Agenten.
Den Debugger verwenden 55<br />
Abbildung 3.22 Debugger nach dem Start eines Agenten<br />
<strong>Das</strong> Programm wurde an der ersten ausgeführten Zeile angehalten (das geschieht<br />
immer). Diese wird durch einen kleinen gelben Pfeil markiert. Er zeigt an, welche<br />
Zeile als Nächstes ausgeführt werden wird.<br />
Haltepunkte<br />
Etwas weiter unten sehen Sie einen großen roten Punkt (im Buch ist er natürlich<br />
schwarz). Dieser markiert einen Haltepunkt (engl. Breakpoint).<br />
Sie haben jetzt die Wahl, das Programm einfach weiterlaufen zu lassen oder nur<br />
gezielt den nächsten Schritt auszuführen. Der nächste Schritt würde mit der oben<br />
befindlichen Schaltfläche SCHRITT AUSFÜHREN abgearbeitet. <strong>Das</strong> ist der Code, der<br />
sich in der aktuellen Zeile befindet, an deren Beginn der Pfeil postiert ist. Danach<br />
würde der Pfeil automatisch zur nächsten Zeile weiterrutschen. Manchmal ist es<br />
notwendig, jeden Schritt zu verfolgen; dann wählt man diesen Weg.<br />
Häufig gibt es aber nur eine gewisse Stelle, die näher untersucht werden soll. Dann<br />
setzt man dort einen Haltepunkt und klickt FORTFAHREN an. Auf diese Weise wird<br />
das Programm alle weiteren Schritte abarbeiten, bis es auf diesen oder einen anderen<br />
Haltepunkt stößt. Mit FORTFAHREN würden wir in unserem Beispiel also bei dem<br />
roten Punkt vor der Messagebox-Anweisung landen.<br />
Um einen Haltepunkt zu setzen, bewegt man den blauen Balken (Cursor) auf die<br />
entsprechende Zeile und klickt sie doppelt an oder drückt einmal [F9]. Möchte<br />
man einen Haltepunkt entfernen, so wiederholt man das Ganze zweimal. Wieder-<br />
IBM SOFTWARE PRESS
56 Einführung in die <strong>LotusScript</strong>-Programmierung<br />
holt man es nur einmal, dann wird der Haltepunkt nur deaktiviert. In Abbildung<br />
3.26 sehen Sie ein Beispiel da<strong>für</strong>. Dieser ist zwar vermerkt, aber nicht aktiv, sodass<br />
das Programm dort nicht halten wird. Dennoch können deaktivierte Haltepunkte<br />
über das Fenster BREAKPOINTS angesteuert werden.<br />
In Abbildung 3.22 sehen Sie im unteren Bereich vier Reiter <strong>für</strong> vier verschiedene<br />
Anzeigen. Der obere Reiter ist mit BREAKPOINTS beschriftet. Somit sehen Sie hier die<br />
gesetzten Haltepunkte. In unserem Beispiel ist es nur einer. Die Angaben sagen aus,<br />
dass er in der Routine Initialize in der 13. Zeile gesetzt ist. Wenn Sie mehrere Haltepunkte<br />
gesetzt haben und zu einem bestimmten »hinspringen« möchten, dann<br />
wählen Sie einfach die BREAKPOINTS-Seite und klicken auf den entsprechenden Haltepunkt.<br />
Dies bringt Sie an den gewünschten Ort.<br />
Mit der Anweisung Stop kann man Haltepunkte auch kodieren. Sie haben den Vorteil,<br />
dass sie mit dem Code verbunden sind und mit Bedingungen verknüpft werden<br />
können, beispielsweise so:<br />
...<br />
If strPrefix = “Blödsinn“ Then<br />
Stop<br />
End If<br />
...<br />
Stop-Anweisungen werden allerdings nicht als Haltepunkte auf der Seite BREAK-<br />
POINTS aufgeführt.<br />
Die Haltepunkte werden nur beachtet, wenn das Programm im Debug-Modus läuft.<br />
Außerdem sind die im Designer gesetzten Haltepunkte an die bookmark.nsf des Entwicklers<br />
gebunden (sie werden dort in einem Profildokument hinterlegt). Daher<br />
brauchen sie <strong>für</strong> ein Produktivprogramm nicht entfernt zu werden. Allerdings würde<br />
es keinen guten Eindruck machen, eine Reihe von Stop-Anweisungen zu hinterlassen,<br />
über die dann nachfolgende Entwickler »stolpern«. Sie sollten die Haltepunkte<br />
vor der Auslieferung Ihres Programms beseitigen.<br />
Inhalte von Variablen prüfen und verändern<br />
Die zweite Seite im unteren Bereich mit der Aufschrift VARIABLEN gibt uns einen<br />
Einblick in die Variablen und ihre Inhalte.<br />
In Abbildung 3.23 sehen Sie die drei Variablen der Initialize-Prozedur. Links<br />
erkennt man die Namen, ganz rechts die Datentypen und in der Mitte die Inhalte.<br />
Man kann den Inhalt von Variablen ändern, sodass nachfolgende Zugriffe mit<br />
angepassten Werten ausgeführt werden.
Den Debugger verwenden 57<br />
Abbildung 3.23 Inhalte der Variablen prüfen und verändern<br />
Als Beispiel führen wir eine Änderung an der Variablen strPrefix aus. Dazu wird die<br />
Variable mit der Maus angeklickt, woraufhin ihr Wert im unteren Feld NEUER WERT<br />
erscheint. Dort schreibt man den neuen Wert einfach hinein.<br />
Möchte man die Änderungen übernehmen, klickt man rechts das grüne Häkchen<br />
an. Sollen sie verworfen werden, klickt man auf das rote Kreuzchen oder geht einfach<br />
ohne Bestätigung des Häkchens weiter (Abbildung 3.24).<br />
Abbildung 3.24 Den Wert einer Variablen ändern<br />
Hier wird der Text “Der Agent sagt: “ umgeändert in “<strong>Das</strong> Programm sagt: “.<br />
Genauso geht man bei Zahlen, Datumswerten, Array-Elementen, Listen-Elementen<br />
und entsprechenden Eigenschaften von Objekten vor.<br />
Manche Eigenschaften von Objekten lassen sich nicht ändern. Dies sind dann<br />
Eigenschaften, die auch in Programmen nur gelesen werden können.<br />
IBM SOFTWARE PRESS
58 Einführung in die <strong>LotusScript</strong>-Programmierung<br />
Ausgabe überwachen<br />
Mit Print getätigte Ausgaben werden im Fenster AUSGABE angezeigt. Im “Hello World“-<br />
Agent wurde dazu noch eine Zeile eingefügt, die einen Text ausgibt (Abbildung 3.25).<br />
Abbildung 3.25 Print schreibt ins AUSGABE-Fenster.<br />
Aufrufe verfolgen und zum Navigieren verwenden<br />
Während weitere Unterroutinen aufgerufen werden, wird der Aufrufstapel verfolgt<br />
und im Fenster AUFRUFE angezeigt (Abbildung 3.26).<br />
Abbildung 3.26 Aufrufstapel verfolgen<br />
Hier sehen Sie einerseits, welche Aufrufe hintereinander getätigt wurden, um an<br />
die momentane Stelle zu gelangen.<br />
Andererseits können Sie durch Anklicken gezielt in eine der »Zwischenstationen«<br />
gelangen. Dabei kommen Sie nicht nur zu der entsprechenden Routine, sondern<br />
sehen im Fenster VARIABLEN auch die dazugehörenden Variablen mit deren aktuellen<br />
Werten.
Eingebaute Funktionen 59<br />
In unserem Beispiel bin ich in der zuletzt aufgerufenen Unterfunktion GetTime<br />
geblieben. Auf dem Stapel wird sie daher als oberste angezeigt (Abbildung 3.26).<br />
Übrigens sehen Sie auch einen deaktivierten Haltepunkt. Dieser ist zwar vermerkt,<br />
aber nicht aktiv, sodass das Programm dort nicht halten wird. Dennoch können<br />
deaktivierte Haltepunkte über das Fenster BREAKPOINTS angesteuert werden.<br />
Die übrigen Schaltflächen<br />
Die Schaltfläche SCHRITT ÜBERSPRINGEN wird verwendet, wenn man den Aufruf einer<br />
Funktion oder Prozedur überspringen möchte, ohne den darin befindlichen Code<br />
zu analysieren.<br />
Die Schaltfläche SCHRITT BEENDEN wird verwendet, wenn man den Aufruf einer<br />
Funktion oder Prozedur beenden möchte, ohne den darin befindlichen Code noch<br />
weiter zu analysieren. Hier ist man also schon hineingesprungen und möchte<br />
schnellstmöglich wieder heraus.<br />
Mit der Schaltfläche STOPPEN wird das Script an sich abgebrochen. In diesem Fall<br />
möchte man also nicht, dass das Programm weiter ausgeführt wird.<br />
Die Schaltfläche DEBUGGER SCHLIESSEN bricht das Programm ebenfalls ab. Sie deaktiviert<br />
aber gleichzeitig den Debugger, sodass folgende Programmaufrufe wieder<br />
normal ausgeführt werden.<br />
Navigation zwischen den Modulen und Routinen<br />
Unterhalb der Schaltflächen finden Sie noch die Comboboxen OBJEKT und EREIG-<br />
NIS. Mit diesen können Sie zwischen Modulen, deren Abschnitten und Ereignishandlern<br />
und anderen Routinen hin- und hernavigieren, ohne dass sie aufgerufen<br />
worden sein müssen. Darin unterscheidet sich diese Navigiermöglichkeit vom Aufrufstapel.<br />
3.7 Eingebaute Funktionen<br />
Nun haben wir schon viel über Prozeduren im Allgemeinen und über Funktionen<br />
im Speziellen gesprochen. Diese waren an einen Agenten, also ein <strong>Notes</strong>-Element<br />
gebunden. Gleichzeitig haben wir aber auch, ohne groß darüber nachzudenken,<br />
Funktionen verwendet, die in <strong>LotusScript</strong> fest eingebaut sind: MessageBox, Date, Time,<br />
InputBox.<br />
Die Sprache bietet viele solche Funktionen, die die unterschiedlichsten Dinge tun.<br />
In Kapitel 4, Sprachbefehle – nach Themen, (ab Seite 89) werden sie nach Themen<br />
getrennt im Einzelnen besprochen, sodass Sie je nach Anforderung schnell die<br />
richtigen Befehle finden werden.<br />
Anders als bei den selbst erstellten Prozeduren sind bei vielen <strong>LotusScript</strong>-Funktionen<br />
verschiedene Parameter optional. <strong>Das</strong> heißt, sie können, müssen aber nicht<br />
angegeben werden. Werden sie weggelassen, so setzt <strong>LotusScript</strong> selbst einen Wert<br />
ein, den sogenannten Vorgabewert.<br />
IBM SOFTWARE PRESS
60 Einführung in die <strong>LotusScript</strong>-Programmierung<br />
Folgt auf ausgelassene Parameter kein Parameter mehr, den Sie angeben möchten,<br />
so können Sie diese komplett inklusive Kommata weglassen. Folgt aber noch eine<br />
Wertangabe, so müssen die ausgelassenen Stellen dazwischen fast immer durch<br />
Kommata markiert werden. Nur so kann <strong>LotusScript</strong> erkennen, welchen Parameter<br />
Sie spezifizieren wollten und welche auszulassen sind.<br />
Beispielsweise kann MessageBox bis zu drei Parameter verarbeiten: Anzeigetext,<br />
Optionen und Titel. Wenn Sie nur einen Text anzeigen möchten, dann genügt folgender<br />
Aufruf:<br />
MessageBox “Dieser Text soll angezeigt werden“<br />
Möchten Sie auch einen Titel angeben, aber keine Optionen, dann sieht der Aufruf<br />
so aus:<br />
MessageBox “Dieser Text soll angezeigt werden“, , “Dies ist der Titel“<br />
3.7.1 Zwei Rückgabearten – Variant und String<br />
Viele eingebaute Funktionen existieren in zwei Varianten, deren Namen sich durch<br />
ein $-Suffix unterscheiden, zum Beispiel: Date und Date$. Der Unterschied ist, dass<br />
die Funktionen ohne Suffix das Ergebnis als Variant zurückgeben, während die mit<br />
Suffix einen String ausgeben.<br />
In der praktischen Arbeit werden Sie den Unterschied kaum merken. Daher findet<br />
man auch nur selten <strong>LotusScript</strong>-Code, in dem die Funktionen mit Suffix notiert<br />
werden.<br />
Dementsprechend habe ich auch in diesem Buch darauf verzichtet, jedes Mal beide<br />
Versionen zu erwähnen. Sollten Sie trotzdem unbedingt einen String als Rückgabewert<br />
benötigen und nicht CStr <strong>für</strong> eine Typumwandlung einsetzen wollen, so finden<br />
Sie in der Designer-Hilfe schnell die Information, ob es <strong>für</strong> eine bestimmte<br />
Funktion die Suffix-Version gibt.<br />
3.8 Mit (<strong>Notes</strong>-)Objekten arbeiten<br />
Bis jetzt haben wir noch nicht allzu viel Berührung mit <strong>Notes</strong>-Objekten gehabt.<br />
<strong>Das</strong> einzige war, dass wir einen Agenten als Container <strong>für</strong> unsere <strong>LotusScript</strong>-Programme<br />
genutzt haben. Ansonsten haben wir uns mit der Sprache <strong>LotusScript</strong> an<br />
sich beschäftigt. Da war noch keine Gelegenheit, sich mit der <strong>Notes</strong>/<strong>Domino</strong>-<br />
Umgebung zu beschäftigen.<br />
Im Prinzip sind dies zwei unterschiedliche Dinge. <strong>LotusScript</strong> ist eine Programmiersprache,<br />
die unabhängig von <strong>Notes</strong> existiert. Sie wird auch von anderen IBM<br />
Lotus-Produkten verwendet (zum Beispiel WordPro).<br />
<strong>Notes</strong>/<strong>Domino</strong> ist ein Produkt, in das auch <strong>LotusScript</strong> eingebaut wurde, um dessen<br />
Elemente mit dieser Sprache programmieren zu können. Diese Verbindung<br />
wird durch die sogenannten <strong>Notes</strong>-Klassen oder <strong>Notes</strong>-Objekte hergestellt. Praktisch<br />
gesehen, sind das Programmteile, die in <strong>LotusScript</strong> zusätzlich zur eigentlichen<br />
Sprache zur Verfügung stehen.
Mit (<strong>Notes</strong>-)Objekten arbeiten 61<br />
Bevor wir etwas mehr über Klassen und Objekte auch im allgemeinen Sinne sprechen,<br />
möchte ich Ihnen zunächst kurz die praktische Arbeit damit vorstellen. So<br />
bekommen Sie am schnellsten eine Vorstellung davon, was Klassen und Objekte<br />
<strong>für</strong> Sie als <strong>LotusScript</strong>-Programmierer bedeuten.<br />
3.8.1 Daten aus der aktuellen <strong>Notes</strong>-Sitzung abfragen (Teil 1)<br />
Eine zentrale Klasse <strong>für</strong> die Arbeit mit <strong>Notes</strong>/<strong>Domino</strong> ist <strong>Notes</strong>Session. Mit ihr erhalten<br />
wir Zugang zur aktuellen <strong>Notes</strong>-Sitzung. Man erfährt von ihr, wie der aktuelle<br />
Benutzer heißt (also die <strong>Notes</strong>-ID, mit der Ihr Programm läuft), in welcher Datenbank<br />
sich Ihr Script befindet, ob es auf dem Server oder dem Client läuft usw. Als<br />
kleine Demonstration soll das folgende Programm dienen, das uns verrät, wie der<br />
Agent heißt, in dem unser Script läuft:<br />
Sub Initialize<br />
Dim session As New <strong>Notes</strong>Session<br />
Dim agentThis As <strong>Notes</strong>Agent<br />
Dim strAgentName As String<br />
Set agentThis = session.CurrentAgent<br />
strAgentName = agentThis.Name<br />
Messagebox "Der Name dieses Agenten lautet: " & strAgentName<br />
End Sub<br />
Listing 3.10 Unsere erste Arbeit mit <strong>Notes</strong>-Objekten<br />
Die erste Anweisung lautet Dim session As New <strong>Notes</strong>Session und legt ein <strong>Notes</strong>Session-Objekt<br />
an. Mit Set agentThis = session.CurrentAgent bekommen wir Zugriff auf<br />
den Agenten, in dem das Script läuft, also auf »unseren« Agenten. Sein Name wird<br />
mit agentThis.Name ermittelt und anschließend über die Messagebox ausgegeben.<br />
Sie werden gesehen haben, dass drei neue Dinge aufgetaucht sind: die Anweisung<br />
New innerhalb der Variablendeklaration der ersten Zeile, dann das Schlüsselwort Set<br />
bei der ersten Zuweisung sowie der Punktoperator zwischen session und Current-<br />
Agent bzw. agentThis und Name. Zudem fallen noch die neuen »Datentypen« <strong>Notes</strong>Session<br />
und <strong>Notes</strong>Agent in den Deklarationszeilen auf.<br />
Bevor wir die Angelegenheit Stück <strong>für</strong> Stück durchgehen, benötigen wir noch etwas<br />
Theorie.<br />
3.8.2 Etwas Theorie – Objekte, Methoden und Eigenschaften<br />
Objekt<br />
Objekte sind benannte Programmteile, die sich ein wenig wie die Gegenstände<br />
in der realen Welt verhalten. Sie verfügen über eigene Daten (die Eigenschaften),<br />
die sie unabhängig von anderen Objekten verwalten. Sie haben<br />
Prozeduren (die Methoden), die ihre Aktionsmöglichkeiten ausmachen.<br />
IBM SOFTWARE PRESS
62 Einführung in die <strong>LotusScript</strong>-Programmierung<br />
Wenn Sie diese Definition mit der Definition der Prozedur auf Seite 48 vergleichen,<br />
dann werden Sie feststellen, dass sich die Definitionen ein wenig ähneln. Auch<br />
Objekte bieten also die Möglichkeit, eine bestimmte Menge Code auszulagern und<br />
diese bei Bedarf einfach über den Objektnamen aufzurufen. Dieser Code wird<br />
innerhalb der Klasse wie eine Prozedur formuliert und wird fast genauso mit Call<br />
aufgerufen. Solche Objekt-»Prozeduren« nennt man Methoden.<br />
Darüber hinaus haben Objekte im Allgemeinen sogenannte Eigenschaften. <strong>Das</strong> sind<br />
vereinfacht gesagt Variablen, die diverse <strong>für</strong> das Objekt relevante Daten speichern<br />
und ausgeben können. Eigenschaften werden häufig von Methoden bearbeitet,<br />
geändert und ausgegeben. Bei einem streng objektorientierten Design legt man<br />
sogar Wert darauf, dass auf Eigenschaften nur in Ausnahmefällen direkt zugegriffen<br />
weden kann.<br />
Man könnte auch sagen, dass Objekte eine Zusammenfassung von verschiedenen<br />
Prozeduren mit gemeinsamen Daten darstellen.<br />
Klasse<br />
Eine Klasse ist eine Art Schablone, mit der Objekte beschrieben und erstellt<br />
werden können.<br />
Beim Programmieren wird zunächst eine Klasse deklariert. Wenn man mit ihr<br />
arbeiten möchte, erzeugt man ein Objekt (mit New). Die in <strong>LotusScript</strong> eingebauten<br />
<strong>Notes</strong>-Klassen braucht man natürlich nicht mehr zu deklarieren.<br />
Objekte sind genaue Abbilder ihrer Klasse. Allerdings ist die Klasse nur die »Bauvorschrift«.<br />
Eine Klasse kann in einem Programm nur einmal existieren. Davon abgeleitete<br />
Objekte kann man so viele erstellen, wie man möchte bzw. wie der Arbeitsspeicher<br />
hergibt. Die Objekte sind unabhängig voneinander. Insbesondere ihre<br />
Eigenschaften sind eine »Privatangelegenheit«, in die sich kein anderes Objekt einmischen<br />
sollte. Diesen letzten Punkt kann man zwar durch schlechte Konzeption<br />
und Programmierung umgehen. Man sollte es aber nicht tun, da die Unabhängigkeit<br />
der Objekte voneinander ein wichtiges Merkmal des objektorientierten<br />
Designs (OOD) darstellt.<br />
Diese eher anschauliche Definition wird nicht jeder wissenschaftlichen Betrachtungsweise<br />
standhalten. Aber wir betreiben hier ja auch keine wissenschaftlichen<br />
Forschungen, sondern möchten mit den Objekten arbeiten.<br />
Verlassen wir also die Theorie wieder, und wir wenden uns unserem Beispiel zu.<br />
3.8.3 Daten aus der aktuellen <strong>Notes</strong>-Sitzung abfragen (Teil 2)<br />
Ohne jetzt weiter auf Details einzugehen, stellen wir fest, dass man Objekte offensichtlich<br />
mit der Syntax<br />
Dim ObjektVariable As New KlassenName
Mit (<strong>Notes</strong>-)Objekten arbeiten 63<br />
erzeugen kann. Sobald diese Anweisung abgearbeitet wurde, existiert das Objekt<br />
und kann im Programmcode verwendet werden.<br />
Der Klassenname ist die Bezeichnung <strong>für</strong> die Art des Objekts. In unserem Beispiel<br />
haben wir ein Objekt von der Art <strong>Notes</strong>Session erzeugt.<br />
Damit haben wir ein Objekt, das uns nützliche Auskünfte zur momentanen <strong>Notes</strong>-<br />
Sitzung geben kann. Beispielsweise »weiß« das Objekt, wer der gerade geöffnete<br />
Agent ist. Was es nicht weiß, ist, wie dieser Agent heißt. <strong>Das</strong> weiß er aber natürlich<br />
selbst.<br />
Deswegen haben wir das session-Objekt erst einmal nach dem geöffneten Agenten<br />
»befragt«. Dazu wird die Eigenschaft CurrentAgent mit dem »Punktoperator« angesprochen<br />
(englisch Dot), wobei das Objekt wie eine Variable mit dem Variablennamen<br />
notiert wird:<br />
session.CurrentAgent<br />
Hinweis<br />
Dazu muss man sagen, dass der Objektname in der Tat der Name einer Variablen<br />
ist. Denn beim Erzeugen mit Dim...As New... wurde zunächst eine Variable<br />
mit dem Objektnamen angelegt (hier session), dann wurde das Objekt<br />
erzeugt und im Programmspeicher abgelegt, und anschließend wurde die<br />
Adresse des Objekts in der Variablen abgelegt.<br />
Da wir <strong>für</strong> die Variable den Datentyp einer Klasse bestimmt haben (<strong>Notes</strong>Session),<br />
weiß <strong>LotusScript</strong>, dass es hier nicht einfach den Inhalt, nämlich die<br />
Objektadresse, ausgeben soll. Stattdessen sucht es automatisch das Objekt an<br />
der angegebenen Adresse und wertet dieses aus. <strong>Das</strong>s hier im Hintergrund<br />
Speicheradressen eine Rolle spielen, brauchen Sie als <strong>LotusScript</strong>-Entwickler<br />
im Prinzip nicht zu wissen. Es wird Ihnen aber verständlicher machen,<br />
warum eine Objektzuweisung ein vorangestelltes Set benötigt, während<br />
andere Variablenwerte ohne Set zugewiesen werden.<br />
In der Eigenschaft CurrentAgent befindet sich ein <strong>Notes</strong>Agent-Objekt des gerade laufenden<br />
Agenten, also »unseres« Agenten. <strong>Das</strong> Objekt wurde bereits intern von<br />
<strong>Notes</strong>Session erzeugt. Deshalb können wir es wie gezeigt einfach mit dem Punktoperator<br />
abfragen und benötigen keine zweite New-Anweisung.<br />
Wir weisen das Objekt einer Objektvariablen vom Typ <strong>Notes</strong>Agent zu. Wie schon<br />
gesagt, muss eine Objektzuweisung immer durch ein vorangestelltes Set kenntlich<br />
gemacht werden:<br />
Set agentThis = session.CurrentAgent<br />
Allerdings interessiert uns dieser Agent selbst nicht so sehr, sondern sein Name.<br />
Den erfährt man mit:<br />
strAgentName = agent.Name<br />
IBM SOFTWARE PRESS
64 Einführung in die <strong>LotusScript</strong>-Programmierung<br />
Diese Eigenschaft von <strong>Notes</strong>Agent gibt eine Zeichenkette aus, also einen String-Wert.<br />
Daher können wir sie einfach einer String-Variablen zuweisen (natürlich ohne Set,<br />
das ja nur zur Zuweisung von Objektreferenzen verwendet wird).<br />
Und den Rest kennen Sie ja bereits.<br />
In Verbindung mit <strong>Notes</strong>Session hatten wir also gesehen, wie Objekt-Eigenschaften<br />
gelesen werden. Im folgenden Abschnitt werden wir eine Objekt-Methode verwenden.<br />
3.8.4 Eine Methode des Arbeitsbereichs aufrufen<br />
Eine andere zentrale <strong>Notes</strong>-Klasse ist <strong>Notes</strong>UIWorkspace. <strong>Das</strong> »UI« im Namen deutet<br />
darauf hin, dass diese Klasse mit dem User Interface zu tun hat (also mit der Benutzerschnittstelle<br />
– das sind die Dinge, die man auf dem Bildschirm sieht).<br />
Mit dieser Klasse erhält man Zugriff auf die im UI geöffneten Elemente, z. B. ein<br />
Dokument, eine geöffnete Ansicht usw. Man kann mit ihr Dialogboxen anzeigen<br />
und Masken zur Erstellung von neuen Dokumenten öffnen. Vorhandene Dokumente<br />
können zur Bearbeitung angezeigt werden usw.<br />
Hinweis<br />
Da wir gerade über Dialogboxen sprachen: Sie werden bemerkt haben, dass es<br />
offensichtlich »an zwei Stellen« Dialogboxen gibt, denn wir hatten ja schon<br />
die <strong>LotusScript</strong>-Funktionen MessageBox und InputBox als solche kennengelernt.<br />
Hier zeigt sich wieder die Zweiteilung: einerseits die Sprache <strong>LotusScript</strong> –<br />
andererseits die von <strong>Notes</strong>/<strong>Domino</strong> zusätzlich zur Verfügung gestellten Klassen,<br />
deren Methoden sich hier und da ein wenig mit <strong>LotusScript</strong>-Funktionen<br />
überschneiden.<br />
<strong>Das</strong> ist insbesondere bei den Dialogboxen, der Arbeit mit Dateien und bei<br />
OLE-Objekten der Fall. Bei der Arbeit mit den Klassen werden Sie feststellen,<br />
dass deren Angebote meistens über die Möglichkeiten von <strong>LotusScript</strong> hinausreichen<br />
bzw. anderen Anforderungen genügen. Es hat also beides seine<br />
Berechtigung.<br />
Um zu zeigen, wie Objekt-Methoden verwendet werden, erstellen wir als Beispiel<br />
mit <strong>Notes</strong>UIWorkspace.ComposeDocument ein neues Dokument. Mit dieser Methode können<br />
Sie in irgendeiner zugänglichen Datenbank (auf der Sie Schreibrechte haben)<br />
ein Dokument mit einer der da<strong>für</strong> vorgesehenen Masken erstellen.<br />
Da ich nicht weiß, welche Datenbanken in Ihrer Umgebung zu finden sind, nehmen<br />
wir einfach Ihre Mail-Datei, die ziemlich sicher existieren wird, und erstellen<br />
darin ein neues Memo. Nun weiß ich auch nicht, wie Ihre Mail-Datei heißt. <strong>Das</strong><br />
können wir aber mit <strong>Notes</strong>Database in Erfahrung bringen. Der Code wird wieder in<br />
einen Agenten wie dem “Hello World“-Agenten geschrieben:
Mit (<strong>Notes</strong>-)Objekten arbeiten 65<br />
Sub Initialize<br />
Dim dbMail As New <strong>Notes</strong>Database("", "")<br />
Dim ws As New <strong>Notes</strong>UIWorkspace<br />
'Mail-Datei öffnen, um Server und Pfad ermitteln zu können<br />
Call dbMail.OpenMail()<br />
'Memo-Maske aus Mail-Datei <strong>für</strong> eine neue Mail öffnen<br />
Call ws.ComposeDocument(dbMail.Server, dbMail.FilePath, "Memo")<br />
End Sub<br />
Listing 3.11 Programm zur Erstellung einer neuen Mail<br />
Sie sehen, das Programm ist sehr kurz, und es wird praktisch nur mit <strong>Notes</strong>-Objekten<br />
gearbeitet.<br />
Als Erstes benötigen wir wieder ein <strong>Notes</strong>Database-Objekt. Dies steht <strong>für</strong> Datenbanken<br />
im Hintergrund, also <strong>für</strong> den nicht sichtbaren Teil. Wir möchten gern erfahren,<br />
wo sich die Mail-Datei des Benutzers befindet (also Ihre Mail-Datei, wenn Sie<br />
das Script laufen lassen). Dazu bietet uns die Klasse <strong>Notes</strong>Database die Methode Open-<br />
Mail an. Der Aufruf öffnet die Datenbank nur im Hintergrund, es wird (noch) kein<br />
Fenster sichtbar. Wir nehmen als sicher an, dass Sie eine Mail-Datei besitzen, dass<br />
alles richtig konfiguriert ist und dass Sie Zugriff auf die Datenbank haben. Dann<br />
werden in dem dbMail-Objekt nach dem Aufruf von OpenMail der Server und der<br />
Dateipfad (FilePath) vermerkt sein. Diese Angaben übergeben wir als die ersten beiden<br />
notwendigen Parameter an ComposeDocument. Diese Methode soll auch noch wissen,<br />
welche Maske sie <strong>für</strong> das neue Dokument verwenden soll, und wir geben<br />
»Memo« an. Nach ihrem Aufruf wird ein Fenster mit der Mail-Maske (»Memo«)<br />
sichtbar.<br />
Jetzt können Sie die neue Mail am Bildschirm wie jede andere füllen und absenden.<br />
In diesem Script wurde zweimal eine Objekt-Methode aufgerufen: mit <strong>Notes</strong>Database.OpenMail<br />
eine parameterlose und mit <strong>Notes</strong>UIWorkspace.ComposeDocument eine<br />
andere mit Parametern.<br />
Der Aufruf ist sehr ähnlich wie bei den Prozeduren, die Sie früher kennengelernt<br />
haben, und erfolgte mit Call.<br />
Hinweis<br />
Call kann bei allen Arten von Prozeduraufrufen auch weggelassen werden.<br />
Genauso können die runden Klammern weggelassen werden, wenn keine<br />
Parameter übergeben werden. Aus Call dbMail.OpenMail() würde dann:<br />
dbMail.OpenMail<br />
<strong>Das</strong> sieht aber fast wie die Abfrage einer Eigenschaft aus, und deshalb verwende<br />
ich bei solchen Aufrufen immer Call und setze dann in der Regel auch<br />
die Klammern. Andere entscheiden sich <strong>für</strong> die kürzere Variante. <strong>Das</strong> ist eine<br />
reine Geschmackssache.<br />
IBM SOFTWARE PRESS
66 Einführung in die <strong>LotusScript</strong>-Programmierung<br />
Der Unterschied ist nur, dass wie bei den Eigenschaften der Name der Objektvariablen<br />
davor gesetzt und mit dem Punktoperator verbunden werden muss.<br />
Wenn eine Methode einen Rückgabewert hat, kann die Zuweisung zu einer Variablen<br />
analog zu der Vorgehensweise bei Funktionen erfolgen. Häufig geben die<br />
Methoden Objekte zurück, die dann mit Set zugewiesen werden müssen. Unsere<br />
ComposeDocument-Methode gibt ein <strong>Notes</strong>UIDocument-Objekt zurück, das man <strong>für</strong> weitere<br />
Bearbeitungen nutzen kann. Die Zuweisung könnte so erfolgen:<br />
...<br />
Dim uidoc As <strong>Notes</strong>UIDocument<br />
...<br />
Set uidoc = ws.ComposeDocument(dbMail.Server, dbMail.FilePath, "Memo")<br />
...<br />
Listing 3.12 Hier wird das erstellte Dokument zur weiteren Bearbeitung als <strong>Notes</strong>UIDocument-Objekt<br />
übernommen.<br />
3.8.5 Eigenschaften ändern<br />
Eigenschaften kann man nicht nur abfragen, sie können in manchen Fällen auch<br />
geändert werden.<br />
So können wir zum Beispiel das in Listing 3.12 ergriffene <strong>Notes</strong>UIDocument verwenden,<br />
um sicherzustellen, dass das horizontale Lineal angezeigt wird:<br />
uidoc.Ruler = True<br />
Nicht änderbare Eigenschaften<br />
Es gibt natürlich auch viele Eigenschaften, bei denen eine Änderung nicht sinnvoll<br />
wäre.<br />
Zum Beispiel gibt <strong>Notes</strong>UIDocument.IsNewDoc an, ob das Dokument noch neu ist oder<br />
schon einmal gespeichert wurde. Wenn unser Programm die Eigenschaft später<br />
nach dem ersten Speichern einfach von True auf False setzen könnte, dann würde<br />
sie anschließend offensichtlichen Unsinn enthalten.<br />
Daher sind viele Eigenschaften gegen Änderungen gesperrt. Die Klassenreferenz<br />
gibt Auskunft darüber, welche Eigenschaften änderbar sind und welche nicht.<br />
3.9 Weitere Startpunkte <strong>für</strong> <strong>LotusScript</strong>-Programme<br />
Bis jetzt haben wir nur Agenten programmiert. Um Ihnen eine Richtung aufzuzeigen,<br />
wie Sie Scripts einsetzen können, folgen jetzt ein paar exemplarische Hinweise.<br />
Weitere Möglichkeiten finden Sie bei den einschlägigen Themen weiter hinten<br />
im Buch und in den Beschreibungen der Events (Ereignisse) der UI-Klassen.<br />
Wenn ich jetzt ein paar Eventhandler explizit erwähne, dann sind diese nur ein<br />
kleiner Auszug aus der Liste der programmierbaren Events.
Weitere Startpunkte <strong>für</strong> <strong>LotusScript</strong>-Programme 67<br />
3.9.1 Aktionsschaltflächen<br />
Wenn Sie auf einer Maske, einer Seite oder in einer Aktionsleiste eine Schaltfläche<br />
einbauen, dann kann diese anschließend ähnlich wie ein Agent programmiert werden.<br />
Wenn sich der Fokus auf der Schaltfläche befindet, zeigt sich das Programmierfenster<br />
unten ähnlich wie bei dem Agenten. Auch müssen wir zunächst die<br />
Sprache <strong>LotusScript</strong> auswählen (vorher wird eine Formel angezeigt) und sehen<br />
dann die einzelnen Eventhandler. Bei Schaltflächen gibt es außer den schon<br />
bekannten Sub Initialize und Sub Terminate noch Sub Click und Sub ObjectExecute.<br />
Soll der Button das Programm auf einen Klick hin ausführen, dann ist Sub Click die<br />
richtige Wahl. (Sub Initialize würde beim Laden der Maske und dem damit verbunden<br />
Initialisieren der Schaltfläche aufgerufen, was selten das ist, was wir benötigen).<br />
3.9.2 Masken, Teilmasken und Seiten<br />
Masken weisen eine Fülle von Eventhandlern auf. Seiten haben einige Eventhandler<br />
weniger, weil Seiten nicht gespeichert werden können; sie sind nicht mit einem<br />
Dokument verbunden. Auch Teilmasken verfügen über ähnliche Eventhandler wie<br />
Masken.<br />
Wenn Sie <strong>für</strong> bestimmte Fälle verhindern möchten, dass ein Dokument gespeichert<br />
wird, können Sie die Sub QuerySave-Routine bearbeiten. Sie können darin eine<br />
Prüfung vornehmen und <strong>für</strong> den Fall, dass sie negativ ausfällt, den Parameter Continue<br />
= False setzen. Dann wird die Maske die Speicherung nicht ausführen.<br />
Sollen in der Maske direkt nach dem Öffnen gewisse Aktionen durchgeführt werden<br />
(noch bevor der Benutzer eingreifen kann), so können Sie Sub PostOpen verwenden.<br />
Durch eine Maske können Sie auf die dahinterliegenden Hintergrunddokumente<br />
zugreifen (<strong>Notes</strong>UIDocument.Document) und sie ändern, oder Sie geben bestimmte Texte<br />
mit <strong>Notes</strong>UIDocument direkt in der Maske ein.<br />
Im folgenden Beispiel greifen wir im PostOpen-Eventhandler auf das Hintergrunddokument<br />
zu und geben dessen Universal-ID aus:<br />
Sub Postopen(Source As <strong>Notes</strong>uidocument)<br />
Dim docThis As <strong>Notes</strong>Document<br />
Set docThis = Source.Document<br />
Print docThis.UniversalID<br />
End Sub<br />
Listing 3.13 Zugriff auf das Hintergrunddokument<br />
Wird ein Agent bei geöffneter Maske aufgerufen, so startet man mit einem <strong>Notes</strong>-<br />
UIWorkspace-Objekt, mit dem man als CurrentDocument auf das Vordergrunddokument<br />
Zugriff erlangt und anschließend auf das Hintergrunddokument:<br />
IBM SOFTWARE PRESS
68 Einführung in die <strong>LotusScript</strong>-Programmierung<br />
Sub Initialize<br />
Dim ws As <strong>Notes</strong>UIWorkspace<br />
Dim docThis As <strong>Notes</strong>Document<br />
Set docThis = ws.CurrentDocument.Document<br />
Print docThis.UniversalID<br />
End Sub<br />
Listing 3.14 Zugriff auf das Hintergrunddokument der geöffneten Maske über das <strong>Notes</strong>UIWorkspace-Objekt<br />
3.9.3 Ansichten und Ordner<br />
Ansichten können Sie in zweierlei Hinsicht programmieren. Zum einen können Sie<br />
auch hier Eventhandler mit Programmen füllen, die ausgeführt werden, wenn eine<br />
Ansicht geöffnet oder geschlossen wird, wenn Dokumente ausgewählt und geöffnet<br />
werden usw.<br />
Zum anderen kann auch die Gestaltung von Ansichten mit <strong>LotusScript</strong> verändert<br />
werden. Dazu halten die <strong>Notes</strong>View-Klassen eine Reihe von Möglichkeiten bereit.<br />
Außerdem können Ansichten zum Durchlaufen ihrer Inhalte und zum Suchen<br />
darin verwendet werden.<br />
Die Startpunkte <strong>für</strong> die letztgenannten Aktionen können wiederum in irgendeinem<br />
passenden Eventhandler liegen (in einer Schaltfläche: Sub Click, in einem<br />
Agenten: Sub Initialize usw.).<br />
3.9.4 Datenbanken<br />
Auf das Öffnen und Schließen einer Datenbank kann mit Eventhandlern im sogenannten<br />
DATENBANK-SCRIPT in den DATENBANKRESSOURCEN aus dem Abschnitt ANDERE<br />
reagiert werden. Was man vielleicht weniger vermuten würde, ist, dass hier auch<br />
Eventhandler <strong>für</strong> die Behandlung von Drag&Drop-Operationen verborgen sind.<br />
3.9.5 Gliederungen<br />
Gliederungen können mit den Klassen <strong>Notes</strong>Outline und <strong>Notes</strong>OutlineEntry bearbeitet<br />
werden. Sie können Einträge hinzufügen, entfernen und ihre Ziele verändern.<br />
Die Startpunkte <strong>für</strong> diese Aktionen können in irgendeinem passenden Eventhandler<br />
liegen (in einer Schaltfläche: Sub Click, in einem Agenten: Sub Initialize usw.).<br />
3.10 Bibliotheken erstellen und einbinden<br />
Um große Mengen von <strong>LotusScript</strong>-Code sinnvoll zu strukturieren, bietet es sich<br />
an, sie in Bibliotheken auszulagern.<br />
Sie finden die vorhandenen Bibliotheken unter GEMEINSAMER CODE/SCRIPTBIB-<br />
LIOTHEKEN. Dort können neue Bibliotheken mit der Aktion NEUE LOTUSSCRIPT BIB-
Bibliotheken erstellen und einbinden 69<br />
LIOTHEK angelegt werden. Geben Sie ihnen sprechende Namen, die die darin abgelegten<br />
Programmteile charakterisieren. Dann ist es später leichter, die darin<br />
befindlichen Codestücke zu finden.<br />
Wenn eine Bibliothek neu angelegt wird, präsentiert sie sich zunächst wie ein noch<br />
leerer Agent (Abbildung 3.27).<br />
Abbildung 3.27 Neu angelegte <strong>LotusScript</strong>-Bibliothek<br />
Zunächst trägt sie den Namen “(unbenannt)“, was man in den Eigenschaften ändert.<br />
Spätestens beim Abspeichern wird man dazu aufgefordert.<br />
Nun wird der auszulagernde Code hier genauso abgelegt wie in anderen Modulen<br />
auch. Nur werden Sie in der Regel die beiden Routinen Sub Initialize und Sub Terminate<br />
unberührt lassen. Die erste kommt nur in Betracht, wenn Sie möchten, dass<br />
beim Laden der Bibliothek gewisse Werte voreingestellt werden, beispielsweise globale<br />
Variablen (die Sie als guter Programmierer hoffentlich nur in Ausnahmefällen<br />
verwenden werden). Sub Terminate kann zum Aufräumen beim Entladen der Bibliothek<br />
verwendet werden können.<br />
Bibliotheken werden mit der Anweisung<br />
Use strLibraryName$<br />
eingebunden. Diese muss im (Options)-Abschnitt eines anderen Moduls, also eines<br />
Agenten, einer Maske oder einer Ansicht usw. aufgeführt werden. Wenn dieses<br />
andere Modul geladen wird, dann wird die Bibliothek automatisch mitgeladen.<br />
Wird das andere Modul entladen, dann wird auch die Bibliothek entladen.<br />
Es können mehrere Use-Anweisungen untereinander geschrieben werden. Außerdem<br />
können Ketten gebildet werden, indem eine Bibliothek eine weitere angibt,<br />
die von ihr selbst geladen wird, usw.<br />
Hinweis<br />
Die Auflösung der verketteten Inhalte ist in der Vergangenheit nicht immer<br />
zuverlässig gewesen. Dies hat sich insbesondere in mysteriösen Fehlern von<br />
Hintergrundagenten bemerkbar gemacht. Deshalb verzichte ich auch heute<br />
noch auf eine Verkettung bzw. führe die verketteten Bibliotheken im ausführenden<br />
Modul (zum Beispiel einem Agenten) lückenlos auf. So kann man<br />
sicher sein, dass der <strong>LotusScript</strong>-Interpreter alle findet.<br />
IBM SOFTWARE PRESS
70 Einführung in die <strong>LotusScript</strong>-Programmierung<br />
Anschließend kann der (öffentliche) Code aus der Bibliothek wie jeder andere verwendet<br />
werden. <strong>Das</strong> heißt, Prozeduren, Funktionen, Klassendefinitionen und<br />
benutzerdefinierte Datentypen können verwendet werden, als wären sie in demselben<br />
Modul geschrieben worden. Es muss nur darauf geachtet werden, dass ein zu<br />
verwendendes Element nicht als Private deklariert wurde.<br />
3.11 Eigene zusammengesetzte Datentypen erstellen<br />
Die Anweisung Type bietet die Möglichkeit, eigene Datentypen zu erstellen. Dies<br />
beschränkt sich allerdings auf die Zusammensetzung anderer vorhandener Datentypen.<br />
Sie können nicht wie in C++ das Verhalten der erstellten Datentypen steuern.<br />
<strong>Das</strong> ist in der praktischen Arbeit mit <strong>LotusScript</strong> auch selten erforderlich. Und<br />
wenn, dann kann man sich mit der Erstellung eigener Klassen behelfen.<br />
Um einen zusammengesetzten Typ zu erstellen, schreibt man die Anweisung Type<br />
in Verbindung mit dem gewünschten Namen des Typs hin. Anschließend notiert<br />
man eine Liste von Elementen, die in dem Typ enthalten sollen. Diese werden wie<br />
Variablen ohne Dim oder Ähnliches notiert. Zum Schluss wird die Deklaration mit<br />
End Type abgeschlossen. Ein Beispiel:<br />
Type Person<br />
Vorname As String<br />
Nachname As String<br />
Geburtsjahr As Integer<br />
Ort As String<br />
End Type<br />
Diese Deklaration muss in den Abschnitt (Declarations) geschrieben werden.<br />
Eine Variable dieses Typs kann man dann im laufenden Code deklarieren wie jede<br />
andere auch. Allerdings muss man bei Zuweisungen und Auswertungen angeben,<br />
welche Elemente man ansprechen möchte. Dazu wird wie beim Ansprechen von<br />
Objekt-Eigenschaften und -Methoden der Punktoperator verwendet.<br />
Als Beispiel sehen Sie eine kleine Prozedur, die die Angaben als Parameter übernimmt<br />
und einer Variablen vom Typ Person zuweist. Anschließend werden die<br />
Daten ausgegeben:<br />
Sub FillPersonRecord(in_strFirstName$, in_strLastName$, in_strCity$,<br />
in_iYearOfBirth%)<br />
Dim tPerson As Person<br />
tPerson.Geburtsjahr = in_iYearOfBirth%<br />
tPerson.Nachname = in_strLastName<br />
tPerson.Vorname = in_strFirstName<br />
tPerson.Ort = in_strCity<br />
Print "Datensatz erzeugt <strong>für</strong> " & tPerson.Vorname & " " tPerson.Nachname<br />
End Sub<br />
Listing 3.15 Variable vom Datentyp Person erstellen und mit Inhalten füllen
Eigene Klassen und Objekte erstellen 71<br />
Führt man den folgenden Aufruf durch, dann kann man das Füllen der Typ-Elemente<br />
beobachten und erhält zum Schluss in der Statuszeile die Information<br />
“Datensatz erzeugt <strong>für</strong> Code Coder“:<br />
Call FillPersonRecord("Code", "Coder", "Kodistan", "1972")<br />
Hier sieht man auch, dass es nicht darauf ankommt, in welcher Reihenfolge die<br />
einzelnen Elemente des selbst erstellten Datentyps angesprochen werden.<br />
Solche Datenstrukturen lassen sich gut verwenden, um zusammenhängende<br />
Daten, auf denen umfangreiche Aktionen ausgeführt werden, sinnvoll zusammenzufassen.<br />
<strong>Das</strong> kann zum Beispiel in der Schnittstellenprogrammierung sehr zur<br />
Erstellung eines gut strukturierten Programms beitragen.<br />
Andere Einsatzgebiete sind die Bearbeitung von Dateien im wahlfreien Zugriffsmodus<br />
oder der Austausch von Daten mit der <strong>Notes</strong> C-API, bei dem oft zusammengesetzte<br />
Datentypen gefragt sind.<br />
3.12 Eigene Klassen und Objekte erstellen<br />
Auch eigene Klassen lassen sich erstellen, deren Objekte wie die Objekte der eingebauten<br />
<strong>Notes</strong>-Klassen verwendet werden können.<br />
Es ist sehr zu empfehlen, umfangreicheren Code nicht nur in Funktionen, sondern<br />
auch in einer Klassenstruktur zu organisieren. Mit ein bisschen Übung ist das ist<br />
nicht viel aufwendiger als das Schreiben von einfachen Prozeduren. Aber es erhöht<br />
die Lesbarkeit und Wartbarkeit Ihrer Programme enorm. Zusatz- und Änderungswünsche,<br />
die im schnellen Geschäftsleben häufig an einen Entwickler herangetragen<br />
werden, lassen sich in einer sinnvollen Klassen- und Objektstruktur häufig viel<br />
leichter und schneller umsetzen.<br />
Um denjenigen, die sich noch nicht so viel mit objektorientierter Programmierung<br />
beschäftigt haben, das Thema etwas verständlicher und schmackhafter zu machen,<br />
möchte ich Ihnen ein kurzes hypothetisches Beispiel vor Augen führen, das die<br />
Arbeitsweise mit Objekten gut veranschaulicht.<br />
Gleichzeitig werde ich Schritt <strong>für</strong> Schritt zeigen, wie in <strong>LotusScript</strong> Klassen<br />
geschrieben und Objekte davon erstellt und verwendet werden.<br />
Wir stellen uns vor, wir würden die Software <strong>für</strong> ein Auto entwickeln, und zwar <strong>für</strong><br />
ein sehr fortschrittliches. In diesem Auto wird fast alles von Software geregelt und<br />
gesteuert, es gibt kaum noch eine direkte Verbindung zwischen den Bedienungselementen<br />
des Cockpits und den ausführenden Teilen wie Lenkung, Motor, Bremsen<br />
usw. – eine Vorstellung, die sich heute bereits nach und nach realisiert.<br />
Wir schreiben also ein Programm, das wir schon mal »Auto« nennen, auch wenn<br />
wir noch nicht so genau wissen, wo wir das Wörtchen Auto dranschreiben sollen.<br />
Interessanter sind jetzt aber erst einmal die Teile. Wir nehmen uns die Lenkung vor.<br />
Wir stellen uns vor, irgendwo im Lenkgestänge befindet sich ein Motor, der in der<br />
Lage ist, per Software Befehle entgegenzunehmen. Die nötigen Befehle lauten:<br />
NachRechtsAusschlagen, NachLinksAuschlagen, GeradeZiehen.<br />
IBM SOFTWARE PRESS
72 Einführung in die <strong>LotusScript</strong>-Programmierung<br />
Jetzt könnten wir <strong>für</strong> jeden dieser Befehle eine Prozedur schreiben, die die damit<br />
verbundenen Aktionen durchführt:<br />
Sub NachRechtsAusschlagen<br />
End Sub<br />
Sub NachLinksAusschlagen<br />
End Sub<br />
Sub GeradeZiehen<br />
End Sub<br />
Wenn der Autofahrer nach rechts abbiegen möchte, ruft er Call NachRechtsAusschlagen<br />
auf, will er nach links, so führt er Call NachLinksAusschlagen aus.<br />
Wir stellen uns jetzt ein noch moderneres Auto vor, ein Auto, in dem die einzelnen<br />
Vorderräder nicht mehr mechanisch miteinander verbunden sind. Jedes Rad wird<br />
getrennt durch Software angesteuert. Auf diese Weise können die Räder schwierigen<br />
Bedingungen viel flexibler angepasst werden, als das mit einer starren Lenkachse<br />
der Fall ist. Jetzt hat jedes Rad einen eigenen Stellmotor. Jedes Rad empfängt<br />
die Befehle Call NachRechtsAusschlagen, Call NachLinksAusschlagen und Call GeradeZiehen.<br />
Natürlich möchte der Fahrer nicht jedem Rad diese Befehle einzeln mitteilen. Es<br />
gibt also ein zentrales Programm, das die Verwaltung übernimmt. Außerdem gibt<br />
es die Aufrufe Call NachRechtsAusschlagen, Call NachLinksAusschlagen und Call Gerade-<br />
Ziehen jetzt sowohl <strong>für</strong> die zentrale Lenksoftware als auch <strong>für</strong> die Rädersoftware.<br />
Und nun beginnt sich abzuzeichnen, dass unsere Lenkung softwaretechnisch<br />
schwierig werden wird. Wir müssen die Prozeduren von Lenksoftware und Rädersoftware<br />
auseinander halten. Also schreiben wir:<br />
Sub LenkungNachRechtsAusschlagen<br />
End Sub<br />
Sub LenkungNachLinksAusschlagen<br />
End Sub<br />
Sub LenkungGeradeZiehen<br />
End Sub<br />
Sub RechtesRadNachRechtsAusschlagen<br />
End Sub<br />
Sub RechtesRadNachLinksAusschlagen
Eigene Klassen und Objekte erstellen 73<br />
End Sub<br />
Sub RechtesRadGeradeZiehen<br />
End Sub<br />
Sub LinkesRadNachRechtsAusschlagen<br />
End Sub<br />
Sub LinkesRadNachLinksAusschlagen<br />
End Sub<br />
Sub LinkesRadGeradeZiehen<br />
End Sub<br />
Alle diese Prozeduren müssen wir ins Hauptprogramm einbinden und dort ansprechen.<br />
(Man könnte natürlich eine Prozedur schreiben, die die Lenkung repräsentiert<br />
und damit die Steuerung der einzelnen Räder vom Hauptprogramm auslagert.<br />
Allerdings würde dadurch das Problem nicht gelöst, dass viele Prozeduren vorhanden<br />
sind, die auch von anderen Programmteilen missbraucht werden könnten.)<br />
So wäre es, wenn wir den sogenannten funktionalen Ansatz wählen würden. <strong>Das</strong><br />
machen wir aber nicht; wir entscheiden uns natürlich <strong>für</strong> die Erstellung von Objekten,<br />
da<strong>für</strong> ist das Kapitel ja gedacht. Wenn wir die erst einmal haben (wir nennen<br />
sie hier schon einmal Lenkung und Rad), dann gestalten sich die Aufrufe sehr einfach:<br />
Call Lenkung.NachRechtsAusschlagen<br />
Call Lenkung.NachLinksAusschlagen<br />
Call RechtesRad.NachRechtsAusschlagen<br />
Call LinkesRad.NachRechtsAusschlagen<br />
Jetzt werden alle beteiligten Objekte ihre eigene Prozedur NachRechtsAusschlagen<br />
haben. Es gibt keine Namenskonflikte mehr, weil die Prozeduren den Objekten als<br />
Methoden fest zugeordnet sind. Die feste Zuordnung bringt es mit sich, dass die<br />
Prozeduren nicht mehr so leicht im falschen Zusammenhang angewendet werden<br />
können. Es müssen keine Namensungetüme zur Unterscheidung der vielen »herumliegenden«<br />
Prozeduren mehr geschaffen werden.<br />
Zunächst schreiben wir eine Klasse, die dann die Vorlage <strong>für</strong> die Räder bildet.<br />
Klassen werden in <strong>LotusScript</strong> mit der Anweisung Class erstellt (im Modul-<br />
Abschnitt (Declarations)):<br />
Class Rad<br />
Sub NachRechtsAusschlagen<br />
End Sub<br />
IBM SOFTWARE PRESS
74 Einführung in die <strong>LotusScript</strong>-Programmierung<br />
Sub NachLinksAusschlagen<br />
End Sub<br />
Sub GeradeZiehen<br />
End Sub<br />
End Class<br />
Mit der Dim-Anweisung können wir dann <strong>für</strong> jedes Rad ein Objekt dieser Klasse<br />
deklarieren:<br />
Dim radVorneRechts As Rad<br />
Dim radVorneLinks As Rad<br />
Soll das rechte Vorderrad nach links lenken, dann lautet der Aufruf:<br />
radVorneRechts.NachLinksAusschlagen<br />
Wenn Ihnen der Vorteil noch nicht ganz einleuchtet, dann haben Sie noch ein<br />
wenig Geduld, es kommt gleich besser.<br />
Es wurde ja bereits festgestellt, dass Objekte eigene Variablen besitzen können, die<br />
sogenannten Eigenschaften. In unserem Beispiel wird sich das gleich als sehr nützlich<br />
erweisen.<br />
Wenn die Software wissen soll, wie ein angeforderter Lenkausschlag umgesetzt werden<br />
soll, dann muss sie eine Information darüber haben, wie der momentane Ausschlag<br />
ist. In einem konventionellen funktionalen Softwaredesign würden wir<br />
diese Werte in einzelnen Variablen festhalten müssen (<strong>für</strong> jedes Rad eine), die dann<br />
an zentraler Stelle gepflegt werden (von der Möglichkeit, statische Variablen zu verwenden,<br />
sehen wir hier einmal ab).<br />
Im objektorientierten Design brauchen wir die Variable nur einmal <strong>für</strong> die Klasse<br />
Rad zu deklarieren, und schon sind zwei Stück verfügbar, <strong>für</strong> jedes der zwei Rad-<br />
Objekte getrennt:<br />
Class Rad<br />
MomentanerLenkausschlag As Integer<br />
...<br />
End Class<br />
Diese Eigenschaft muss jetzt natürlich noch »gefüttert« werden. Wir erstellen dazu<br />
eine Methode SetzeLenkausschlag, die das <strong>für</strong> uns übernimmt (die Eigenschaft ist<br />
nicht mit Public angelegt worden, denn wir möchten ja nicht, dass irgendwelche<br />
anderen Programme Zugriff auf den Lenkausschlag bekommen und zum Sicherheitsrisiko<br />
werden).<br />
Dabei stellen wir fest, dass die Methoden <strong>für</strong> das Rechts-, Links- und Geradeauslenken<br />
sehr verwandt sind. Daher können wir die eigentliche Lenkarbeit der neuen<br />
Methode überlassen, während die übrigen Methoden sie nur mit dem jeweils passenden<br />
Wert aufrufen.<br />
Um uns die Sache einfacher zu machen, gehen wir davon aus, dass es nur drei mögliche<br />
Werte gibt: 1 <strong>für</strong> rechts, -1 <strong>für</strong> links und 0 <strong>für</strong> geradeaus. Wir wollen dem Fah-
Eigene Klassen und Objekte erstellen 75<br />
rer nicht zumuten, sich die Zahlen zu merken, und hinterlegen sie daher in der Rad-<br />
Klasse selbst als entsprechende Eigenschaften. Wir müssen nur da<strong>für</strong> sorgen, dass<br />
sie richtig initialisiert werden. <strong>Das</strong> übernimmt die Methode New (New wird automatisch<br />
aufgerufen, wenn ein Objekt mit New neu angelegt wird):<br />
Class Rad<br />
iMomentanerLenkausschlag As Integer<br />
iRechts As Integer<br />
iLinks As Integer<br />
iGeradeaus As Integer<br />
Sub New()<br />
iRechts = 1<br />
iLinks = -1<br />
iGeradeaus = 0<br />
End Sub<br />
Sub SetzeLenkausschlag(in_iLenkrichtung%)<br />
If Not ((in_iLenkrichtung = iRechts) Or (in_iLenkrichtung = iLinks) Or _<br />
(in_iLenkrichtung = iGeradeaus)) Then Error 1999, “Ungültiger Wert“<br />
iMomentanerLenkausschlag = in_iLenkrichtung<br />
End Sub<br />
Sub NachRechtsAusschlagen<br />
Call SetzeLenkausschlag(iRechts)<br />
End Sub<br />
Sub NachLinksAusschlagen<br />
Call SetzeLenkausschlag(iLinks)<br />
End Sub<br />
Sub GeradeZiehen<br />
Call SetzeLenkausschlag(iGeradeaus)<br />
End Sub<br />
Property Get MomentaneLenkrichtung As String<br />
Dim strReturn$<br />
Select Case iMomentanerLenkausschlag<br />
Case iRechts: strReturn = “Rechts“<br />
Case iLinks: strReturn = “Links“<br />
Case iGeradeaus: strReturn = “Geradeaus“<br />
End Select<br />
End Property<br />
End Class<br />
Mit der zum Schluss hinzugefügten Property Get sorgen wir da<strong>für</strong>, dass die momentane<br />
Lenkrichtung abgefragt werden kann, ohne dass wir die Eigenschaft iMomentanerLenkausschlag<br />
öffentlich zugänglich machen müssten.<br />
IBM SOFTWARE PRESS
76 Einführung in die <strong>LotusScript</strong>-Programmierung<br />
Hinweis<br />
Eine Property (Eigenschaft) verhält sich einerseits wie eine Methode und<br />
andererseits wie eine Zuweisung mit Einbahnstraßencharakter.<br />
In einer Property können alle möglichen Anweisungen wie in einer Methode<br />
ausgeführt werden. Sie kann sogar parametrisiert werden.<br />
Auf der anderen Seite wird sie aber »von außen« wie eine Eigenschaft aufgerufen.<br />
Einer Property Get kann ein Wert zugewiesen werden, und eine Property<br />
Set kann abgefragt werden. Gibt es nur eine davon, dann kann auch<br />
nur die entsprechende Richtung verwendet werden.<br />
Auf diese Weise kann man Eigenschaften programmieren, die nur gelesen,<br />
nur beschrieben oder sowohl gelesen als auch beschrieben werden können.<br />
Jetzt benötigen wir noch das Auto, an dem die Räder befestigt werden. Da es auch<br />
Autos gibt, bei denen alle vier Räder in den Lenkvorgang einbezogen werden, montieren<br />
wir gleich vier. Normalerweise müssten wir natürlich zwei Sorten von<br />
Rädern erstellen:<br />
Class Auto<br />
Räder List As Rad<br />
Sub New()<br />
Set Räder(“VorneRechts”) = New Rad()<br />
Set Räder(“VorneLinks”) = New Rad()<br />
Set Räder(“HintenRechts”) = New Rad()<br />
Set Räder(“HintenLinks”) = New Rad()<br />
End Sub<br />
End Class<br />
Die Montage geschah in Form einer Liste, weil sich das beim Erstellen der zentralen<br />
Lenkvorrichtung als praktisch erweisen wird.<br />
Jetzt erstellen wir die Lenkung. Sie muss alle vier Räder einstellen. Die hinteren<br />
werden gegenläufig eingestellt. Dies erreichen wir durch das Voranstellen eines<br />
einfachen Minuszeichens. Der Wert <strong>für</strong> Geradeaus ist 0, die Negation davon auch;<br />
also können wir immer so vorgehen.<br />
Allerdings ist es praktischer, der Lenkung nur eine einzige Methode zum Lenken<br />
mitzugeben (es gibt ja auch nur ein Lenkrad). Dann muss der Fahrer beim Aufrufen<br />
mitteilen, in welche Richtung er möchte. Damit er das in sprechender Weise tun<br />
kann, bieten wir im die drei Eigenschaften RECHTS, LINKS und GERADEAUS an.<br />
Dazu werden entsprechende Properties erstellt. Wir können sie auch intern verwenden,<br />
wodurch wir uns die Variablen sparen, die wir <strong>für</strong> die Räder angelegt und<br />
in New initialisiert haben.<br />
Die Lenkung muss natürlich mit den Rädern in Verbindung stehen, also sehen wir<br />
vor, die Räderliste bei Erstellung des Objekts zu übergeben und intern eine Referenz<br />
festzuhalten. Diese wird dann beim Lenkvorgang abgearbeitet.
Eigene Klassen und Objekte erstellen 77<br />
Class Lenkung<br />
iMomentanerLenkausschlag As Integer<br />
lstobRäder As Variant<br />
Sub New(in_lstobRäder As Variant)<br />
lstobRäder = in_lstobRäder<br />
End Sub<br />
Sub Lenken(in_iLenkrichtung%)<br />
If Not ((in_iLenkrichtung = RECHTS) Or (in_iLenkrichtung = LINKS) Or _<br />
(in_iLenkrichtung = GERADEAUS)) Then Error 1999, “Ungültiger Wert“<br />
lstobRäder(“VorneRechts“).SetzeLenkausschlag(in_iLenkrichtung)<br />
lstobRäder(“VorneLinks“).SetzeLenkausschlag(in_iLenkrichtung)<br />
lstobRäder(“HintenRechts“).SetzeLenkausschlag(- in_iLenkrichtung)<br />
lstobRäder(“HintenLinks“).SetzeLenkausschlag(- in_iLenkrichtung)<br />
iMomentanerLenkausschlag = in_iLenkrichtung<br />
End Sub<br />
Property Get MomentaneLenkrichtung As String<br />
Dim strReturn$<br />
Select Case iMomentanerLenkausschlag<br />
Case RECHTS: strReturn = “Rechts“<br />
Case LINKS: strReturn = “Links“<br />
Case GERADEAUS: strReturn = “Geradeaus“<br />
End Select<br />
End Property<br />
Property Get RECHTS As Integer<br />
RECHTS = 1<br />
End Property<br />
Property Get LINKS As Integer<br />
LINKS = -1<br />
End Property<br />
Property Get GERADEAUS As Integer<br />
GERADEAUS = 0<br />
End Property<br />
End Class<br />
Die Lenkung wird am Auto befestigt:<br />
Class Auto<br />
lstobRäder List As Rad<br />
obLenkrad As Lenkung<br />
Sub New()<br />
Set lstobRäder(“VorneRechts”) = New Rad()<br />
IBM SOFTWARE PRESS
78 Einführung in die <strong>LotusScript</strong>-Programmierung<br />
Set lstobRäder(“VorneLinks”) = New Rad()<br />
Set lstobRäder(“HintenRechts”) = New Rad()<br />
Set lstobRäder(“HintenLinks”) = New Rad()<br />
Set obLenkrad = New Lenkung(lstobRäder)<br />
End Sub<br />
Property Get Lenkrad As Lenkung<br />
Set Lenkrad = obLenkrad<br />
End Property<br />
End Class<br />
Jetzt können wir ein Auto mit New erzeugen, auf das Lenkrad zugreifen und in die<br />
Richtungen lenken, in die wir möchten:<br />
Dim obAuto As New Auto<br />
Call obAuto.Lenkrad.Lenken(obAuto.Lenkrad.RECHTS)<br />
Call obAuto.Lenkrad.Lenken(obAuto.Lenkrad.LINKS)<br />
Call obAuto.Lenkrad.Lenken(obAuto.Lenkrad.GERADEAUS)<br />
Ein Aufruf, und es geht in die Richtung, die wir vorgeben. Die ganzen Interna (wie<br />
viele und welche Räder in welche Richtung gelenkt werden) interessieren uns nicht<br />
– so, wie es sich bei einem richtigen Auto gehört.<br />
Und genauso einfach kann sich Software bedienen lassen. Einige Vorteile dieser<br />
Programmierungsart sind:<br />
Die hohe Anschaulichkeit: <strong>Das</strong> macht das Programmieren einfacher.<br />
Es entwickelt sich auf natürliche Weise eine sinnvolle Architektur.<br />
Es werden wie von allein abgeschlossene Module (die Klassen) erstellt, die sich<br />
einzeln fortentwickeln und warten lassen.<br />
Es bilden sich klare Schnittstellen heraus, was den Überblick und die Austauschbarkeit<br />
fördert.<br />
Es wird eine hohe Wiederverwendbarkeit des Codes und von Codeteilen erreicht.<br />
Aber das war noch nicht alles. Sie werden gleich noch mehr Möglichkeiten zur<br />
Codeoptimierung kennenlernen. Außerdem wird deutlich werden, wie sich ein<br />
objektorientiertes Design mit der Zeit fortentwickeln kann, ohne dass das eigentliche<br />
Program davon betroffen ist. Der Benutzer merkt davon nichts.<br />
Vererbung<br />
Wenn wir also etwas genauer hinsehen, dann entdecken wir gewisse Gemeinsamkeiten<br />
zwischen der Rad-Klasse und der Klasse Lenkung. Beide beschäftigen sich mit<br />
der Lenkung, die eine <strong>für</strong> ein einzelnes Rad, die andere <strong>für</strong> alle Räder. <strong>Das</strong> bringt<br />
eine gewisse Redundanz mit sich, die wir jetzt mithilfe der Vererbung beseitigen.
Eigene Klassen und Objekte erstellen 79<br />
Zunächst erstellen wir eine Klasse, die die gemeinsamen Merkmale aufnimmt. Da<br />
sich der Einsatz der Properties <strong>für</strong> die Lenkrichtungen ganz gut macht, übernehmen<br />
wir diese Idee auch <strong>für</strong> die gemeinsame Klasse. Wir nennen sie Lenkbares-<br />
Objekt:<br />
Class LenkbaresObjekt<br />
iMomentanerLenkausschlag As Integer<br />
Sub Lenken(in_iLenkrichtung%)<br />
If Not ((in_iLenkrichtung = RECHTS) Or (in_iLenkrichtung = LINKS) Or _<br />
(in_iLenkrichtung = GERADEAUS)) Then Error 1999, "Ungültiger Wert"<br />
iMomentanerLenkausschlag = in_iLenkrichtung<br />
End Sub<br />
Property Get MomentaneLenkrichtung As String<br />
Dim strReturn$<br />
Select Case iMomentanerLenkausschlag<br />
Case RECHTS: strReturn = "Rechts"<br />
Case LINKS: strReturn = "Links"<br />
Case GERADEAUS: strReturn = "Geradeaus"<br />
End Select<br />
End Property<br />
Property Get RECHTS As Integer<br />
RECHTS = 1<br />
End Property<br />
Property Get LINKS As Integer<br />
LINKS = -1<br />
End Property<br />
Property Get GERADEAUS As Integer<br />
GERADEAUS = 0<br />
End Property<br />
End Class<br />
Zunächst lassen wir die Rad-Klasse mit Class Rad As LenkbaresObjekt von unserer neu<br />
erstellten Basisklasse LenkbaresObjekt erben und werfen alles raus, was nicht mehr<br />
benötigt wird. Und siehe da, die Klasse Rad wird ziemlich leer, ja sogar ganz leer.<br />
Alles, was sie benötigt, ist bereits in der Basisklasse vorhanden:<br />
Class Rad As LenkbaresObjekt<br />
End Class<br />
Auch die Methode SetLenkausschlag benötigen wir nicht mehr; sie entspricht der<br />
Methode Lenken aus der Basisklasse.<br />
IBM SOFTWARE PRESS
80 Einführung in die <strong>LotusScript</strong>-Programmierung<br />
Hinweis<br />
Theoretisch könnte man die Räder ganz durch Objekte vom Typ LenkbaresObjekt<br />
ersetzen. Aber um die Architektur klar zu gestalten, ist es besser, sie so zu<br />
belassen. Denn die Verwendung von Rad-Objekten ist näher an der Anschauung<br />
als die Verwendung von LenkbaresObjekt. Und umgekehrt wäre es nicht<br />
sehr geschickt, die Klasse LenkbaresObjekt in Rad umzubenennen, denn dann<br />
müssten wir die Klasse Lenkung von der Klasse Rad erben lassen, und auch das<br />
ist nicht sehr anschaulich. Es ist einfach so, dass die Räder und die Lenkung<br />
sehr viel gemeinsam haben, aber dennoch sehr verschieden sind. Wir können<br />
also nur die Gemeinsamkeiten in eine gemeinsame Basisklasse verlagern, aber<br />
nicht sagen, dass die eine Klasse eine direkte Ableitung von der anderen sei.<br />
Dann lassen wir also auch noch die Klasse Lenkung alle Eigenschaften und Methoden<br />
von LenkbaresObjekt erben. Alles, was vererbt wird, kann aus der Klasse Lenkung<br />
entfernt werden. <strong>Das</strong> macht auch sie wesentlich kürzer. Die SetzeLenkausschlag-Aufrufe<br />
in die Rad-Objekte benennen wir dabei in Lenken um.<br />
Class Lenkung As LenkbaresObjekt<br />
lstobRäder As Variant<br />
Sub New(in_lstobRäder As Variant)<br />
lstobRäder = in_lstobRäder<br />
End Sub<br />
Sub Lenken(in_iLenkrichtung%)<br />
If Not ((in_iLenkrichtung = RECHTS) Or (in_iLenkrichtung = LINKS) Or _<br />
(in_iLenkrichtung = GERADEAUS)) Then Error 1999, "Ungültiger Wert"<br />
lstobRäder("VorneRechts").Lenken(in_iLenkrichtung)<br />
lstobRäder("VorneLinks").Lenken(in_iLenkrichtung)<br />
lstobRäder("HintenRechts").Lenken(- in_iLenkrichtung)<br />
lstobRäder("HintenLinks").Lenken(- in_iLenkrichtung)<br />
iMomentanerLenkausschlag = in_iLenkrichtung<br />
End Sub<br />
End Class<br />
Die Methode Lenken haben wir in dieser Klasse neu formulieren müsssen, da sie bei<br />
dieser Klasse eine andere Bedeutung hat als bei den Rädern. Man nennt diese Art<br />
der Neuformulierung Methoden überschreiben. Bei <strong>LotusScript</strong> muss man darauf achten,<br />
dass die Signatur der neu formulierten Methode genau mit der Signatur der<br />
vererbten übereinstimmt (damit sind gemeint: die Art der Prozedur, der Name, der<br />
oder die Parameter und der Rückgabewert). Für diejenigen, die sich mit der objektorientierten<br />
Programmierung auskennen: Methoden von <strong>LotusScript</strong>-Klassen können<br />
überschrieben, aber nicht überladen werden.
Eigene Klassen und Objekte erstellen 81<br />
Für die Erstellung des Auto-Objekts und die Lenkaufrufe ändert sich nichts:<br />
Dim obAuto As New Auto<br />
Call obAuto.Lenkrad.Lenken(obAuto.Lenkrad.RECHTS)<br />
Call obAuto.Lenkrad.Lenken(obAuto.Lenkrad.LINKS)<br />
Call obAuto.Lenkrad.Lenken(obAuto.Lenkrad.GERADEAUS)<br />
Es gibt noch eine Verbesserungsmöglichkeit. Auch diese möchte ich Ihnen nicht<br />
vorenthalten:<br />
Die überschriebene Methode Lenken der Klasse Lenkung könnte einen Teil ihrer Arbeit<br />
der Basisklasse überlassen. Denn die Abprüfung, ob der Parameter zur Lenkrichtung<br />
zulässig ist, ist in beiden gleich, und auch das Festhalten der internen Eigenschaft<br />
iMomentanerLenkausschlag wiederholt sich.<br />
Wir können diese Schritte also entfernen, müssen nur da<strong>für</strong> sorgen, dass zu Beginn<br />
die Methode Lenken aus der Basisklasse aufgerufen wird. Dies geschieht mit dem<br />
doppelten Punktoperator in Verbindung mit dem Namen der Basisklasse, also mit<br />
der Anweisung Call LenkbaresObjekt..Lenken(in_iLenkrichtung):<br />
Class Lenkung As LenkbaresObjekt<br />
lstobRäder As Variant<br />
Sub New(in_lstobRäder As Variant)<br />
lstobRäder = in_lstobRäder<br />
End Sub<br />
Sub Lenken(in_iLenkrichtung%)<br />
Call LenkbaresObjekt..Lenken(in_iLenkrichtung)<br />
lstobRäder("VorneRechts").Lenken(in_iLenkrichtung)<br />
lstobRäder("VorneLinks").Lenken(in_iLenkrichtung)<br />
lstobRäder("HintenRechts").Lenken(- in_iLenkrichtung)<br />
lstobRäder("HintenLinks").Lenken(- in_iLenkrichtung)<br />
End Sub<br />
End Class<br />
Es ist zu empfehlen, sich den Ablauf des Programms mal im Debugger anzusehen.<br />
Dort wird uns als Objekt der obersten Ebene unser Auto-Objekt angezeigt. Gleichzeitig<br />
kann man den Aufbau der Objekte <strong>für</strong> Auto, Lenkung und Räder und die<br />
jeweiligen Zustände ansehen (repräsentiert durch die gemeinsame interne Eigenschaft<br />
iMomentanerLenkausschlag). Dazu habe ich einen Screenshot nach jedem der<br />
vier Vorgänge erstellt, sodass man zumindest den groben Ablauf sehen kann:<br />
IBM SOFTWARE PRESS
82 Einführung in die <strong>LotusScript</strong>-Programmierung<br />
Abbildung 3.28 Objektzustände der Räder und der Lenkung nach Erstellung der Variable obAuto.<br />
Alle Lenkangaben in iMomentanerLenkausschlag stehen auf GERADEAUS (0).<br />
Abbildung 3.29 Die Objektzustände nach dem Rechtslenken. Die Vorderräder stehen auf RECHTS (1).<br />
<strong>Das</strong>selbe trifft auf den in obLenkrad gespeicherten Gesamtzustand zu. Die<br />
Hinterräder stehen auf LINKS (-1). <strong>Das</strong> ist aufgrund des geforderten gegenläufigen<br />
Verhaltens korrekt.<br />
Abbildung 3.30 Die Objektzustände nach dem Linkslenken. Alle Lenkzustände haben sich ins<br />
Gegenteil verkehrt. Auch das ist korrekt.
Gültigkeitsbereiche und Module 83<br />
Abbildung 3.31 Die Objektzustände nach dem Geradeauslenken. Alle Lenkzustände<br />
(iMomemtanerLenkausschlag) sind wieder auf GERADEAUS (0).<br />
3.13 Gültigkeitsbereiche und Module<br />
Variablen haben einen begrenzten Gültigkeitsbereich. Er beginnt mit der Deklaration<br />
und erstreckt sich ab da auf einen der drei möglichen Bereiche Modul, Prozedur<br />
und benutzerdefinierte Klasse bzw. benutzerdefinierter Datentyp.<br />
Prozeduren werden im nächsten Abschnitt ausführlich behandelt. Für diesen<br />
Abschnitt genügt es zu wissen, dass eine Prozedur ein Stück Programmcode ist.<br />
Vielleicht haben Sie bei der Arbeit mit Sub Initialize schon gesehen, dass ein Agent<br />
noch einen weiteren Eventhandler (also eine spezielle Prozedur) hat, nämlich<br />
Sub Terminate. Außerdem sind noch zwei Abschnitte sichtbar: (Options) und (Declarations).<br />
Diese zwei Prozeduren bilden mit den Abschnitten zusammen ein (Programm-)<br />
Modul. Wie Sie im nächsten Abschnitt sehen werden, kann der Entwickler weitere<br />
Prozeduren anlegen. Wenn wir dies im Agenten tun, dann werden sie automatisch<br />
zu diesem einen Modul hinzugefügt.<br />
Andere Module finden wir bei Masken, Ansichten, Datenbanken usw. Module sind<br />
also in der Regel an Gestaltungselemente der Datenbanken gebunden, aber nicht<br />
immer. Eine Ausnahme sind die <strong>LotusScript</strong>-Bibliotheken. Sie stellen eigene<br />
Module dar, die in andere Module hinzugeladen werden können. Zwar werden sie<br />
in gewisser Weise auch als Gestaltungselemente bezeichnet, aber sie sind keinem<br />
»sichtbaren« Teil der Datenbank zugeordnet.<br />
Variablen, die in einer Prozedur deklariert werden, sind bis zum Ende der Prozedur<br />
gültig. Variablen, die in einem Modul deklariert werden, sind innerhalb des<br />
Moduls gültig. Variablen, die innerhalb einer Klasse oder eines benutzerdefinierten<br />
Datentyps deklariert werden, sind innerhalb des Gültigkeitsbereiches der damit<br />
angelegten Variablen gültig.<br />
Modifizierer<br />
Um die Sache nicht zu einfach werden zu lassen, gibt es auch noch die Modifizierer<br />
Public, Private und Static.<br />
IBM SOFTWARE PRESS
84 Einführung in die <strong>LotusScript</strong>-Programmierung<br />
In der Designer-Hilfe werden sie zwar nicht so genannt, sondern einfach als abgewandelte<br />
Schlüsselwörter <strong>für</strong> die Variablendeklaration behandelt (als Ergänzung zu<br />
Dim). Aber sie haben im Prinzip keine andere Funktion, als den Sichtbarkeitsbereich<br />
zu verändern.<br />
Modulebene<br />
In einem Modul kann eine Variable mit einer öffentlichen oder einer privaten<br />
Sichtbarkeit angelegt werden. Im ersten Fall sind die Variablen auch außerhalb des<br />
Moduls sichtbar, im anderen Fall nur innerhalb. Wenn Sie beispielsweise eine<br />
<strong>LotusScript</strong>-Bibliothek zu einem Maskenmodul hinzuladen (mit Use), dann sind<br />
deren Variablen <strong>für</strong> die Maskenprozeduren nur sichtbar, wenn sie in der Bibliothek<br />
als öffentlich deklariert wurden.<br />
Hiermit können wir die beiden Begriffe Gültigkeit und Sichtbarkeit noch etwas<br />
genauer fassen: Beide Modulvariablen sind gültig, solange das Modul geladen ist.<br />
Doch ist die private Modulvariable nur innerhalb des Moduls sichtbar, also zugänglich.<br />
Die öffentliche Variable ist auch außerhalb sichtbar.<br />
Die gleichen Bedingungen gelten <strong>für</strong> die Deklaration von Prozeduren, Klassen und<br />
Typen. Wird eines dieser Elemente mit Private deklariert, so ist es nur innerhalb des<br />
Moduls sichtbar.<br />
Auf diese Weise kann man Teile eines Moduls, die nur intern verwendet werden,<br />
vor dem Zugriff von außen verstecken. Nach außen zeigt man dann nur die Elemente,<br />
die in einem anderen Modul zur Anwendung kommen sollen. Diese kann<br />
man dann als die API des Moduls bezeichnen.<br />
Prozedurebene<br />
Innerhalb von Prozeduren sind Variablen immer nicht-öffentlich. Da man hier<br />
nicht zwischen privat und öffentlich entscheiden kann, gibt es in dieser Hinsicht<br />
nur eine Deklarationsmöglichkeit, und die heißt Dim. Dim legt in diesem Fall eine<br />
private Variable an, auch wenn das Schlüsselwort Private nicht zum Einsatz kommen<br />
kann.<br />
Sie können aber eine andere Modifikation durchführen, die speziell <strong>für</strong> Prozeduren<br />
gilt: Static. Mit Static wird eine statische Variable angelegt. Damit wird die Aufbewahrungsdauer<br />
des zuletzt zugewiesenen Variableninhalts verändert. Normalerweise<br />
ist der Inhalt mit dem Verlassen einer Funktion vergangen. Bei statischen<br />
Variablen wird er hingegen bis zum nächsten Aufruf der Funktion aufbewahrt.<br />
Solange das Modul mit der Funktion geladen ist, wird man also bei jedem Aufruf<br />
den zuletzt zugewiesenen Wert vorfinden.<br />
Elementvariablen von benutzerdefinierten Typen<br />
Die Elemente eines mit Type erzeugten Datentyps (also dessen Variablen) sind<br />
immer öffentlich sichtbar (solange die Variable dieses Datentyps gültig ist). Daher<br />
wird beim Aufruf von Type auch keine Anweisung vor die Deklaration geschrieben,<br />
weder Dim noch Private noch Public oder Static.
Wie geht es nun weiter? 85<br />
Eigenschaften und Methoden von Klassen<br />
Die Eigenschaften von mit Class erzeugten benutzerdefinierten Klassen bzw. der<br />
davon angelegten Objekte (also deren Variablen) sind standardmäßig privat bezüglich<br />
des Objekts. Sie sind also nur innerhalb des Objekts sichtbar. Sollen sie von<br />
außen sichtbar sein, müssen sie Public deklariert werden.<br />
Bei den Methoden (also den in den Klassen enthaltenen Prozeduren) verhält es sich<br />
genau umgekehrt. Sie sind standardmäßig öffentlich sichtbar, können aber mit<br />
Private auf den Innenbereich der Klasse bzw. der von ihr abgeleiteten Objekte<br />
beschränkt werden.<br />
3.14 Wie geht es nun weiter?<br />
Sie sind nun in die Grundzüge der <strong>Notes</strong>/<strong>Domino</strong>-Programmierung mit Lotus-<br />
Script eingeweiht. Sie sind sogar in der Lage, komplexe objektorientierte Programme<br />
mit <strong>LotusScript</strong> zu entwerfen.<br />
Nun werden Sie sich sicherlich Ihren speziellen Aufgaben zuwenden wollen, die Sie<br />
mit <strong>LotusScript</strong> lösen möchten.<br />
Um Ihnen zu helfen, schnellstmöglich die <strong>LotusScript</strong>-Funktionen und <strong>Notes</strong>-Klassen<br />
zu finden, die Ihnen dabei zur Seite stehen, sind die übrigen Ausführungen<br />
nach Themen und Stichworten angeordnet.<br />
Im <strong>LotusScript</strong>-Bereich finden Sie jeweils ein Thema mit einer mehr oder weniger<br />
langen Einführung, in der gezeigt wird, wie es mit den zur Verfügung stehenden<br />
Funktionen bearbeitet werden kann. Anschließend finden Sie dann jeweils die<br />
vollständige Liste der Funktionen, die mit Syntax und eventuellen Besonderheiten<br />
behandelt werden.<br />
Daran schließt sich ein Bereich von Kapiteln an, die einzelne Themen behandeln,<br />
die mit <strong>Notes</strong>-Klassen bearbeitet werden können. <strong>Das</strong> ist aber nicht immer ausschließlich<br />
zu verstehen. Kapitel wie 8, Datumswerte und Zeitangaben, (Seite 325)<br />
und 10, Dateien und Streams, (Seite 375) befassen sich auch sehr ausführlich mit<br />
<strong>LotusScript</strong>-Funktionen.<br />
Daran fügt sich ein großer Bereich an, in dem die <strong>Notes</strong>-Klassen alphabetisch aufgeführt<br />
sind und in der Form einer Referenz besprochen werden.<br />
Sie werden schnell merken, dass die systematische Abhandlung der <strong>LotusScript</strong>-<br />
Funktionen und der <strong>Notes</strong>-Klassen keine einfache Wiederholung der Designer-<br />
Hilfe darstellt. Wo immer es angebracht war, werden zusätzliche Hinweise gegeben,<br />
die Sie auf Fallgruben und praktische Anwendungsmöglichkeiten aufmerksam<br />
machen. Andererseits sind hier zwar meistens, aber nicht immer sämtliche syntaktischen<br />
Hinweise und Wertebereiche aufgeführt, da eben das Geben von praktischen<br />
Hinweisen im Vordergrund steht. Wenn Sie also einen Hinweis vermissen,<br />
dann sollten Sie auch die Designer-Hilfe zu Rate ziehen.<br />
Auch der sorgfältige Index soll Ihnen helfen, schnell Hinweise zu den Themen zu<br />
finden, die Sie interessieren.<br />
IBM SOFTWARE PRESS