Datei: Teil2_Kap02.doc, Seite17 28. Mai 2008 Kapitel 2 II – Grundlagen von VBA Die ersten VBA-Prozeduren erstellen In diesem Kapitel lernen Sie die Bedienung des VBA-Editors kennen den grundsätzlichen Aufbau von Prozeduren die Unterschiede zwischen Sub-Prozeduren und Funktionen wie Sie Parameter in Ihren Prozeduren einsetzen wo sich eigene Prozeduren gut testen lassen welche Alternativen es zu herkömmlichen Prozeduren gibt 2.1 Die Programm-Oberfläche Access 2007 ist ein Datenbank-Management-System, also ein Programm, das es Ihnen erlaubt, effektiv mit Datenbanken zu arbeiten. Zusätzlich enthält es eine integrierte Programmier-Umgebung für VBA (Visual Basic for Applications), mit der die Datenbank gesteuert werden kann. Um diesen VBA-Editor geht es bei der Programmierung mit VBA. Wichtige Komponenten des VBA-Editors Während die Programm-Oberfläche von Access 2007 gegenüber den vorherigen Versionen u. a. durch die Registerkarten erheblich verändert wurde, wird der VBA-Editor zur Eingabe der Prozeduren weiterhin mit herkömmlichen Menüs bedient. Wenn Sie mit dem VBA-Editor noch nicht vertraut sind, schauen Sie sich ihn am besten zuerst einmal gründlich an: 1. Starten Sie Access 2007 und erstellen eine neue, leere Datenbank namens Grundlagen.accdb. Die darin meist automatisch angelegte leere Tabelle Tabelle1 können Sie löschen, denn Sie beginnen zunächst einmal ohne Daten. 17 Lorenz Hölscher: Richtig einsteigen: Access 2007 VBA-Programmierung. Microsoft Press 2008 (ISBN 978-3-86645-210-7) Datei: Teil2_Kap02.doc, Seite18 28. Mai 2008 Kapitel 2 Die ersten VBA-Prozeduren erstellen Abbildung 2.1: Eine neue leere Datenbank anlegen. 2. Klappen Sie auf der Registerkarte Erstellen in der Gruppe Andere mit dem kleinen Pfeil der Schalt- fläche Makro die Liste aus und klicken darin auf Modul. Abbildung 2.2: Fügen Sie ein neues Modul hinzu. 3. Sie befinden sich nun im VBA-Editor und sehen links den Projekt-Explorer mit dem Überblick über alle in der Datenbank enthaltenen Module und rechts im großen Fenster die Code-Ansicht. Abbildung 2.3: Der VBA-Editor mit einem leeren Modul. 18 Lorenz Hölscher: Richtig einsteigen: Access 2007 VBA-Programmierung. Microsoft Press 2008 (ISBN 978-3-86645-210-7) Datei: Teil2_Kap02.doc, Seite19 28. Mai 2008 2.1 Die Programm-Oberfläche Dieser VBA-Editor besteht aus vielen Komponenten, die Sie möglicherweise von anderen WindowsAnwendungen her schon kennen: Menüleiste In der Menüleiste finden Sie alle Befehle, die Sie für das Erstellen, das Ausführen und Symbolleiste Unterhalb der Menüleiste sehen Sie links die Standardsymbolleiste mit zahlreichen Schaltflächen (wie Speichern, Rückgängig, Wiederholen, usw.), die Ihnen sicherlich von anderen Anwendungen her bekannt sind. Wie gewohnt können Sie andere Symbolleisten manuell sichtbar machen: Klicken Sie eine sichtbare Symbolleiste mit der rechten Maustaste an und wählen Sie den Namen der Symbolleiste aus, welche Sie ein- oder ausblenden wollen. Für die bequeme Arbeit kann ich Ihnen hier vor allem die (im Bild rechts schon sichtbare) Symbolleiste Bearbeiten empfehlen, da diese die Symbole zum Kommentieren von Code enthält (rechts neben der Hand). Projekt-Explorer Links im Fenster zeigt der Projekt-Explorer auf der obersten Ebene alle geöffneten Datenbanken an. Hier sehen Sie natürlich die von Ihnen geöffnete Datenbank Grundlagen.accdb. Dort können aber auch noch weitere Dateien erscheinen, nämlich die (Abfrage-, Formular- oder Berichts-)Assistenten, die in Wirklichkeit versteckte Datenbanken sind. Dann finden Sie im Projekt-Explorer beispielsweise zusätzlich eine Datei acwzmain.accde, welche die wesentlichen Assistenten (acwzmain = Access Wizard Main) enthält. Unterhalb der Datei-Ebene listet Access im Projekt-Explorer zukünftig Kategorien wie Module, Klassenmodule und Microsoft Office Access Klassenobjekte auf, wenn sie denn in der Datenbank enthalten sind. Bei letzteren handelt es sich übrigens um den VBA-Code ganz normaler AccessFormulare und -Berichte. Abbildung 2.4: Der Projekt-Explorer mit Beispielen aller Kategorien. Sie können diese gruppierte Darstellung durch Klick auf das Ordner-Symbol im Projekt-Explorer umschalten, ich werde hier allerdings aus Gründen der besseren Übersichtlichkeit die gruppierte Darstellung beibehalten. Code-Fenster Den größten Teil der Ansicht nimmt rechts das Code-Fenster in Anspruch. In ihm findet die eigentliche Programmierung statt, daher verhält es sich weitgehend wie ein spezieller Text-Editor. Sie finden dort schon die Codezeile Option Compare Database eingetragen. Auch wenn im Folgenden der Code ganzer Module abgedruckt wird, werde ich diese Zeile nicht jedes Mal wiederholen. 19 Lorenz Hölscher: Richtig einsteigen: Access 2007 VBA-Programmierung. Microsoft Press 2008 (ISBN 978-3-86645-210-7) II – Grundlagen von VBA die Fehlersuche in Ihren Prozeduren benötigen. Datei: Teil2_Kap02.doc, Seite20 28. Mai 2008 Kapitel 2 Die ersten VBA-Prozeduren erstellen 2.2 Das »klassische« erste Programm erstellen Es ist gute Tradition, dass das erste Programm, das man in einer neuen Programmiersprache erstellt, einfach nur den Text »Hello World« auf dem Bildschirm ausgibt. Wenn das klappt, haben Sie alle notwendigen Handgriffe für ein komplettes Programm korrekt durchgeführt. Ich möchte mich dieser Tradition anschließen, da der Quellcode extrem kurz ist und trotzdem alle wichtigen Elemente enthält. Sein Verständnis ist ein gutes Fundament für das Erstellen weiterer Programme. 1. Klicken Sie unterhalb von Option Compare Database in das Code-Fenster und fügen nach Wunsch mit der Eingabe-Taste noch ein paar Leerzeilen hinzu. 2. Schreiben Sie dort Sub Hallo an den Anfang einer Zeile. 3. Beenden Sie diese Zeile mit der Eingabe-Taste, so dass der VBA-Editor automatisch ein Paar runde Klammern und zwei Zeilen tiefer ein End Sub ergänzt. Damit ist der sogenannte Prozedur-Rumpf fertig, es fehlt nur noch eine auszuführende Anweisung darin. Abbildung 2.5: Eine erste, noch leere Prozedur. 4. Die Einfügemarke blinkt nun in der mittleren leeren Zeile. Wegen der besseren Übersichtlichkeit rücken Sie dort bitte mit der Tabulator-Taste ein und schreiben msgbox dahinter. 5. Sobald Sie danach ein Leerzeichen eingeben, erscheint ein sogenanntes QuickInfo. Dabei handelt es sich um ein kleines gelbes Fenster mit Informationen zur Benutzung dieses Befehls. Das bedeutet vor allem automatisch, dass es den Befehl msgbox tatsächlich gibt. Abbildung 2.6: Das QuickInfo zum Befehl MsgBox. 6. Das QuickInfo zeigt fett markiert dasjenige Argument an, dessen Eingabe jetzt erforderlich ist. Die weiteren Argumente wären durch Komma getrennt und würden dann entsprechend im QuickInfo fett erscheinen. Das Argument Prompt ist ein Text- oder Zeichenketten-Datentyp (was hier aber nirgends ersichtlich ist) und muss angegeben werden. Alle übrigen Argumente dieser Prozedur sind optional und stehen deswegen in eckigen Klammern. 7. Geben Sie nun bitte "Hello world!" mit den Anführungszeichen ein und verlassen die Zeile mit der PfeilUnten-Taste. Benutzen Sie dazu nicht die Eingabe-Taste, denn dann erzeugen Sie nur unnötige Leerzeilen. 20 Lorenz Hölscher: Richtig einsteigen: Access 2007 VBA-Programmierung. Microsoft Press 2008 (ISBN 978-3-86645-210-7) Datei: Teil2_Kap02.doc, Seite21 28. Mai 2008 2.2 Das »klassische« erste Programm erstellen Abbildung 2.7: Die fertige Prozedur. genannte Syntaxprüfung) vor und ändert die Kleinschreibung von msgbox in die vorgegebene MsgBoxSchreibweise. 9. Sollte Ihnen hier ein Fehler unterlaufen, meldet sich der Editor sofort beim Verlassen der Zeile, färbt diese rot und markiert den vermutlich fehlerhaften Teil. Außerdem erscheint eine Meldung mit einer Erläuterung zum Fehler. Abbildung 2.8: Ein provozierter Fehler, denn der Punkt gehört nicht in die Zeile. 10. Wenn alles in Ordnung ist, können Sie dieses Programm oder besser diese Prozedur starten. Dazu klicken Sie irgendwo zwischen Sub und End Sub in den Code und drücken die Taste F5. Die so markierte Prozedur Hallo wird gestartet und Sie sehen das Ergebnis des MsgBox-Befehls. Abbildung 2.9: Das vom MsgBox-Befehl erzeugte Meldungsfenster. 11. Das Meldungsfenster bleibt so lange stehen, bis Sie es durch einen Klick auf OK schließen. Erst dann läuft auch der Code weiter, selbst wenn – wie in diesem Beispiel – keine Anweisungen mehr folgen. 21 Lorenz Hölscher: Richtig einsteigen: Access 2007 VBA-Programmierung. Microsoft Press 2008 (ISBN 978-3-86645-210-7) II – Grundlagen von VBA 8. Der VBA-Editor nimmt nun automatisch eine Prüfung auf korrekte Benutzung aller Befehle (die so Datei: Teil2_Kap02.doc, Seite22 28. Mai 2008 Kapitel 2 Die ersten VBA-Prozeduren erstellen »Hello world!« unter der Lupe Auch wenn dieses kleine Programm nicht viel macht, so sind darin doch viele wesentliche Konzepte der VBA-Programmierung enthalten: Damit eine Prozedur überhaupt erstellt werden kann, braucht sie einen Namen. Dieser muss (innerhalb eines Moduls) eindeutig sein und darf nicht mit einem reservierten Schlüsselwort oder einem schon vorhandenen VBA-Befehl identisch sein. Die Prozedur hat einen sogenannten Rumpf, also die Konstruktion aus Grenzen der von diesem Namen bezeichneten Prozedur angibt. Innerhalb des Prozedur-Rumpfs dürfen beliebig viele Zeilen mit je einem Befehl stehen, auch wenn das eben noch nicht zu sehen war. Eine Prozedur kann durch Markieren des Codes und Drücken der F5-Taste gestartet werden. Alternativ können Sie eine Prozedur auch mit dem Menübefehl Ausführen Sub/Userform ausführen starten. Wenn dann keine ausführbare Prozedur markiert war, erscheint der Dialog aus Abbildung 2.10 mit allen ausführbaren Prozeduren zur Auswahl. Sub ... End Sub, welche die Abbildung 2.10: Der Dialog zur Auswahl einer Prozedur. Damit haben Sie eine eigene Prozedur erstellt und auch erfolgreich aufgerufen. Grundsätzlich wird dieser Ablauf so bleiben, auch wenn es natürlich noch eine Vielzahl an Veränderungen in Details geben wird. Denken Sie jetzt bitte noch daran, das Modul mit dem Befehl Datei/Grundlagen speichern zu sichern. Der wenig sprechende Name Modul1 ist hier ausreichend. Das Modul ist Teil der Grundlagen.accdbDatenbank und daher auch in der Access 2007-Oberfläche im Navigationsbereich zu sehen. 22 Lorenz Hölscher: Richtig einsteigen: Access 2007 VBA-Programmierung. Microsoft Press 2008 (ISBN 978-3-86645-210-7) Datei: Teil2_Kap02.doc, Seite23 28. Mai 2008 Abbildung 2.11: Der Navigationsbereich der Datenbank zeigt das Modul an. Weitere Parameter nutzen Wie Sie vielleicht anhand des QuickInfos schon bemerkt hatten, kennt der MsgBox-Befehl noch weitere Parameter. Manchmal werden diese übrigens auch als Argumente bezeichnet, was dasselbe bedeutet. Die folgenden Parameter des MsgBox-Befehls sind jedoch optional, können also bei Bedarf weggelassen werden. 1. Erstellen Sie bitte im gleichen Modul eine neue Prozedur HalloMitIcon, indem Sie in einer neuen Zeile Sub HalloMitIcon schreiben und mit der Eingabe-Taste bestätigen. 2. In der Prozedur rücken Sie ebenfalls mit der Tabulator-Taste ein und schreiben MsgBox "Hello world!". Bis dahin ist außer dem Namen alles genauso wie im ersten Beispiel. 3. Nun folgt dem ersten Argument aber ein Komma, woraufhin sofort eine Liste der sogenannten IntelliSense-Technik ausklappt. Diese Technik sorgt dafür, dass in der bereitgestellten Liste nur die Parameter (oder bei Bedarf auch Prozeduren, Methoden oder Eigenschaften) angezeigt werden, die an dieser Stelle überhaupt sinnvoll nutzbar sind. 4. Beginnen Sie, die Buchstaben vbi zu tippen. Die Auswahl springt in der Liste an die nächste Posi- tion, die zu diesem Wortanfang passt. Abbildung 2.12: Die IntelliSense-Liste für das zweite Argument. 5. Das so bereits markierte Wort vbInformation wählen Sie nun mit der Tabulator-Taste (nicht mit der Eingabe-Taste, sonst fügen Sie wieder eine ungewollte Leerzeile ein!) aus. Alternativ hätten Sie auch mit der Maus auf dem Eintrag doppelklicken können, aber die Tastatur ist in diesem Zusammenhang sicherlich effektiver. 23 Lorenz Hölscher: Richtig einsteigen: Access 2007 VBA-Programmierung. Microsoft Press 2008 (ISBN 978-3-86645-210-7) II – Grundlagen von VBA 2.2 Das »klassische« erste Programm erstellen Datei: Teil2_Kap02.doc, Seite24 28. Mai 2008 Kapitel 2 Die ersten VBA-Prozeduren erstellen Jetzt ist der Code komplett und Sie können ihn mit der F5-Taste starten. Diesmal enthält das Meldungsfenster ein weißes »i« im blauen Kreis als Symbol. Solche kleinen Symbole werden gelegentlich auch als Icons bezeichnet. Abbildung 2.13: Das Meldungsfenster hat diesmal ein Symbol. Vordefinierte Konstanten Hinter dem Wort vbInformation steckt in Wahrheit eine Zahl, nämlich 64. Diese ist in VBA vordefiniert, aber eigentlich müssen Sie deren Wert gar nicht kennen. Denn eine solche Konstante, wie dies technisch heißt und später noch ausführlich besprochen werden wird, dient gerade der besseren Lesbarkeit des Codes. Auch wenn niemand wüsste, welchen Wert die Konstante vbInformation tatsächlich hat, kann doch jeder sehen, dass in dieser Zeile das Info-Symbol aufgerufen wird. Sie sollten solche vorhandenen Konstanten benutzen, wann immer es möglich ist. Praktischerweise bietet die IntelliSense-Technik diese auch ganz selbstverständlich an und zwar sogar für selbstdefinierte Konstanten, wie Sie später noch sehen werden. Es gibt übrigens verschiedene Arten vordefinierter Konstanten: Konstanten, die allgemein gelten und auch in anderen VBA-Versionen (etwa in Word oder Excel) benutzt werden können, beginnen mit vb als Abkürzung für Visual Basic. Andere Konstanten sind nur in Access definiert und am Präfix ac zu erkennen. Schaltflächen angeben Sie haben sich möglicherweise gewundert, dass das QuickInfo für den hier benutzten zweiten Parameter die Bezeichnung Buttons, also Schaltflächen, angibt, obwohl damit doch ein Symbol erzeugt wurde. Tatsächlich ist das zwar nur ein einziges Argument, welches jedoch trotzdem mehrere Informationen enthalten kann. 1. Erweitern Sie bitte die Prozedur HalloMitIcon so, dass Sie nach der Konstanten vbInformation ein Plus- Zeichen (+) eingeben. Jetzt klappt erneut die IntelliSense-Liste aus und bietet die gleichen Konstanten wie eben an. 2. Geben Sie nach dem +-Zeichen nun als zweite Konstante vbYesNo an. 3. Führen Sie die Prozedur nun mit F5 aus. Sie sehen, dass tatsächlich Schaltflächen verändert wur- den. Während bisher nur die OK-Schaltfläche zu sehen war, erscheinen jetzt stattdessen die beiden Schaltflächen Ja und Nein. 24 Lorenz Hölscher: Richtig einsteigen: Access 2007 VBA-Programmierung. Microsoft Press 2008 (ISBN 978-3-86645-210-7) Datei: Teil2_Kap02.doc, Seite25 28. Mai 2008 2.2 Das »klassische« erste Programm erstellen Abbildung 2.14: Das Meldungsfenster zeigt jetzt zwei Schaltflächen an. 4. Sie können das Argument sogar mit einem weiteren +-Zeichen und beispielsweise der Konstanten vbDefaultButton2 ergänzen, so dass der Code nunmehr wie folgt aussieht: Sub HalloMitIcon() MsgBox "Hello world!", vbInformation + vbYesNo + vbDefaultButton2 End Sub Durch diese Änderung wird im angezeigten Meldungsfenster der Fokus der Standard-Schaltfläche von bisher Ja auf Nein verschoben. Sie sehen das an der punktierten Linie am Rande der Schaltfläche. Das hat zur Folge, dass ein Bestätigen mit der Eingabe-Taste nicht mehr die Ja-, sondern nun die Nein-Schaltfläche auslöst. Abbildung 2.15: Der Fokus für die Standard-Schaltfläche liegt nun auf Nein. Wie Sie sehen, hat dieses Argument doch mit Schaltflächen zu tun. Der mathematische Trick, mit dem hier offensichtlich drei Werte in einer einzigen Zahl übergeben werden können, heißt übrigens »Binärcodierung« und ist wesentlicher Bestandteil dessen, wie ein Computer arbeitet. Wir werden uns daher bei Gelegenheit noch damit beschäftigen. Auch die Auswertung der Schaltflächen muss noch ein wenig warten. Bis dahin sollen Sie erst einmal weitere eigene Prozeduren erstellen und vor allem auch nutzen. Eigene Prozeduren aufrufen Innerhalb Ihrer eigenen Prozedur namens Hallo haben Sie einen vorhandenen VBA-Befehl MsgBox aufgerufen. Sie können selbstverständlich auch selbst erstellte Prozeduren statt der VBA-Befehle nutzen. Wenn Sie beispielsweise an vielen Stellen in Ihrer Datenbank immer wieder eine Meldung zur Version machen wollen, wäre es wenig sinnvoll, dies jedes Mal erneut in aller Ausführlichkeit zu schreiben. 1. Stattdessen erstellen Sie zunächst eine Prozedur MeldeVersion nach dem bisherigen Muster mit fol- gendem Code: 25 Lorenz Hölscher: Richtig einsteigen: Access 2007 VBA-Programmierung. Microsoft Press 2008 (ISBN 978-3-86645-210-7) II – Grundlagen von VBA Es ist übrigens egal, welche der beiden Schaltflächen Sie anklicken, um den Meldungsdialog zu schließen. Da die Prozedur noch keine Auswertung vornimmt, passiert ohnehin nichts. Datei: Teil2_Kap02.doc, Seite26 28. Mai 2008 Kapitel 2 Die ersten VBA-Prozeduren erstellen Sub MeldeVersion() MsgBox "Version 1.0 von Lorenz Hölscher", vbInformation End Sub 2. Sie können diese Prozedur gerne direkt mit der F5-Taste testen und erhalten dann den folgenden Meldungsdialog. Abbildung 2.16: Der Meldungsdialog von MeldeVersion. So weit war es gegenüber den vorherigen Prozeduren nichts Neues. Jetzt soll diese selbstgeschriebene Prozedur aber in anderen Prozeduren aufgerufen werden. Das kann sogar in einem anderen Modul sein, damit es nicht gar zu einfach wird. 1. Schließen Sie das aktuelle Modul Modul1. Wenn sich dessen Code-Fenster im Vollbild befindet, liegt das X-Symbol zum Schließen unterhalb des roten Schließsymbols oben rechts vom VBAEditor selber. 2. Wählen Sie den Befehl Einfügen/Modul, damit Sie ein neues Modul erhalten. 3. Geben Sie dort mit Sub TesteMeldungen eine neue Prozedur ein und bestätigen Sie die Zeile mit der Eingabe-Taste, damit der Prozedur-Rumpf vervollständigt wird. 4. Innerhalb der Prozedur rücken Sie wie immer mit der Tabulator-Taste ein. 5. Beginnen Sie nun den Namen Ihrer eigenen Prozedur zu schreiben, also mel, und drücken Strg+Leertaste. Wenn es mehrere ähnlich beginnende Prozedurnamen gäbe, erschiene nun die IntelliSense-Liste zur Auswahl. Da jedoch bereits der Wortanfang eindeutig war, vervollständigt der VBA-Editor sofort zu MeldeVersion. Abbildung 2.17: Der Code der Prozedur TesteMeldungen. Das war eigentlich schon alles. Sie rufen eigene Prozeduren genau so auf wie vorhandene VBAProzeduren, indem Sie nämlich deren Namen nennen. Wenn diese noch Parameter hätten, würden diese folgen. 6. Jetzt können Sie mit der Eingabe-Taste noch weitere Zeilen anfügen und dort jeweils in einer eige- nen Zeile einmal den Befehl Beep und dann wieder MeldeVersion einfügen. 26 Lorenz Hölscher: Richtig einsteigen: Access 2007 VBA-Programmierung. Microsoft Press 2008 (ISBN 978-3-86645-210-7) Datei: Teil2_Kap02.doc, Seite27 28. Mai 2008 2.2 Das »klassische« erste Programm erstellen Abbildung 2.18: Der erweiterte Code der Prozedur TesteMeldungen. hören Ihren Computer piepsen und sehen dann ein zweites Mal die Versionsmeldung. Möglicherweise ist das Piepsen nur sehr leise oder ganz abgeschaltet, denn das ist von der verwendeten Hardware abhängig und heute oftmals deaktiviert. Sie haben Recht, dass dieser Code noch keinen wirklichen Nutzen hat, denn er soll ja erst einmal nur die grundsätzlichen Prinzipien zeigen. Aber damit haben Sie auch den zweiten Schritt gemacht: Sie haben nicht nur eine eigene Prozedur geschrieben, sondern auch an beliebiger Stelle aufgerufen. Tipp: Einrückung Ich empfehle Ihnen dringend, den VBA-Code immer sauber einzurücken, wie das hier bereits geschehen ist. Dadurch lassen sich Fehlerquellen wie vergessene End-Anweisungen oder falsch geschachtelte If-Blöcke sofort erkennen. Dabei wird in jedem Block eingerückt, also in allen Strukturen, die typischerweise mit einem End-Befehl schließen: Sub/End Sub, Function/End Function, If/End If, Select/End Select oder With/End With. Es gibt noch weitere Blöcke, die das Schlüsselwort End zwar nicht benutzen, aber ebenso eingerückt werden sollten: For/Next und Do/Loop. Prozedurnamen finden Eben war es ja noch ganz einfach, den Namen der selbstgeschriebenen Prozedur zu finden, denn Sie hatten diese kaum zehn Minuten früher erfunden. Bei größeren Projekten wird aber ganz schnell der Fall auftreten, dass Sie Hunderte von Prozeduren in vielen Modulen haben. Dann reicht es zu wissen, in welchem Modul sich eine gesuchte Prozedur befindet. 1. Daher sollten Sie die Prozeduren nicht wie hier wahllos hintereinander in ein Modul schreiben, sondern besser thematisch sortieren. Dann wird es Module für den Datenzugriff, solche für die Dateibearbeitung oder welche für Berechnungen oder Menübefehle geben. Abbildung 2.19: Die Auswahl eines Prozedurnamens anhand einer Modul-IntelliSense-Liste. 27 Lorenz Hölscher: Richtig einsteigen: Access 2007 VBA-Programmierung. Microsoft Press 2008 (ISBN 978-3-86645-210-7) II – Grundlagen von VBA 7. Wenn Sie nun TesteMeldungen mit der F5-Taste starten, sehen Sie zuerst Ihre Versionsmeldung, Datei: Teil2_Kap02.doc, Seite28 28. Mai 2008 Kapitel 2 Die ersten VBA-Prozeduren erstellen 2. Dann schreiben Sie wie in der obigen Abbildung in einem anderen Modul zuerst den Namen des Moduls mit der gesuchten Funktion sowie den folgenden Punkt. Dann klappt auch für Ihre eigenen Prozeduren die IntelliSense-Liste aus und Sie können bequem unter allen Namen auswählen. 3. Wenn Sie wenigstens den Anfang des Namens wissen, drücken Sie alternativ auch ohne vorange- stellten Modulnamen Strg+Leertaste. Daraufhin wird der Name komplett ergänzt, falls er bereits eindeutig ist, oder es erscheint die IntelliSense-Liste zur genaueren Auswahl. Selbst bei kurzen Prozedur- oder Variablennamen empfehle ich diese Technik, damit Sie sicher sind, dass sie richtig geschrieben sind. Funktion statt Sub-Prozedur Während die bisher beispielhaft geschriebene Sub-Prozedur zwar etwas macht, aber nie etwas an den aufrufenden Code zurückmelden kann, ist das bei Funktionen anders. Statt Sub heißt dort das Schlüsselwort Function und über den eigenen Prozedurnamen lässt sich ein Wert an den Aufrufer zurückgeben. Die MsgBox() darf übrigens ebenso als Sub-Prozedur wie auch als Funktion aufgerufen werden und liefert dann auch eine Rückmeldung über die angeklickte Schaltfläche. Dabei ändert sich zwingend die Schreibweise. Eine aufgerufene Sub-Prozedur mit Argument schreibt sich mit einem Leerzeichen nach dem Prozedurnamen: MsgBox "Hallo" Eine Funktion hingegen muss nicht nur runde Klammern um alle Argumente haben, sondern vor allem den Rückgabewert in einer Variablen oder ähnlichem speichern können: varErgebnis = MsgBox("Klappt das?") Wichtig: Unterschiedliche Schreibweise Das ist ein wichtiger Unterschied beim Aufruf einer Prozedur: nach Sub-Namen folgt ein Leerzeichen, nach Function-Namen immer direkt eine runde Klammer! Dabei ist varErgebnis eine derzeit ziemlich beliebige Variable. Das mag jetzt zwar syntaktisch völlig in Ordnung sein, aber Sie sehen den Inhalt der Variablen immer noch nicht. Daher sollten Sie in der vollständigen Prozedur deren Wert anschließend zu Prüfzwecken anzeigen: Sub FrageMitAntwort() varErgebnis = MsgBox("Klappt das?", vbQuestion + vbYesNo) MsgBox "Ausgewählt: " & varErgebnis End Sub Bitte beachten Sie, dass in der ersten Code-Zeile eine MsgBox()-Funktion aufgerufen wurde, deren Rückgabewert in der Variablen varErgebnis zwischengespeichert wird. In der zweiten Zeile hingegen wird MsgBox als Sub-Prozedur ohne Rückgabewert benutzt. Durch den Verkettungs-Operator & werden die beiden Teile, nämlich der Text »Ausgewählt:« sowie der Inhalt der Variablen varErgebnis zu einem gemeinsamen Text zusammengefügt und dann angezeigt. 28 Lorenz Hölscher: Richtig einsteigen: Access 2007 VBA-Programmierung. Microsoft Press 2008 (ISBN 978-3-86645-210-7) Datei: Teil2_Kap02.doc, Seite29 28. Mai 2008 2.2 Das »klassische« erste Programm erstellen Wie Sie ausprobieren können, gibt ein Klick auf Ja den Wert 6 und auf Nein den Wert 7 zurück. Sie mögen überrascht sein, dass nicht die Beschriftungen der Schaltflächen oder ähnliches als Rückgabewert benutzt werden. Diese Version ist aber sprachunabhängig und damit einfacher zu benutzen. Denn erstens steht trotz der eingesetzten Konstanten vbYesNo tatsächlich nicht Yes und No auf den Schaltflächen, sondern in einem deutschsprachigen Windows auch deutschsprachige Bezeichnungen. Zweitens wäre es mehr als lästig, im Code später darauf zu reagieren, dass ein Benutzer Ja, Yes oder Oui angeklickt hat, wenn Sie diese Worte als Texte bekämen. Da ist eine sprachneutrale Zahl als Rückgabewert viel einfacher zu handhaben. Eigene Funktionen So wie Sie eine eigene Sub-Prozedur schreiben können, geht das auch mit einer selbstdefinierten Funktion, nur eben mit Function als Schlüsselwort statt mit Sub. Der wesentliche Unterschied besteht ja darin, dass eine Funktion einen Rückgabewert an das aufrufende Programm zurückliefert und die SubProzedur nicht. Im folgenden Beispiel wird das morgige Datum als Ergebnis ausgegeben: Function Morgen() Morgen = Date + 1 End Function Dabei ist fast zwingend für eine Funktion, dass irgendwann innerhalb des Codes der Name der Funktion selber, hier also Morgen, einen Wert zugewiesen erhält. Das ist der so genannte Rückgabewert. Date ist in diesem Beispiel eine vorhandene VBA-Prozedur, die das Tagesdatum zurückgibt. Da es sich dabei ja um ein serielles Datum handelt, können Sie auf den Wert einfach 1 addieren, um den folgenden Tag zu errechnen. Hintergrund: Serielles Datum Ein Datum wird auf dem Computer in einer Zahl mit Nachkommastellen gespeichert, als sogenanntes serielles Datum. Dort steht eben nicht der tatsächliche Tages- und Uhrzeit-Wert, sondern eine umgerechnete Zahl. Vor dem Komma steht die Anzahl der Tage seit dem 1.1.1900. Der erste Weihnachtstag 2008 ist 39.806 Tage später, hätte also den Wert 39806,0. Das zugehörige Datum kann jedes Programm intern ermitteln, um es Ihnen jederzeit anzuzeigen. Wegen der dahinter stehenden Zahl können Sie zu diesem Wert einfach 14 hinzuzählen, um ein Datum zwei Wochen später zu finden. Das Ergebnis 39820,0 wird Ihnen dann korrekt als 7.1.2009 angezeigt, denn auch Monats- und Jahreswechsel sind dabei immer automatisch berücksichtigt. 29 Lorenz Hölscher: Richtig einsteigen: Access 2007 VBA-Programmierung. Microsoft Press 2008 (ISBN 978-3-86645-210-7) II – Grundlagen von VBA Abbildung 2.20: Die beiden durch FrageMitAntwort erzeugten Meldungen, wenn Ja angeklickt wurde. Datei: Teil2_Kap02.doc, Seite30 28. Mai 2008 Kapitel 2 Die ersten VBA-Prozeduren erstellen Im Nachkomma-Anteil der Zahl ist die Uhrzeit enthalten, und zwar als prozentualer Anteil an den laufenden 24 Stunden. Ein Wert von 0,5 entspricht daher exakt 12:00 Uhr, während 20:15 Uhr als 0,84375 gespeichert würde. Um eine Stunde später zu ermitteln, müssen Sie einfach nur 1/24 addieren. Der Vor- und Nachkomma-Anteil des Wertes zusammen speichert also Tag und Uhrzeit in einer einzigen Zahl, was viel platzsparender ist als etwa die Ziffern in einer Zeichenkette abzulegen. Es gibt allerdings noch einen beim Testen von Funktionen eher lästigen Unterschied: Funktionen lassen sich zwar auch mit der F5-Taste starten, aber ihr Ergebnis erscheint dabei nie. Hilfsweise brauchen Sie also eine Sub-Prozedur, die nur zum Test-Aufruf der Funktion nötig ist: Sub TesteMorgen() MsgBox "Morgen ist: " & Morgen() End Sub Wenn Sie diese Test-Prozedur TesteMorgen starten, erscheint das Dialogfeld aus der folgenden Abbildung. Abbildung 2.21: Eine Meldung, die nur dem Test der Morgen()-Funktion dient. Test im Direktfenster Alternativ können Sie auch ein spezielles Fenster, den Direktbereich, öffnen, um solche kleinen Tests »auf die Schnelle« durchführen zu können. Klicken Sie entweder auf das Menü Ansicht/Direktfenster oder drücken Sie Strg+G, so dass am unteren Bildschirmrand ein mit Direktbereich überschriebenes, leeres Fenster erscheint. Hier können Sie Funktionen oder Formeln direkt nach einem Fragezeichen eingeben und mit der Eingabe-Taste bestätigen: Abbildung 2.22: Der Direktbereich mit zwei ausgeführten Funktionen und jeweils darunter deren Ergebnissen. Wie Sie in Abbildung 2.22 sehen, sind auch mehrere unabhängige Eingaben möglich, bei denen jeweils unterhalb der Eingabe das Ergebnis genannt wird. Im Direktfenster können Sie übrigens wie in einem Modul mit dem Namen der Funktion beginnen und diese dann mit Strg+Leertaste ergänzen lassen oder aus der IntelliSense-Liste auswählen. Statt einer MsgBox kann die Ausgabe eines Wertes auch per VBA-Code in das Direktfenster erfolgen. Schreiben Sie dann stattdessen Debug.Print, wird der folgende Inhalt im Direktfenster ausgegeben: 30 Lorenz Hölscher: Richtig einsteigen: Access 2007 VBA-Programmierung. Microsoft Press 2008 (ISBN 978-3-86645-210-7) Datei: Teil2_Kap02.doc, Seite31 28. Mai 2008 Abbildung 2.23: Der Direktbereich zeigt die Ausgabe für Debug.Print an. Der Vorteil gegenüber der MsgBox besteht darin, dass diese Meldung nicht einzeln bestätigt werden muss, sondern nach dem Programmdurchlauf im Direktfenster stehen bleibt. Gerade für viele Prüfwerte in längerem Code ist das viel praktischer, wie Sie später noch sehen werden. Funktion mit Parametern Die bisherigen selbstgeschriebenen Beispiel-Prozeduren sind relativ unflexibel gewesen, weil sie keine wechselnden Inhalte annehmen konnten. Das ändert sich, sobald Sie ihnen Parameter mitgeben. Das muss schon in deren Definition verankert werden, nämlich zwischen den bisher leeren Klammern nach dem Prozedurnamen: Function Quadrat(Zahl) Quadrat = Zahl ^ 2 End Function Die Funktion Quadrat erwartet nun beim Aufruf einen als Zahl benannten Parameter und gibt als Ergebnis dessen Quadratzahl zurück. Hinweis: Rechen-Operator für Potenzen Im Beispiel der Quadrat()-Funktion haben Sie sicherlich das Caret-Zeichen (Softlink d0201, auch Zirkumflex oder Dach genannt) entdeckt. Es liegt links oben auf der Tastatur und gehört zu den Akzent-Zeichen. Daher erscheint es erst auf dem Bildschirm, wenn Sie anschließend ein Leerzeichen eingegeben haben. Es dient in VBA dazu, die folgende Zahl als Exponenten oder Hochzahl angeben zu können. Die Schreibweise 2 ^ n entspricht also 2n (2 hoch n) und errechnet die n-te Potenz von 2. Falls Sie jetzt ein entsprechendes Zeichen für die Berechnung einer Wurzel vermissen: Das braucht es nicht. Wurzeln sind mathematisch gesehen nur Kehrwerte im Exponenten. Die Quadratwurzel aus 2 ( 2 2 , also ungefähr 1,41) schreibt sich 2 ^ 0.5 oder 2 ^ (1/2). Bitte achten Sie auf die Klammern im letzten Beispiel, denn sonst stimmt die Berechnungs-Reihenfolge nicht! 31 Lorenz Hölscher: Richtig einsteigen: Access 2007 VBA-Programmierung. Microsoft Press 2008 (ISBN 978-3-86645-210-7) II – Grundlagen von VBA 2.2 Das »klassische« erste Programm erstellen Datei: Teil2_Kap02.doc, Seite32 28. Mai 2008 Kapitel 2 Die ersten VBA-Prozeduren erstellen Der Test dieser Funktion geschieht mit einer Sub-Prozedur, die das Ergebnis beispielsweise wieder im Direktfenster anzeigt: Sub TesteQuadrat() Debug.Print Quadrat(5) End Sub Wenn Sie TesteQuadrat ausführen, erscheint im Direktfenster als Ergebnis korrekt die 25. Beim Schreiben der Testfunktion werden Sie bemerkt haben, dass hinter Quadrat nach Eingabe der öffnenden Klammer, die ja hinter einem Funktionsnamen immer stehen muss, ein QuickInfo automatisch auf den notwendigen Parameter Zahl hinwies. Abbildung 2.24: Im QuickInfo ist der notwendige Parameter zu sehen. Sie sollten daher immer darauf achten, für solche Parameter sprechende Namen zu wählen, weil diese beim Aufruf zu sehen sind. Zukünftig sollten solche Parameter auch mit ungarischer Notation und passendem Datentyp versehen sein, aber das ist erst Thema des nächsten Kapitels. Sub-Prozedur mit Parametern Selbstverständlich können auch Sub-Prozeduren mit Parametern ausgestattet werden. Stellen Sie sich vor, Sie wollen an vielen Stellen in Ihrem Programm eine standardisierte Fehlermeldung nutzen. Diese nennt dann außer dem konkreten, wechselnden Fehlertext ein paar Standard-Informationen wie Programm-Autor, Versionsstand, Datum oder ähnliches. Es wäre reine Arbeitsbeschaffung, wollten Sie diese Informationen an allen Stellen mit einer Fehlermeldung immer wieder eingeben. 1. Schreiben Sie stattdessen für Ihre Standard-Fehlermeldung eine zentrale Prozedur: Sub StandardFehlermeldung(Fehlertext) MsgBox Fehlertext & vbCrLf & vbCrLf & _ "Programmversion: 1.01" & vbCrLf & _ "Stand: 24.12.2007" & vbCrLf & _ "Autor: Lorenz Hölscher", vbCritical End Sub Sub TesteFehlermeldung() StandardFehlermeldung "Das ist nur ein Test" End Sub 2. Mit TesteFehlermeldung lässt sich die Prozedur direkt testen. Da sie ja ohnehin ein Meldungsfenster erzeugt, hilft das Direktfenster hier auch nicht weiter. 32 Lorenz Hölscher: Richtig einsteigen: Access 2007 VBA-Programmierung. Microsoft Press 2008 (ISBN 978-3-86645-210-7) Datei: Teil2_Kap02.doc, Seite33 28. Mai 2008 2.2 Das »klassische« erste Programm erstellen Sie brauchen also an allen Stellen, wo eine Fehlermeldung erscheinen soll, nur noch StandardFehlermeldung mit dem gewünschten Text aufzurufen. Das ist nicht nur viel übersichtlicher und kürzer, sondern vor allem auch einfacher, wenn es mal Änderungen gibt. Änderungen an zentralen Prozeduren Wie Sie im obigen Code sehen, nutzt die Prozedur StandardFehlermeldung eine MsgBox-Prozedur, bei der mit der Konstanten vbCrLf Zeilenumbrüche im Ergebnis erzeugt werden. Um zwischen wechselndem Text und Standard-Informationen einen größeren Abstand zu erreichen, können auch mehrere Zeilenumbrüche aufeinander folgen. Hinweis: Zeilenumbrüche Wenn Sie im Code mit der Eingabe-Taste einen Zeilenumbruch machen, sind Sie und der Compiler sich einig, dass eine neue Zeile beginnt. Sie können jedoch auch einen Zeilenumbruch einbauen, den der Compiler nicht sieht. Mit der Folge Leerzeichen, Unterstrich und Zeilenumbruch finden Ihre Augen zwar eine mehrzeilige Darstellung, der Compiler aber liest das wie eine einzige Zeile. Damit dies als Folgezeile erkennbar ist, rücke ich dort jeweils ein, wie das im obigen Code schon geschehen ist. Es gibt auch die umgekehrte Variante: ein Zeilenumbruch, den Sie im Code nicht sehen, der aber im Ergebnis enthalten ist. Dafür steht die Konstante vbCrLf, die eigentlich nur eine Zeichenkette mit den Buchstaben ASCII 13 und ASCII 10 (Softlink d0202) enthält. Diese erzeugen einen Zeilenumbruch, wenn sie im Text eines Meldungsfensters erscheinen. Damit man sich die ASCII-Nummern weder merken noch diese mühsam aufrufen muss (nämlich mit Chr(13) & Chr(10)), gibt es diese Konstante, die immer und überall für Zeilenumbrüche eingesetzt werden kann. Deren etwas kryptischer Name kommt noch aus der Zeit der Schreibmaschinen. Diese haben für die neue Zeile links einen Hebel, der die Walze nach rechts schiebt (Wagenrücklauf = carriage return) und eine Zeile weiter dreht (Zeilenvorschub = line feed). Aus diesen Anfangsbuchstaben setzt sich die Konstante zusammen: Visual Basic carriage return line feed. Inzwischen fällt Ihnen aber auf, dass es schöner wäre, wenn die Informationen mit Tabulator-Zeichen (Konstante vbTab bzw. ASCII-Zeichen 9) strukturiert wären. Das geht nämlich auch in einer MsgBox, ohne dass Sie allerdings den Abstand der Tabstopps beeinflussen könnten. Hätten Sie nun überall im Code die MsgBox mit allen Zusatz-Informationen mehrfach hineinkopiert, müssten Sie hoffen, dass Sie mit Bearbeiten/Ersetzen die Änderungen automatisiert vornehmen können. Selbst wenn das hier zufällig klappt, ist das normalerweise nicht nur ein erheblicher Aufwand, sondern oft schon inhaltlich zum Scheitern verurteilt. 33 Lorenz Hölscher: Richtig einsteigen: Access 2007 VBA-Programmierung. Microsoft Press 2008 (ISBN 978-3-86645-210-7) II – Grundlagen von VBA Abbildung 2.25: Die Standard-Fehlermeldung mit wechselndem Text am Anfang. Datei: Teil2_Kap02.doc, Seite34 28. Mai 2008 Kapitel 2 Die ersten VBA-Prozeduren erstellen Hier gibt es aber die zentrale Prozedur arbeiten müssen: StandardFehlermeldung, die Sie nur an einer einzigen Stelle über- Sub StandardFehlermeldung(Fehlertext) MsgBox Fehlertext & vbCrLf & vbCrLf & _ "Programmversion:" & vbTab "1.01" & vbCrLf & _ "Stand:" & vbTab & vbTab "24.12.2007" & vbCrLf & _ "Autor:" & vbTab & vbTab "Lorenz Hölscher", vbCritical End Sub Sub TesteFehlermeldung() StandardFehlermeldung "Das ist nur ein Test" End Sub Die notwendigen Änderungen beziehen sich alleine auf die Prozedur StandardFehlermeldung und sind dort fett markiert. Die Aufrufe dieser Prozedur, wie beispielhaft in TesteFehlermeldung gezeigt, bleiben völlig unverändert. Jetzt sieht das Meldungsfenster ohne viel Aufwand schon deutlich schöner aus: Abbildung 2.26: Durch den Tabulator stehen die Daten untereinander wie in einer Tabelle. Wegen der erheblich unterschiedlichen Länge der Beschriftungen müssen unterschiedlich viele Tabzeichen mit vbTab eingefügt werden. Das ist nur durch Probieren herauszubekommen und im übrigen bei einer solchen Proportionalschrift ja auch abhängig von der Schriftart. Da diese als Teil des WindowsOberflächendesigns geändert werden kann, sollten Sie davon nicht allzu viel Gebrauch machen, denn ein solches »Layout« mit Tabulator-Zeichen könnte schnell scheitern. Mehrere Parameter Sie sind bei den Parametern eigener Prozeduren keineswegs auf einen einzigen beschränkt. Mehrere Parameter werden sowohl in der Definition als auch später beim Aufruf in VBA immer durch Kommata getrennt, völlig unabhängig davon, was Ihre Windows-Ländereinstellung als Listenzeichen angibt. 1. Das Beispiel mit der Standard-Fehlermeldung kann so erweitert werden, dass außer dem bisherigen Text im Meldungsfenster auch die Titelzeile des Dialogs als Titeltext geändert werden kann: Sub StandardFehlermeldung(Fehlertext, Titeltext) MsgBox Fehlertext & vbCrLf & vbCrLf & _ "Programmversion:" & vbTab "1.01" & vbCrLf & _ "Stand:" & vbTab & vbTab "24.12.2007" & vbCrLf & _ "Autor:" & vbTab & vbTab "Lorenz Hölscher", _ vbCritical, Titeltext End Sub 34 Lorenz Hölscher: Richtig einsteigen: Access 2007 VBA-Programmierung. Microsoft Press 2008 (ISBN 978-3-86645-210-7) Datei: Teil2_Kap02.doc, Seite35 28. Mai 2008 2.2 Das »klassische« erste Programm erstellen 2. Da die nun veränderte Prozedur StandardFehlermeldung zwei Parameter definiert hat, müssen sie auch beim Aufruf in TesteFehlermeldung mit Daten gefüllt werden, und zwar auch in dieser Reihenfolge: Sub TesteFehlermeldung() StandardFehlermeldung "Das ist nur ein Test", "Versuch" End Sub II – Grundlagen von VBA 3. Jetzt sieht der Dialog so aus wie in Abbildung 2.27, mit dem Text »Versuch« in seiner Titelzeile. Abbildung 2.27: Das Meldungsfenster erhält nun einen flexiblen Titel. Benannte Parameter Wenn Sie die vorgegebene Reihenfolge der Parameter nicht einhalten wollen, müssen Sie deren Namen angeben. Sie haben diese Schreibweise vielleicht schon mal beim Aufzeichnen von Makros (was allerdings nur in den übrigen Office-Programmen, nicht aber in Access möglich ist) gesehen. 1. Sie dürfen den Parameternamen vor dessen Inhalt setzen, indem Sie die Zeichen »:=« folgen lassen, wie im nächsten Beispiel Sub TesteFehlermeldung() StandardFehlermeldung Fehlertext:="Das ist nur ein Test", Titeltext:="Versuch" End Sub 2. Das verlängert hier natürlich vor allem die Zeile und wird erst dann sinnvoll, wenn Sie ein paar der Argumente weglassen (dürfen) oder deren Reihenfolge ändern: Sub TesteFehlermeldung() StandardFehlermeldung Titeltext:="Versuch", Fehlertext:="Das ist nur ein Test" End Sub Auch diese Version funktioniert, aber Sie dürfen hier bei diesem Beispiel noch keinen der Parameter weglassen, daher lohnt sich das eigentlich nicht. 1. Sobald aber eine Prozedur optionale Parameter enthält wie den Befehl zum Öffnen eines Formulars, erhöhen benannte Parameter sicherlich die Lesefreundlichkeit: Sub OeffneFormular1() DoCmd.OpenForm "frmTest", , , , , acDialog End Sub 2. Mit diesem Aufruf wird ein Formular namens frmTest als modaler Dialog geöffnet. Dadurch sind keine Eingaben außerhalb des Formulars möglich. Da diese Anzeigeart durch den sechsten Parameter gesteuert wird und die vier dazwischen liegenden Parameter optional sind, müssen Sie dort leere Kommata stehen lassen. 35 Lorenz Hölscher: Richtig einsteigen: Access 2007 VBA-Programmierung. Microsoft Press 2008 (ISBN 978-3-86645-210-7) Datei: Teil2_Kap02.doc, Seite36 28. Mai 2008 Kapitel 2 Die ersten VBA-Prozeduren erstellen 3. Mit benannten Parametern können Sie das kürzer schreiben: Sub OeffneFormular1() DoCmd.OpenForm FormName:="frmTest", WindowMode:=acDialog End Sub Ich werde hier im Buch auf benannte Parameter verzichten, da die Code-Zeilen ansonsten sehr lang werden und öfter umbrochen werden müssten. Das würde die Lesefreundlichkeit doch erheblich einschränken. Optionale Parameter Sie haben eben schon das nächste Stichwort gelesen: optionale Parameter, also solche, die Sie nach Wunsch auch weglassen können. Sie dürfen optionale Parameter auch in selbstdefinierten Prozeduren einsetzen, aber immer nur als letzte(n) der Parameter. Sobald der erste optionale Parameter definiert wird, dürfen nur noch weitere optionale folgen. Sie werden jeweils mit dem voranstehenden Schlüsselwort Optional gekennzeichnet. 1. Sie könnten zum Beispiel eine Funktion erstellen, die Vor- und Nachnamen aus zwei Teilen zusammensetzt. Meistens wissen Sie den Vornamen, aber manchmal eben nicht. Daher wird der Vorname der optionale Parameter und muss also hinten stehen: Function NamenZusammen(Nachname, Optional Vorname) If IsMissing(Vorname) Then NamenZusammen = "Herr/Frau " & Nachname Else NamenZusammen = Vorname & " " & Nachname End If End Function Sub TesteNamenZusammen() Debug.Print NamenZusammen("Hölscher", "Lorenz") Debug.Print NamenZusammen("Müller-Lüdenscheid") Debug.Print NamenZusammen("Testinghoff", "Theophilia") End Sub Die If-Konstruktion an sich dürfte Ihnen schon bekannt vorkommen, aber die IsMissing()Funktion ist neu. Sie wird gebraucht, um zu überprüfen, ob ein optionaler Parameter überhaupt übergeben wurde. IsMissing() liefert einen True/False-Wert zurück, daher können Sie das Ergebnis direkt hinter If als Bedingung nutzen. Sie dürften auch If IsMissing(Vorname) = True Then schreiben, aber das macht inhaltlich keinen Unterschied. 2. Statt der Überprüfung im Code, ob ein Parameter aufgerufen wurde, können Sie ihm auch bei der Definition direkt einen Standardwert mitgeben. Das vereinfacht den Code meist deutlich, weil die entfallen kann. Schließlich hat er entweder seinen Standardwert oder einen konkreten, vom aufrufenden Code übergebenen Wert. IsMissing()-Prüfung Function NamenZusammen(Nachname, Optional Vorname = "Herr/Frau") NamenZusammen = Vorname & " " & Nachname End Function 36 Lorenz Hölscher: Richtig einsteigen: Access 2007 VBA-Programmierung. Microsoft Press 2008 (ISBN 978-3-86645-210-7) Datei: Teil2_Kap02.doc, Seite37 28. Mai 2008 2.2 Das »klassische« erste Programm erstellen In beiden Versionen erscheinen im Direktfenster die zusammengesetzten Namen, passend mit Vornamen oder eben der allgemeinen Herr/Frau-Anrede: Funktionen auch außerhalb von VBA aufrufen Funktionen lassen sich in Access nicht nur in VBA selber, sondern auch an verschiedenen anderen Stellen aufrufen. Deren wichtigste und vielleicht offensichtlichste ist sicherlich eine Abfrage. Dazu muss die Funktion NamenZusammen ein wenig abgewandelt werden, weil es in Abfragen nicht direkt optionale Parameter geben kann. Sie können die Funktion zwar mit einem oder zwei Parametern aufrufen, aber eben nur für alle Zeilen gleich. Wenn Sie diese jedoch mit beiden Parametern aufrufen und einer der Datensätze dafür keinen Inhalt hat (also nicht einen Leerstring enthält, sondern Null ist!), greift die IsMissing()-Prüfung nicht. Schließlich haben Sie den Parameter aufgerufen, nur sein Inhalt ist leer. 1. Damit die vorherigen Beispiele unverändert bleiben können, soll die neue Funktion nun NamenVerketten heißen: Function NamenVerketten(Nachname, Optional Vorname) If IsNull(Vorname) Then NamenVerketten = "Herr/Frau " & Nachname Else NamenVerketten = Vorname & " " & Nachname End If End Function Entsprechend der IsMissing()-Funktion für einen fehlenden Parameter gibt es auch eine IsNull()Funktion, die überprüft, ob der Inhalt der Variablen den Zustand Null hat. Mit den feinen Unterschieden zwischen einer leeren Zeichenkette und einem Null-Zustand werden wir uns ausführlicher in Kapitel 3 beschäftigen. 2. Zum Testen brauchen Sie zuerst eine Tabelle mit den Daten; hier im Beispiel heißt sie tblNamen mit den beiden Textfeldern namVorname und namNachname. Eine Abfrage basiert darauf und zeigt zum Vergleich die beiden Original-Felder ebenfalls an. In einem dritten, berechneten Feld namens Zusammen rufen Sie dann die Funktion auf. Die Schreibweise lautet Zusammen: NamenVerketten([namNachname]; [namVorname]) wie beim Aufruf integrierter Funktionen. Achtung: anders als in VBA ist das Trennzeichen für Parameter in Abfragen immer das Semikolon und nicht das Komma! 37 Lorenz Hölscher: Richtig einsteigen: Access 2007 VBA-Programmierung. Microsoft Press 2008 (ISBN 978-3-86645-210-7) II – Grundlagen von VBA Abbildung 2.28: Die Ergebnisse der Namenszusammensetzung im Direktbereich. Datei: Teil2_Kap02.doc, Seite38 28. Mai 2008 Kapitel 2 Die ersten VBA-Prozeduren erstellen Abbildung 2.29: Der Entwurf der Abfrage mit der Funktion Namenverketten. 3. Wenn Sie diese Abfrage ausführen, sehen Sie in der Spalte Zusammen die von der Funktion zu- rückgelieferten Ergebnisse: Abbildung 2.30: Die Datenblattansicht der Abfrage qryNamenverketten. Probleme mit fehlerhaften Abfrage-Funktionen Wenn Sie in einer solchen Funktion, die in einer Abfrage aufgerufen wird, einen Fehler haben, werden Sie mit Fehler-Meldungen überflutet. 1. Da Sie ja auch bei geöffneter Abfrage im VBA-Code weiterarbeiten können, probieren Sie doch mal wie im folgenden Bild durch ein zusätzliches & vor dem Parameter einen solchen Fehler zu provozieren. Vorname in der markierten Zeile 38 Lorenz Hölscher: Richtig einsteigen: Access 2007 VBA-Programmierung. Microsoft Press 2008 (ISBN 978-3-86645-210-7) Datei: Teil2_Kap02.doc, Seite39 28. Mai 2008 2.2 Das »klassische« erste Programm erstellen 2. Zunächst passiert nichts. Sobald Sie aber die Abfrage ansehen, kommt die gezeigte Fehlermeldung, Abbildung 2.31: Die Fehlermeldung bei einem Syntaxproblem in der Funktion. 3. Daraufhin ist die Startzeile der Funktion gelb hinterlegt, weil der Compiler dort gerne anfangen würde, aber den Code mangels korrekter Syntax nicht kompilieren und ausführen konnte. Also stoppen Sie ihn mit dem Menü Ausführen/Zurücksetzen. Auch das ist alles normal, wie Sie später im Zusammenhang mit der Fehlerbehandlung von VBA noch lesen werden. 4. Die Überraschung kommt anschließend, denn obwohl Sie den Compiler ja gerade gestoppt haben, erscheint sofort wieder die Fehlermeldung. In unserem Fall werden Sie das nur dreimal erleben und dann ist der Spuk vorbei. Das könnte Sie auch auf die Spur bringen, was da passiert ist: Die Funktion NamenVerketten wird in jeder Abfragezeile einmal aufgerufen. Der Compiler-Stopp gilt also für den ersten Aufruf. Anschließend startet die Abfrage die Funktion für die zweite Zeile erneut. Bei richtig großen Abfragen wird der Fehler also nur so oft wiederholt, wie Sie Datensätze auf dem Bildschirm sehen (wenn Sie Glück haben, nämlich bei Auswahlabfragen) oder sogar so oft, wie es insgesamt Datensätze gibt (wenn Sie weniger Glück haben, nämlich bei Aktionsabfragen). Bevor Sie in einem solchen Fall verzweifeln und doch lieber den Rechner booten, gibt es einen Trick, um da doch noch heil herauszukommen. 5. Bevor Sie das nächste Mal den Compiler mit Ausführen/Zurücksetzen stoppen, haben Sie die Chance, etwas am Code zu ändern. Entweder Sie korrigieren das Syntaxproblem oder, wenn das nicht geht, benennen Sie gnadenlos die Funktion um. Es ist völlig egal, wie sie heißt, Hauptsache anders! Dann können Sie alles zurücksetzen und in Ruhe weiterarbeiten. Andernfalls könnten Sie nämlich noch nicht einmal zur Abfrage wechseln, um dort das Fenster zu schließen. Das Ansehen alleine löst sofort eine Neuberechnung aus und zwingt Sie wieder in den VBA-Code. 39 Lorenz Hölscher: Richtig einsteigen: Access 2007 VBA-Programmierung. Microsoft Press 2008 (ISBN 978-3-86645-210-7) II – Grundlagen von VBA dass beim Kompilieren ein Syntaxfehler aufgetreten sei. Das ist nicht überraschend und kann mit OK bestätigt werden. Datei: Teil2_Kap02.doc, Seite40 28. Mai 2008 Kapitel 2 Die ersten VBA-Prozeduren erstellen Properties Eigentlich reicht die Aufteilung der Programmierwelt in Prozeduren mit und solche ohne Rückgabewert, also Sub oder Function. Denn mit den gleich vorgestellten Properties (Plural von Property) können Sie eigentlich auch nicht mehr machen. Aber die Schreibweise wird deutlich verbessert und macht Ihren Code lesefreundlicher. Das mag für die ersten zehn oder zwanzig Zeilen Code noch uninteressant sein, weil Sie dann dankbar sind, wenn überhaupt etwas funktioniert und Sie sich nicht mit Kleinigkeiten wie der Schönheit des Codes herumschlagen wollen. Es geht dabei auch nicht eigentlich um Schönheit, sondern darum, größeren Code noch nach Monaten oder gar Jahren verstehen und bearbeiten zu können. Properties werden Ihnen dabei helfen. Schauen Sie sich einmal das folgende Beispiel an, das auf die Einstellung Beim Speichern persönliche Daten aus Dateieigenschaften entfernen zugreift (im Office-Menü bei den Access-Optionen und dort unter Aktuelle Datenbank zu finden): Sub TesteZugriff() x = CurrentProject.RemovePersonalInformation Msgbox "Die Einstellung ist: " & x CurrentProject.RemovePersonalInformation = True End Sub Der Code merkt sich anfangs die Einstellung dieses Werts und zeigt die in der Variablen x zwischengespeicherte Ja/Nein- bzw. True/False-Entscheidung an. Danach wird der Wert auf True gesetzt. Nachteile von herkömmlichen Prozeduren Das sieht für Sie wahrscheinlich so unauffällig aus, dass Sie sich fragen, was ich daran so gut finde? Ganz einfach: Sie können RemovePersonalInformation sowohl lesend als auch schreibend benutzen. 1. Jetzt versuchen Sie das bitte mal mit Prozeduren: Sub WertSetzen(Wie) CurrentProject.RemovePersonalInformation = Wie End Sub Function WertLesen() WertLesen = CurrentProject.RemovePersonalInformation End Function 2. Sie benötigen eine Sub-Prozedur zum Setzen des Wertes und eine Function zum Auslesen. Dann können Sie entsprechend dem ursprünglichen Test-Code Ihre eigenen Prozeduren aufrufen: Sub TesteMeinenZugriff() x = WertLesen Msgbox "Die Einstellung ist: " & x WertSetzen True End Sub 40 Lorenz Hölscher: Richtig einsteigen: Access 2007 VBA-Programmierung. Microsoft Press 2008 (ISBN 978-3-86645-210-7) Datei: Teil2_Kap02.doc, Seite41 28. Mai 2008 2.2 Das »klassische« erste Programm erstellen Dem Aufruf eigener Prozeduren mangelt es im Vergleich zu einem VBA-Original an zwei Vorteilen: Die beiden Prozeduren mit gleicher Aufgabe, jedoch verschiedener Richtung (lesen oder schreiben) dürfen nicht wie im vorherigen Beispiel gleichnamig sein. Der Zusammenhang ist nicht erkennbar und Sie haben automatisch doppelt so viele Prozedurnamen, die Sie sich merken müssen. Beim Aufruf der Sub-Prozedur WertSetzen ist nicht erkennbar, dass ein Wert zugewiesen wird. Im Original stand dort ein Gleichheitszeichen und die Aufgabe war viel offensichtlicher. Syntax von Properties Es gibt bei Properties genau wie bei Prozeduren auch zwei Richtungen, nämlich lesen und schreiben. Eine Get-Property entspricht einer Function, denn sie liefert einen Rückgabewert. Eine Let-Property ist vergleichbar einer Sub-Prozedur, denn sie nimmt einen Wert entgegen. Außerdem gibt es noch sozusagen den Sonderfall einer Let-Property, nämlich die Set-Property. Diese ist nicht für »normale« Texte oder Zahlen, sondern für Objekte gedacht. Damit ist sie erst einmal uninteressant, sie ähnelt der Let-Property sowieso weitgehend. 1. Eine Property beginnt im Gegensatz zu einer Prozedur gleich mit zwei Schlüsselworten, nämlich Property Get oder Property Let. Dann folgt wie üblich der eigentliche Code. Die oben schon beschriebene WertLesen-Funktion wäre als Property so zu schreiben: Property Get DatenEntfernenOption() DatenEntfernenOption = CurrentProject.RemovePersonalInformation End Property 2. So weit ist der besondere Vorteil gegenüber einer Funktion noch nicht zu erkennen. Jetzt folgt das Gegenstück, nämlich der Ersatz für die DatenSetzen-Prozedur: Property Let DatenEntfernenOption(Wie) CurrentProject.RemovePersonalInformation = Wie End Property 3. Haben Sie etwas bemerkt? Der Name der zweiten Property ist identisch mit der ersten! Damit ist eines der Probleme erledigt, denn Sie können nun für die gleiche Aufgabe auch gleiche Namen einsetzen, egal, ob lesend oder schreibend: Sub TesteMeinenPropertyZugriff() x = DatenEntfernenOption Msgbox "Die Einstellung ist: " & x DatenEnfernenOption = True End Sub Und auch das zweite Problem ist erledigt, denn der Aufruf zum Setzen der Eigenschaft hat damit auch ein Gleichheitszeichen erhalten. Es ist rein optisch schon zu erkennen, dass dabei eine WertZuweisung stattfindet. Sie müssen für Properties nicht notwendigerweise beide, also Let und Get, erstellen. Wenn Sie nur jeweils eine erstellen, haben Sie automatisch eine Eigenschaft, die nur lesend oder nur schreibend benutzt werden kann. Genau das passiert bei VBA intern auch, wenn Sie feststellen, dass beispielsweise CurrentProject.Name = "Test" scheitert und dort die Fehlermeldung »Zuweisung an schreibgeschützte Eigenschaft nicht möglich« auslöst. 41 Lorenz Hölscher: Richtig einsteigen: Access 2007 VBA-Programmierung. Microsoft Press 2008 (ISBN 978-3-86645-210-7) II – Grundlagen von VBA Das sind genau die beiden Punkte, in denen Properties Ihnen zu besserem Code verhelfen können. Datei: Teil2_Kap02.doc, Seite42 28. Mai 2008 Kapitel 2 Die ersten VBA-Prozeduren erstellen Properties ändern nicht nur Eigenschaften Auch wenn ich hier eher die Formulierung »Eigenschaft« benutzt habe, müssen Properties nicht wie in diesen Beispiel nur Wert-Zuweisungen vornehmen. Sie sehen zwar aus wie Variablen, denen ein Wert zugewiesen wird oder die diesen zurückgeben. Aber trotzdem dürfen Properties auch jede beliebige Aktion durchführen, da gibt es keine Einschränkung. Vielleicht wollen Sie in einer Protokoll-Tabelle notieren, wann die letzte Änderung dieser Option per VBA vorgenommen wurde? Dann müssen Sie nur die Property Let-Prozedur erweitern: Property Let DatenEntfernenOption(Wie) CurrentProject.RemovePersonalInformation = Wie With CurrentDb.OpenRecordset("tblProtokolle") .AddNew .Fields("proWas").Value = "Option geändert" .Fields("proWann").Value = Date .Update End With End Property Dabei sollen jetzt nicht die Details interessieren, wie die Daten in die Tabelle tblProtokolle geschrieben werden, sondern nur die Tatsache, dass es passiert. Bei jedem Aufruf der Property DatenEntfernenOption werden in den Feldern proWas und proWann die jeweiligen Werte in einem neuen Datensatz eingetragen. Hinweis: Die With-Struktur ist sehr praktisch Anstatt in jeder Zeile immer wieder das gleiche Objekt nennen zu müssen, können Sie diese Schreibweise abkürzen. Dabei wird das Objekt einmal vorher mit With genannt und anschließend überall dort gemeint, wo eine Methode oder Eigenschaft mit einem führenden Punkt beginnt. Aus der langen Form CurrentProject.RemovePersonalInformation =Not CurrentProject.RemovePersonalInformation zur Umschaltung einer Access-Option wird dann die verkürzte Schreibweise With CurrentProject .RemovePersonalInformation =Not .RemovePersonalInformation End With Beachten Sie dabei, dass der führende Punkt keineswegs am Anfang der Zeile stehen muss, wie hier zu sehen ist. Je mehr Eigenschaften oder Methoden eines Objekts aufgerufen werden, desto effektiver und übersichtlicher ist diese alternative Schreibweise. Properties mit mehreren Parametern Auch Properties können mehrere Parameter besitzen, aber nur der letzte davon verhält sich so wie in dieser beschriebenen Form mit der Nutzung des Gleichheitszeichens. Die übrigen Parameter werden wie üblich innerhalb der runden Klammern übergeben. 1. Erstellen Sie beispielsweise die beiden folgenden Properties, um die Farbe des Detailbereichs eines beliebigen Formulars auszulesen oder zu setzen: 42 Lorenz Hölscher: Richtig einsteigen: Access 2007 VBA-Programmierung. Microsoft Press 2008 (ISBN 978-3-86645-210-7) Datei: Teil2_Kap02.doc, Seite43 28. Mai 2008 2.2 Das »klassische« erste Programm erstellen Property Let FormularHintergrund(FormName, Farbe) Forms(FormName).Section(acDetail).BackColor = Farbe End Property Property Get FormularHintergrund(FormName) FormularHintergrund = Forms(FormName).Section(acDetail).BackColor End Property 2. Entwerfen Sie anschließend ein Formular namens frmTest in der Datenbank, welches völlig leer 3. Da der Zugriff auf ein Formular mit der Forms-Auflistung nur möglich ist, wenn es geöffnet ist, wird das beim Test per DoCmd.OpenForm einfach direkt erledigt: Sub WechselHintergrund() DoCmd.OpenForm "frmTest" MsgBox "Farbnummer ist: " & FormularHintergrund("frmTest") FormularHintergrund("frmTest") = 255 MsgBox "Jetzt ist der Hintergrund rot!" End Sub 4. Starten Sie die Prozedur WechselHintergrund. Diese öffnet das angegebene Formular und liest mittels FormularHintergrund-Property die Farbnummer des Detail-Hintergrunds aus. Wenn Sie an dessen Entwurf nichts geändert haben, ist er vermutlich noch weiß und hat die Farbnummer 16777215. Danach wird seine Farbe auf rot geändert, wie Sie im Hintergrund der zweiten MsgBox sehen. Prozeduren verlassen Alle oben genannten Arten von Prozeduren, also Sub, Function oder Property, können Sie mit den Anweisungen Exit Sub, Exit Function oder Exit Property jeweils vorzeitig verlassen. Das ist vor allem im Zusammenhang mit der Fehlerbehandlung notwendig und wird dort an Beispielen gezeigt. Kommentare Sie können Ihren Code kommentieren, indem Sie wie in alten Basic-Dialekten an den Anfang einer Zeile Rem (für Remark, Kommentar) schreiben. Das ist aber eher unpraktisch, denn Rem muss sich immer am Zeilenanfang befinden. Viel sinnvoller ist das Hochkomma, welches nicht mit den Akzentzeichen verwechselt werden darf und auf der Tastatur rechts neben dem »Ä« liegt. Es darf jederzeit innerhalb der Zeile stehen. Ab diesem Zeichen bis zum Ende der Zeile gilt alles als Kommentar und wird nach Verlassen der Zeile grün gefärbt: Sub KommentarBeispiel() Rem Das wird ignoriert MsgBox "Das funktioniert" MsgBox "Diese Zeile ist ziemlich lang", vbCritical, _ "Test-Meldung" 'hier können Sie kommentieren 'HIER KEIN KOMMENTAR! End Sub 43 Lorenz Hölscher: Richtig einsteigen: Access 2007 VBA-Programmierung. Microsoft Press 2008 (ISBN 978-3-86645-210-7) II – Grundlagen von VBA sein darf. Datei: Teil2_Kap02.doc, Seite44 28. Mai 2008 Kapitel 2 Die ersten VBA-Prozeduren erstellen Beachten Sie bitte, dass nach Pseudo-Umbrüchen (also Leerzeichen + Unterstrich + Umbruch) kein Kommentar stehen darf! Im Grunde befinden Sie sich dabei ja noch mitten in der Zeile, jedenfalls aus Sicht des VBA-Editors, daher beschwert sich dieser auch sofort über einem Syntaxfehler. 2.3 Übungen zu diesem Kapitel In diesem Abschnitt finden Sie einige Übungen zu diesem Kapitel. Die richtigen Antworten finden Sie wie immer auf der Website www.richtigeinsteigen.de. Übung 2.1 Wie unterscheidet sich der Aufruf einer Sub-Prozedur von dem einer Function? Übung 2.2 Erstellen Sie eine Sub-Prozedur TextOderZahl, die per InputBox()-Funktion eine Eingabe erwartet und mit MsgBox() anzeigt, ob es sich dabei um eine Zahl oder einen Text handelt. Dabei hilft Ihnen die IsNumeric()Funktion. Übung 2.3 Verändern Sie die in der letzten Übung erstellte Prozedur TextOderZahl so, dass Sie den von der InputBox() angezeigten Text als Parameter übergeben können. Denken Sie daran, dass TextOderZahl deswegen nicht mehr direkt aufgerufen werden kann, sondern eine zusätzliche Prozedur zum Testaufruf braucht. Übung 2.4 Schreiben Sie eine Funktion Wurzel(Zahl1, Zahl2), welche für einen ersten Parameter Zahl1 dessen Wurzel errechnet. Der zweite Parameter Zahl2 gibt vor, die wievielte Wurzel gefunden wird. Der Aufruf von Wurzel(81, 2) ergibt 9 und Aufruf(125, 3) liefert 5. Übung 2.5 Verbessern Sie die Funktion Wurzel(Zahl1, Zahl2) so, dass der Parameter Zahl2 optional wird. Falls dieser weggelassen ist, soll automatisch die Quadratwurzel ermittelt werden. Wurzel(9, 2) und Wurzel(9) führen dann also beide zum Ergebnis 3. 44 Lorenz Hölscher: Richtig einsteigen: Access 2007 VBA-Programmierung. Microsoft Press 2008 (ISBN 978-3-86645-210-7) Datei: Teil2_Kap02.doc, Seite45 28. Mai 2008 2.4 Zusammenfassung Übung 2.6 Bauen Sie weitere Prüfungen ein, ob Zahl1 oder Zahl2 überhaupt Zahlen sind, indem Sie wiederum die IsNumeric()-Funktion einsetzen. Außerdem darf die Eingabe von 0 für Zahl2 nicht zu einem DivisionsFehler führen, muss also ebenfalls abgefangen werden. In diesen Fällen können Sie einfach den Wert 0 als Ergebnis zurückgeben, daher wird innerhalb der If/End If-Konstruktion jeweils mit Exit Function auf eine weitere Berechnung verzichtet. II – Grundlagen von VBA Übung 2.7 Versehen Sie alle Übungs-Prozeduren mit erläuternden Kommentaren. Übung 2.8 Erstellen Sie die benötigten Property-Prozedur(en) für ProjVer, damit der folgende Code Sub TesteProjVer() ProjVer = 88 MsgBox ProjVer End Sub das Datenbank-eigene Attribut für die Projekt-Version auf »88« setzt und das veränderte Ergebnis anschließend anzeigt. Nutzen Sie dafür den Befehl CurrentDb.Properties("ProjVer").Value. 2.4 Zusammenfassung In diesem Kapitel haben Sie die Grundstrukturen der VBA-Programmierung kennengelernt. Die SubProzeduren, Funktionen und Properties geben den Rahmen für den gesamten Code vor. Sub-Prozeduren lösen Aktionen aus, geben aber keine Ergebniswerte zurück. Sie werden mit ihrem Namen und, wenn Parameter folgen, mit einem Leerzeichen danach aufgerufen. Function-Prozeduren liefern ein Ergebnis, unabhängig davon, ob dieses durch eine einfache Berechnung oder komplexe Aktionen ermittelt wurde. Funktionen weisen ihr Ergebnis einer Variablen zu und haben beim Aufruf ein Paar runde Klammern um ihre Parameter. Die Klammern sind auch nötig, wenn gar keine Parameter verarbeitet werden. Funktionen können auch direkt als Argument einer Prozedur eingesetzt werden. Property-Prozeduren vereinheitlichen die Schreibweise, da sie für lesenden und schreibenden Zugriff gleichlautende Namen besitzen dürfen. Prozeduren dürfen mit keinen bis mehreren Argumenten definiert werden, wobei optionale Parameter immer am Ende stehen müssen. Bei Bedarf können sie beim Aufruf als benannte Argumente auch in anderer Reihenfolge geschrieben werden. 45 Lorenz Hölscher: Richtig einsteigen: Access 2007 VBA-Programmierung. Microsoft Press 2008 (ISBN 978-3-86645-210-7)