vba - gaddo.de · PDF fileDie Deutsche Bibliothek – CIP-Einheitsaufnahme Ein...
-
Upload
nguyenxuyen -
Category
Documents
-
view
217 -
download
1
Transcript of vba - gaddo.de · PDF fileDie Deutsche Bibliothek – CIP-Einheitsaufnahme Ein...
Workshop VBA
René Martin
Workshop VBA
An imprint of Pearson EducationMünchen • Boston • San Francisco • Harlow, England
Don Mills, Ontario • Sydney • Mexico CityMadrid • Amsterdam
Die Deutsche Bibliothek – CIP-Einheitsaufnahme
Ein Titeldatensatz für diese Publikation ist beiDer Deutschen Bibliothek erhältlich.
Die Informationen in diesem Produkt werden ohne Rücksicht auf einen eventuellen Patentschutz veröffentlicht.Warennamen werden ohne Gewährleistung der freien Verwendbarkeit benutzt. Bei der Zusammenstellung von Texten und Abbildungen wurde mit größter Sorgfalt vorgegangen. Trotzdem können Fehler nicht vollständig ausgeschlossen werden. Verlag, Herausgeber und Autoren können für fehlerhafte Angaben und deren Folgen weder eine juristische Verantwortung noch irgendeine Haftung übernehmen. Für Verbesserungsvorschläge und Hinweise auf Fehler sind Verlag und Herausgeber dankbar.
Alle Rechte vorbehalten, auch die der fotomechanischen Wiedergabe und der Speicherung in elektronischen Medien. Die gewerbliche Nutzung der in diesem Produkt gezeigten Modelle und Arbeiten ist nicht zulässig.
Fast alle Hardware- und Softwarebezeichnungen, die in diesem Buch erwähnt werden, sind gleichzeitig auch eingetragene Warenzeichen oder sollten als solche betrachtet werden.
Umwelthinweis: Dieses Produkt wurde auf chlorfrei gebleichtem Papier gedruckt.Die Einschrumpffolie – zum Schutz vor Verschmutzung – ist aus umweltverträglichem und recyclingfähigem PE-Material.
10 9 8 7 6 5 4 3 2 1
03 02 01 00
ISBN 3-8273-1663-4
© 2000 by Addison-Wesley Verlag,ein Imprint der Pearson Education Deutschland GmbH, Martin-Kollar-Straße 10–12, D-81829 München/GermanyAlle Rechte vorbehaltenEinbandgestaltung: Rita Fuhrmann, Frankfurt/Oder Lektorat: Christina Gibbs, [email protected],Korrektorat: Christine Depta, FreisingHerstellung: Elisabeth Egger, [email protected]: reemers publishing services gmbh, KrefeldDruck: Media-Print, PaderbornPrinted in Germany
Inhaltsverzeichnis
Vorwort oder: Warum VBA-Kenntnisse wichtig sind . . . . . . . 11
Aufbau des Buches . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11Verwendete Symbole und Schreibkonventionen . . . . . . . . . 12
1Grundlagen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
1.1 Die Syntax einer Prozedur . . . . . . . . . . . . . . . . . . . . . . . . . . 151.2 Kommentare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 161.3 Programmzeilen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 161.4 Variablen und Datentypen. . . . . . . . . . . . . . . . . . . . . . . . . . 161.5 Konstanten . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 171.6 Datenfelder, Arrays . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 181.7 Deklarieren eines festen Datenfelds . . . . . . . . . . . . . . . . . . . 181.8 Deklarieren eines dynamischen Datenfeldes . . . . . . . . . . . . 191.9 Ein- und Ausgabe . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 201.10 Übungen. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 201.11 Tipps. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 211.12 Lösungen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22
2 Operatoren, Verknüpfungen und Verzweigungen . . . . . . . . . 23
2.1 Operatoren . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 232.2 Verzweigungen I . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 252.3 Verzweigungen II . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 252.4 Verzweigungen III . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 252.5 Verzweigungen IV. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 252.6 Informationsabfragen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 262.7 Übungen. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 272.8 Tipps. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 282.9 Lösungen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28
3Eingebaute Funktionen. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33
3.1 Die mathematischen Funktionen: . . . . . . . . . . . . . . . . . . . . 333.2 Die finanzmathematischen Funktionen: . . . . . . . . . . . . . . . . 34
5
Inhaltsverzeichnis
3.3 Die String-Funktionen: . . . . . . . . . . . . . . . . . . . . . . . . . . . . 353.4 Die Uhrzeit- und Datumsfunktionen . . . . . . . . . . . . . . . . . . 373.5 Die Funktion Format . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 393.6 Umwandlungsfunktionen . . . . . . . . . . . . . . . . . . . . . . . . . . 423.7 Übungen zu den mathematischen Funktionen . . . . . . . . . . 433.8 Übungen zu den Textfunktionen. . . . . . . . . . . . . . . . . . . . . 443.9 Übungen zu den Datumsfunktionen . . . . . . . . . . . . . . . . . . 443.10 Übungen zu den Formatfunktionen . . . . . . . . . . . . . . . . . . 443.11 Tipps . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 453.12 Lösungen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45
4 Selbsterzeugte Funktionen, Aufrufe, Parameterübergabe . . 53
4.1 Aufruf . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 534.2 Globale Variablen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 534.3 Übergabe . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 544.4 Übungen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 564.5 Lösungen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 58
5 Schleifen, rekursives Programmieren . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59
5.1 Zählerschleifen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 595.2 Bedingungsschleifen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 605.3 Rekursionen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 635.4 Übungen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 655.5 Tipps . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 665.6 Lösungen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 68
6Dateizugriff . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 77
6.1 Der Zugriff auf Dateien . . . . . . . . . . . . . . . . . . . . . . . . . . . . 776.2 Übungen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 796.3 Tipps . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 796.5 ini-Dateien . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 806.4 Lösungen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 806.6 Übungen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 816.7 Lösungen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 816.8 Zugriff auf die Registry . . . . . . . . . . . . . . . . . . . . . . . . . . . . 826.9 Übung . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 826.11 Sequentielle Dateien . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 836.10 Lösung . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 83
6
Inhaltsverzeichnis
6.12 Übungen. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 856.13 Tipp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 866.14 Lösungen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 86
7Klassen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 89
7.1 Was sind Klassen?. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 897.2 Eigenschaften von Objekten . . . . . . . . . . . . . . . . . . . . . . . . 907.3 Methode. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 907.4 Übungen. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 937.5 Lösungen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 94
8Fehler . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 103
8.1 Programmierfehler . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1038.2 Fehler zur Laufzeit . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1048.3 Übungen. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1068.4 Lösungen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 107
9Externe DLLs aufrufen. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 111
9.1 Aufruf einer API-Funktion . . . . . . . . . . . . . . . . . . . . . . . . . . 1119.2 Die Declare-Anweisung . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1119.3 Beispiele für den Einsatz von APIs . . . . . . . . . . . . . . . . . . . . 113
10Dialoge . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 115
10.1 Dialog und Befehlsschaltfläche . . . . . . . . . . . . . . . . . . . . . . 11510.2 Übungen. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12010.3 Tipps. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12110.4 Lösungen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12110.5 Textfelder, Beschriftungsfelder und Anzeige . . . . . . . . . . . . 12410.6 Übungen. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12610.7 Tipps. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12710.8 Lösungen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12810.9 Rahmen, Optionsfeld, Kontrollkästchen und Umschaltfeld. . 13410.10 Übungen. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13510.11 Tipps. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13810.12 Lösungen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14110.13 Kombinationsfeld und Listenfeld . . . . . . . . . . . . . . . . . . . . . 152
7
Inhaltsverzeichnis
10.14 Übungen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15410.15 Tipps . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15510.16 Lösungen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15610.17 Bildlaufleiste und Drehfeld . . . . . . . . . . . . . . . . . . . . . . . . . 15910.18 Übungen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16010.19 Tipps . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16010.20 Lösungen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16110.21 Register und Multiseiten . . . . . . . . . . . . . . . . . . . . . . . . . . . 16410.22 Übungen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16510.23 Tipps . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16610.24 Lösungen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16610.25 Steuerelemente zur Laufzeit erzeugen . . . . . . . . . . . . . . . . 16910.26 Übungen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17210.27 Tipps . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17310.28 Lösungen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17310.29 Weitere Steuerelemente . . . . . . . . . . . . . . . . . . . . . . . . . . . 177
11Gemeinsam benutzte Elemente . . . . . . . . . . . . . . . . . . . . . . . . . . . 179
11.1 Das FileSearch-Objekt . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17911.2 Übung . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18311.4 Der Assistent und das Balloon-Objekt . . . . . . . . . . . . . . . . . 18311.3 Lösung . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18311.5 Symbolleisten, Menüleisten und Tastenkombinationen . . . . 18511.6 Übungen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19111.7 Tipps . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19211.8 Lösungen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 192
12Word VBA . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 197
12.1 Dateizugriff . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19712.2 Übungen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20012.3 Lösungen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20012.4 Bewegen, Markieren, Position bestimmen. . . . . . . . . . . . . . 20112.5 Übungen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20812.6 Tipps . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20912.7 Lösungen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20912.8 Tabellen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21012.9 Übungen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 211
8
Inhaltsverzeichnis
12.10 Tipps. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21112.11 Lösungen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21112.12 Formularfelder . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21312.13 Übungen. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21412.14 Tipps. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21412.15 Lösungen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21512.16 Ereignisse in Word . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21512.17 Übungen. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21612.18 Tipps. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21712.19 Lösungen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21812.20 Einige nützliche, erstaunliche und lustige Befehle . . . . . . . . 220
13Excel . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 231
13.1 Dateizugriff . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23113.2 Zugriff auf Tabellenblätter . . . . . . . . . . . . . . . . . . . . . . . . . . 23213.3 Übungen. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23313.4 Lösungen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23413.5 Zugriff auf Zellen. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23513.6 Rechnen in Excel . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23913.7 Zugriff auf Zeichen innerhalb einer Zelle . . . . . . . . . . . . . . . 24113.8 Übungen. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24213.9 Tipp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24313.10 Lösungen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24313.11 Diagramme . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24913.12 Übungen. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26013.13 Tipps. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26113.14 Lösungen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26113.15 Ereignisse in Excel . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26313.16 Übungen. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26413.17 Lösungen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26413.18 Einige nützliche, erstaunliche und lustige Befehle . . . . . . . . 266
14Powerpoint . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 269
14.1 Datei- und Programmzugriff . . . . . . . . . . . . . . . . . . . . . . . . 26914.2 Folien . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27014.3 Folienhintergründe . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27114.4 Objekte auf Folien. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 273
9
Inhaltsverzeichnis
14.5 Besonderheiten bei der Powerpoint-Programmierung . . . . . 27714.6 Übungen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27814.7 Tipps . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27914.8 Lösungen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 279
15Zugriff auf Visio . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 281
15.1 Die oberste Ebene: Application . . . . . . . . . . . . . . . . . . . . . . 28215.2 Das Document-Objekt . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28415.3 Schablonen. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28515.4 Seiten (das Page-Objekt) . . . . . . . . . . . . . . . . . . . . . . . . . . . 28615.5 Shape-Zugriff . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28715.6 Neue Shapes zeichnen . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29215.7 Visio-Ereignisse . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30115.8 Menüs, Symbole und Tastenkombinationen . . . . . . . . . . . . 31215.9 Symbole und Symbolleisten . . . . . . . . . . . . . . . . . . . . . . . . 316
16Outlook . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 319
16.1 Neue Elemente erzeugen . . . . . . . . . . . . . . . . . . . . . . . . . . 31916.2 Das Namespace-Objekt . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32016.3 Die Items . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32216.4 Gruppen und Verknüpfungen. . . . . . . . . . . . . . . . . . . . . . . 32716.5 Ereignisse in Outlook . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32816.6 Übung . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33516.7 Lösung . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 336
17 Austausch zwischen den Programmen . . . . . . . . . . . . . . . . . . 341
17.1 Ein Programm aus einem anderen starten . . . . . . . . . . . . . . 34117.2 Zugriff auf Office-Programme . . . . . . . . . . . . . . . . . . . . . . . 34317.3 Übungen zum Programmaustausch Word nach Excel . . . . . 34717.4 Lösungen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34717.5 Übungen zum Programmaustausch Excel nach Word . . . . . 35017.6 Lösungen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35117.7 Übung zum Programmaustausch Outlook nach Word und Excel 35517.8 Lösung . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35617.9 Übung zum Programmaustausch Visio nach Excel . . . . . . . . 35717.10 Lösung . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 357
Stichwortverzeichnis . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 361
10
Vorwort oder: Warum VBA-Kenntnisse wichtig sind
VBA gewinnt in den letzten Jahren immer stärker an Bedeutung. Dies mag ander Vormachtstellung von Microsoft hängen, dies kann aber auch einfach in derrelativ einfachen Programmiersprache selbst begründet sein. Access war daserste Produkt aus der Microsoft-Office-Palette, das schon in der Version 2.0VBA als Programmiersprache mitlieferte. In dieser Datenbank war dies ein not-wendiger Schritt, denn für die Erstellung einer Datenbank wird fast immer Pro-grammierung benötigt. Excel zog in der Version 5.0 nach, in Word wurdeWordBasic durch VBA in Office 97 ersetzt. In der gleichen Version hielt VBAauch Einzug in Powerpoint.
Heute, im Sommer der Jahres 2000, ist die Zahl der Anwendungen, die VBA in-tegriert haben, immens: zur Microsoft-Palette gesellen sich Visio, Frontpage,Project und Outlook, daneben sind noch weitere Programme wie Flowcharter,Corel Draw, AutoCAD und andere zu nennen. Die Verbreitung und die Beliebt-heit von VBA wächst, und mit ihr die Notwendigkeit, VBA zu lernen. Währendnoch vor Jahren ein guter Freund von mir, ein hervorragender Java- und C++-Programmierer, VBA- (und auch VB-)Programmierer als »Warmduscher« ver-spottete, so musste er zugeben, dass man nicht mit solch mächtigen Program-miersprachen auf »Spatzen« schießen sollte, wenn es darum geht, innerhalb ei-ner Applikation Lösungen zu entwickeln. Und genau das will VBA.
Auch wenn diese Programmiersprache Merkmale anderer Sprachen vermissenlässt (Multithreading, Vererbung und Polymorphismus), so liegt mit VBA 6.0dennoch ein mächtiges Werkzeug vor, mit dem ziemlich »weitgehend« und»tiefschürfend« programmiert werden kann.
Aufbau des BuchesVBA untergliedert sich in drei Bereiche. Zum einen ist der Sprachkern selbst zunennen: der Teil von VBA, der sich auch in VB befindet. Ihm sind die ersten neunKapitel gewidmet, dort werden die typischen Anforderungen, die beim Erler-nen einer Programmiersprache nötig sind, wiederholt und eingeübt. Dazu zäh-len die schon »klassischen« Themen Variablendeklaration, Schleifen, Verzwei-gungen, Fehlerbehandlung. Schließlich sollen die VBA-spezifischen Themeneingebaute und selbstdefinierte Funktionen, Dateizugriff und Klassen bespro-chen werden.
Der zweite Teil widmet sich den Dialogen oder Formularen (»Userforms«). Inden Anwendungen wird dem Benutzer eine solche Eingabemaske zur Verfü-gung gestellt, in die er bequem Daten eintragen, aus vordefinierten Listen et-was auswählen oder über Optionsbuttons und Kontrollkästchen eine Auswahl
11
Vorwort oder: Warum VBA-Kenntnisse wichtig sind
treffen kann. Auch wenn Sie keine Dialoge benötigen, so halte ich dieseszehnte Kapitel für wichtig, da man anhand von Dialogen exemplarisch den Um-gang mit Objekten erläutern und studieren kann.
Der dritte Teil des Buchs (Kapitel 11 – 17) ist schließlich dem »A« in VBA gewid-met: Es geht um die Applikationen. Lange habe ich überlegt, welche der An-wendungsprogramme ich dabei behandle. Schließlich habe ich mich gegen Ac-cess entschieden. Der Grund ist einfach. Zum einen stellt Access in der Version2000 zwei Zugriffsmöglichkeiten auf Tabellen und Abfragen zur Verfügung:DAO und ADO. Man müsste sie beide beschreiben. Zum Zweiten werden dieFormulare in Access programmiertechnisch anders gesteuert als in Word, Excelund Visio. Was bei diesen
strText = Me.txtEingabe.Value
heißt, lautet in Access
strText = Me!txtEingabe.Value
Zum Dritten ist die Programmierumgebung etwas anders, ebenso wie einigeBefehle anders lauten. Aus diesen Gründen habe ich mich gegen Access ent-schieden. Dafür habe ich den »Spitzenreitern« der VBA-Programmierung –Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dassdas Produkt Visio in nächster Zeit immer mehr Bedeutung innerhalb der Micro-soft-Palette gewinnen wird, ist auch ihm ein Kapitel gewidmet, in dem das Ob-jektmodell und einige wichtige Objekte beschrieben werden.
Und schließlich enthält dieses Buch ein kleines Kapitel über Powerpoint und ei-nes über Outlook. Beide Kapitel wurden der Vollständigkeit halber eingefügt,und auch aus dem Glauben, dass (vor allem Outlook) in nächster Zeit an Bedeu-tung gewinnen wird. Sicherlich werden immer mehr Anwender für sich kleineProgramme schreiben, um Outlook zu steuern, oder in Firmen für andere Be-nutzer Makros entwickeln, mit denen Outlook automatisiert wird. Denn schonjetzt stellt Outlook selbst einige interessante Assistenten zur Verfügung.
Verwendete Symbole und SchreibkonventionenFolgende Symbole werden verwendet:
Beispiele helfen Ihnen, Ihre Kenntnisse in der VBA-Programmierung zu vertie-fen. Sie werden mit diesem Icon gekennzeichnet.
Hinweise machen auf Elemente aufmerksam, die nicht selbstverständlich sind.In diesen Abschnitten wird etwas Besonderes erläutert.
Achtung, mit diesem Icon wird eine Warnung/Fehlerquelle angezeigt. An dermarkierten Stelle sollten Sie aufmerksam sein.
Manches geht ganz leicht, wenn man nur weiß, wie. Tipps & Tricks finden Siein den Abschnitten, wo dieses Icon steht.
12
Verwendete Symbole und Schreibkonventionen
Übung
Übungen stehen am Ende eines Kapitels oder unter Abschnitten, die zusam-mengehören. In Anschluss finden Sie stets Tipps zu den einzelnen Lösungen.Nicht zu jeder Aufgabe wurde ein Tipp erstellt. Dies hängt häufig mit demSchwierigkeitsgrad zusammen. Auch in den Lösungen finden sich zum Teil wei-tere Kommentaren oder auch Alternativen. Meine Lösungsvorschläge sind si-cherlich nur eine Möglichkeit, wie man die entsprechenden Aufgaben lösenkann. Mit Sicherheit gibt es zur einen oder anderen Aufgabenstellung nochweitere Lösungsmöglichkeiten.
Jede Übung besitzt eine Bewertung der Schwierigkeit. Dabei gelten grob fol-gende Richtlinien:
Die Übung besteht aus einfachen elementaren Konstrukten, die vielleicht sogarin ähnlicher Form bereits als Beispiel vorgetragen wurden.
Die Übung verlangt die Kombination mehrerer Gebiete der Sprache. Dies könn-ten zum Beispiel Themen sein, die bereits in vorhergehenden Kapiteln bespro-chen und geübt wurden.
Die bisher besprochenen Elemente müssen kombiniert und mit ihnen ein Prob-lem gelöst werden, welches ein gewisses Maß an Transferleistung erfordert.Das eventuell benötigte themenfremde Wissen zur Lösung wird in der Aufga-benstellung vermittelt.
Folgenden Tabelle gibt eine Übersicht zu den im Buch verwendeten Schreibkon-ventionen:
Element Beispiel Formatierung
Dateinamen, mit oder ohne Pfad, wichtige Begriffe
C:\EIGENE DATEIEN\SONTI-GES\PUCCINI.DOC
Kursiv
Menüs DATEI / DRUCKEN GROSSBUCHSTABEN
Schaltflächen OK, ABBRECHEN KAPITÄLCHEN
Namen von Steuerelementen, Beschriftungen, Titel
cmdOk, Abbrechen,txtDatum
Nichtproportionalschrift
spezielle Bezeichnungen, die im Text mitgelesen werden können
»True«»Laufweite»
in »Anführungszeichen«
Tasten (Strg)+(A) (Tasten)
Programmiercode, Schlüssel-wörter und Variablennamen
MsgBox »Gehorsam«
Optionale, das heißt nicht notwendige Programmzeilen
[Anweisung 2] [in eckigen Klammern]
13
Vorwort oder: Warum VBA-Kenntnisse wichtig sind
Nun bleibt mir nur noch, Ihnen viel Spaß beim Lesen des Buchs zu wünschen.
René Martin
Im Oktober 2000
Über Anregungen, Bemerkungen und Kritik freue ich mich:
14
Um überhaupt mit den einfachsten Übungen beginnen zu können, müssen Siegrundlegende Kenntnisse von VBA besitzen. Lassen Sie uns mit dem allgemei-nen Aufbau von Prozeduren beginnen.
1.1 Die Syntax einer Prozedur[Private | Public] [Static] Sub Name [(ArgListe)][Anweisungen][Exit Sub][Anweisungen]End Sub
Dabei bedeuten:
Tab. 1.1: Die Elemente eines Prozedurnamens
1 Grundlagen
Teil Beschreibung
Public Auf die Sub-Prozedur kann von allen anderen Prozeduren in allen Modulen zugegriffen werden. Bei Verwendung in einem Modul kann auf die Prozedur nur innerhalb des Projekts zugegriffen wer-den.
Private Auf die Sub-Prozedur kann nur durch andere Prozeduren aus dem Modul zugegriffen werden, in dem sie deklariert wurde.
Static Die lokalen Variablen der Sub-Prozedur bleiben zwischen Aufrufen erhalten. Das Attribut »Static« wirkt sich nicht auf Variablen aus, die außerhalb der Sub-Prozedur deklariert wurden, auch wenn sie in der Prozedur verwendet werden.
Name Erforderlich. Name der Sub-Prozedur gemäß den Standardkonven-tionen für Namen von Variablen: Maximal 255 Zeichen, kein Schlüs-selwort und eindeutig. Der Name darf nicht mit einer Ziffer beginnen und keine Satz- oder Sonderzeichen enthalten.
ArgListe Variablenliste mit den Argumenten, die an die Sub-Prozedur beim Aufruf übergeben werden. Mehrere Variablen werden durch Kom-mas getrennt.
Anweisungen Eine beliebige Gruppe auszuführender Anweisungen im Rumpf der Sub-Prozedur.
15
1 Grundlagen
1.2 KommentareKommentare werden mit einem Apostroph »’« eingeleitet, das am Anfangoder innerhalb einer Zeile stehen kann. Kommentare können ebenso durch einrem (remark) eingeleitet werden, welches sich nur am Anfang der Zeile befindendarf. Für das Apostroph steht Ihnen in der Symbolleiste »Bearbeiten« ein Sym-bol zum Ein- und Ausschalten zur Verfügung. Kommentare erscheinen in grü-ner Schrift, was Sie im Menü EXTRAS / OPTIONEN im Blatt EDITORFORMEN un-ter der »Codefarbe« Kommentartext ändern könnten.
1.3 ProgrammzeilenEin automatischer Umbruch, wie von der Textverarbeitung bekannt, findet erstnach 1.024 Zeichen statt: Um einen manuellen Umbruch zu organisieren, kannder Text in mehrere Zeilen geteilt werden. Dies erfolgt durch eine obligatorischeLeerstelle, der ein Unterstrich am Ende der Zeile folgt.
Sie dürfen maximal zehn Zeilen Code durch »_« voneinander trennen. Und derUnterstrich darf nicht innerhalb von Textteilen stehen.
Sollen mehrere Befehle in einer Zeile geschrieben werden, dann können diesedurch einen Doppelpunkt voneinander getrennt werden.
1.4 Variablen und DatentypenDie folgende Tabelle liefert eine Zusammenfassung der verschiedenen Variab-lentypen:
Tab. 1.2:Die verschiedenen
VariablentypenDatentyp
Variab-lentyp
Typenkenn-zeichen Bereich
Typ-kürzel Beispiel
Speicherplatz (in Bytes)
Boolean 0 (False) und -1 (True)
f True, False 2
Ganzzah-len
Byte 0 bis 255 byt 7, 104 1
Integer % -32.768 bis 32.767
int 7, 104, 1234
2
Long & -2.147.483.648 bis 2.147.483.647
lng 123456789 4
Dezimal-zahlen
Single ! -3,402823 * 10-
38 bis 3,402823
* 1038
sng 0,15 4
16
Konstanten
Variablen sollten ein Präfix besitzen, an dem ihr Typ erkennbar ist. Diese Kon-vention, die von der Firma »Gregory Reddick & Associates«, einer Unterneh-mensberatungsfirma von Microsoft, herausgegeben wurde, ist nicht verbind-lich. Allerdings arbeiten sehr viele Programmierer damit. Diese Konvention stellteine Möglichkeit der Standardisierung für VBA-Programmierung dar.
Aus den vorgegebenen Datentypen können Sie auch eigene Datentypen zu-sammensetzen.
[Private | Public] Type VarNameElementname [([Indizes])] As Typ[Elementname [([Indizes])] As Typ]...End Type
1.5 Konstanten[Public | Private] Const KonstName [As Typ] = Ausdruck
Die Syntax der Const-Anweisung besteht aus folgenden Teilen:
Double # -1,797693 * 10-
324 bis 1,797693 *
10324
dbl 12345678
* 101008
Currency @ -9,22 * 1014 bis
9,22* 1014
cur 59,90 DM 8
Datum-zahlen
Date 1.1.100 bis 31.12.9999
dat 11.11.1997 8
Text String $ Circa 2 Milliar-den
str »Der Weiße Riese«, »Konrad und Paul”
10 + Länge der Zeichenkette
Variant jeder numeri-sche Wert im Bereich Double, jeder String
22 + Länge der Zeichenkette
Objekte Object alle Objektrefe-renzen
4
Benutzer-definiert
DatentypVariab-lentyp
Typenkenn-zeichen Bereich
Typ-kürzel Beispiel
Speicherplatz (in Bytes)
17
1 Grundlagen
Tab. 1.3:Die Syntax der
Const-Anweisung
1.6 Datenfelder, ArraysDatenfelder werden genauso wie andere Variablen mit Hilfe der Dim-, Static-,Private- oder Public-Anweisungen deklariert. Der Unterschied zwischen »ska-laren Variablen« (Variablen, die keine Datenfelder sind) und »Datenfeldvariab-len« besteht darin, dass Sie generell die Größe des Datenfelds angeben müs-sen. Ein Datenfeld, dessen Größe angegeben ist, ist ein Datenfeld fester Größe.Ein Datenfeld, dessen Größe bei Ausführung eines Programms geändert wer-den kann, ist ein dynamisches Datenfeld.
Ob ein Datenfeld mit 0 oder 1 beginnend indiziert ist, hängt von der Einstellungder Option Base-Anweisung ab. Wenn Option Base 1 nicht angegeben ist, be-ginnen alle Datenfelder mit dem Index 0.
1.7 Deklarieren eines festen DatenfeldsIn der folgenden Code-Zeile wird ein Datenfeld fester Größe als Integer-Daten-feld mit 11 Zeilen und 11 Spalten deklariert:
Dim intMeinDatenfeld(10, 10) As Integer
Das erste Argument stellt die Zeilen, das zweite Argument die Spalten dar.
Wie bei jeder anderen Variablendeklaration entspricht der Datentyp der Ele-mente in einem deklarierten Datenfeld dem Typ Variant, solange Sie keinenDatentyp für das Datenfeld angegeben haben. Jedes Variant-Element des Da-tenfelds verwendet 16 Bytes. Deklarieren Sie Ihre Datenfelder explizit mit einemDatentyp, der nicht Variant ist, um den Code so kompakt wie möglich zu ma-chen!
Teil Beschreibung
Public Schlüsselwort, das auf Modulebene Konstanten deklariert, die allen Proze-duren in allen Modulen zur Verfügung stehen.
Private Schlüsselwort, das auf Modulebene Konstanten deklariert, die nur inner-halb des Moduls verfügbar sind, in dem sie deklariert wurden.
Konst-Name
Erforderlich. Name der Konstanten.
Typ Zulässige Typen sind Byte, Boolean, Integer, Long, Currency, Single, Double, Date, String oder Variant.
Aus-druck
Erforderlich. Ein Literalwert, eine andere Konstante oder eine beliebige Kombination, die beliebige arithmetische oder logische Operatoren (mit Ausnahme von Is) enthält.
18
Deklarieren eines dynamischen Datenfeldes
Die folgenden Code-Zeilen vergleichen die Größe verschiedener Datenfelder:
' Nachstehendes Datenfeld aus Elementen des Datentyps' Integer beansprucht 22 Bytes (11 Elemente * 2 Bytes).ReDim intMeinIntegerDatenfeld(10) As Integer
' Nachstehendes Datenfeld aus Elementen des Datentyps' Double beansprucht 88 Bytes (11 Elemente * 8 Bytes).ReDim dblMeinDoubleDatenfeld(10) As Double
' Nachstehendes Datenfeld aus Elementen des Datentyps Variant' beansprucht mindestens 176 Bytes (11 Elemente * 16 Bytes).ReDim MeinVariantDatenfeld(10)
' Nachstehendes Datenfeld aus Elementen des Datentyps
' Integer beansprucht 100 * 100 * 2 Bytes (20.000 Bytes).ReDim intMeinIntegerDatenfeld (99, 99) As Integer
' Nachstehendes Datenfeld aus Elementen des Datentyps' Double beansprucht 100 * 100 * 8 Bytes (80.000 Bytes).ReDim dblMeinDoubleDatenfeld (99, 99) As Double
' Nachstehendes Datenfeld aus Elementen des Datentyps Variant' beansprucht mindestens 160.000 Bytes' (100 * 100 * 16 Bytes).ReDim MeinVariantDatenfeld(99, 99)
Die maximale Größe eines Datenfelds hängt von Ihrem Betriebssystem sowievon dem verfügbaren Speicher ab. Durch die Verwendung eines Datenfeldes,das den für Ihr System verfügbaren RAM-Speicher überschreitet, wird Ihre An-wendung langsamer, da die Daten von der Festplatte gelesen und auf diese ge-schrieben werden müssen.
1.8 Deklarieren eines dynamischen Datenfeldes
Bei der Deklaration eines dynamischen Datenfelds können Sie die Größe desDatenfelds verändern, während der Code ausgeführt wird. Verwenden Sie zurDeklaration eines Datenfelds eine der Static-, Dim-, Private- oder Public-An-weisungen, und lassen Sie die Klammern leer. Beispiel:
Dim sngDatenfeld() As Single
Anmerkung: Sie können die ReDim-Anweisung dazu verwenden, ein Datenfeldimplizit innerhalb einer Prozedur zu deklarieren. Achten Sie darauf, bei Verwen-dung der ReDim-Anweisung den Namen des Datenfelds richtig zu schreiben.
19
1 Grundlagen
Auch wenn sich die Option Explicit-Anweisung im Modul befindet, wird einzweites Datenfeld erstellt.
Verwenden Sie in einer Prozedur innerhalb des Gültigkeitsbereichs des Daten-feldes die ReDim-Anweisung zur Änderung der Anzahl von Dimensionen, zurDefinition der Anzahl der Elemente und zur Definition der oberen und unterenGrenzen jeder Dimension. Sie können die ReDim-Anweisung beliebig oft ver-wenden, um das dynamische Datenfeld zu ändern. Dies hat jedoch zur Folge,dass die bestehenden Werte des Datenfeldes verloren gehen. Verwenden SieReDim Preserve, um ein Datenfeld zu erweitern, ohne dass die vorhandenenWerte im Datenfeld gelöscht werden. Die folgende Anweisung vergrößert z.B.das Datenfeld varDatenfeld um 10 Elemente, ohne die aktuellen Werte der ur-sprünglichen Elemente zu löschen.
ReDim Preserve varDatenfeld (UBound(varDatenfeld) + 10)
Wenn Sie das Schlüsselwort Preserve mit einem dynamischen Datenfeld ver-wenden, können Sie nur die obere Grenze der letzten Dimension, aber nicht dieAnzahl der Dimensionen ändern.
1.9 Ein- und AusgabeZwei einfache Möglichkeiten zur Ein- und Ausgabe stehen Ihnen über das Mel-dungsfenster und das Eingabefenster zur Verfügung:
MsgBox(prompt[, buttons] [, title] [, helpfile, context])InputBox(prompt[, title] [, default] [, xpos] [, ypos] _ [, helpfile, context])
Wird bei der MsgBox eine Klammer verwendet, dann wird ein Wert vom Typ In-teger zurückgegeben. Die InputBox gibt immer einen String-Wert zurück.
In den folgenden Programmen befinden sich Fehler. Finden Sie diese herausund überlegen Sie sich, wie man sie korrigieren könnte:
Übung 1
Sub Mein erstes Makro() MsgBox "Hallo"End Sub
1.10 Übungen
20
Tipps
Übung 2
Sub Gruß() MsgBox(Prompt:="Guten Morgen")End Sub
Übung 3
Sub Ende1()MsgBox "Diese Anweisung wird aufgrund eines ungültigen _ Vorgangs geschlossen.", vbCriticalEnd Sub
Übung 4
Sub Ende2()MsgBox _"Wenden Sie sich an den Hersteller, " & _ "falls das Problem weiterhin besteht.", _ vbCritical rem Keine schöne MeldungEnd Sub
Übung 5
Sub Wertezuweisen()Dim strJahreszeit(4) As StringDim i As Integer
strJahreszeit(1) = "Frühling": strJahreszeit(2) = "Sommer"strJahreszeit(3) = "Herbst": strJahreszeit(4) = "Winter"
For i = LBound(strJahreszeit) To UBound(strJahreszeit) MsgBox strJahreszeit(i)Next iEnd Sub
Achten Sie genau auf die Schreibweise, auf Leerzeichen, auf korrekte Umbrü-che und auf korrekt deklarierte Variablen!
1.11 Tipps
21
1 Grundlagen
Lösung 1
Der Name der Prozedur Mein erstes Makro darf kein Leerzeichen enthalten. Einkorrekter Name für ein Makro wäre beispielsweise:
Mein_erstes_Makro
oder:
MeinErstesMakro
Lösung 2
Wird das Meldungsfenster mit einer Klammer verwendet, dann muss ein Wertübergeben werden. Also beispielsweise so:
x = MsgBox(Prompt:="Guten Morgen")
Da das Meldungsfenster aber keine Auswahlabfrage wie YesNo oder Abort-RetryIgnore enthält, genügt zur alleinigen Anzeige folgender Befehl:
MsgBox Prompt:="Guten Morgen"
Lösung 3
Der Umbruch zwischen Befehlen darf nur zwischen Parametern oder Befehlstei-len stehen, nicht aber innerhalb von Text. Wenn Sie Text umbrechen möchten,dann bitte so:
MsgBox "Diese Anweisung wird aufgrund eines ungültigen " & _ "Vorgangs geschlossen.", vbCritical
Lösung 4
Kommentare, die mit rem eingeleitet werden, dürfen nicht hinter Befehlen ste-hen. Entweder verwenden Sie das Anführungszeichen oder schreiben Sie dieRemark-Zeile als eigenständige Zeile.
Lösung 5
Arrays beginnen, wenn nichts anderes festgelegt wird, bei 0. Das heißt,LBound(strJahreszeiten) liefert einen leeren String. Dies kann umgangen wer-den, indem ebenfalls bei strJahreszeiten(1) begonnen wird oder indem die Zäh-lung explizit mit 1 beginnt. Entweder durch den allgemeinen Befehl:
Option Base 1
oder indem die Variable folgendermaßen deklariert wird:
Dim strJahreszeiten(1 To 4) As String
1.12 Lösungen
22
2.1 OperatorenFolgende Operatoren stehen Ihnen in VBA zur Verfügung:
Tab. 2.1: Die Operatoren in VBA
2 Operatoren, Verknüpfungen und Verzweigungen
Typ Beschreibung Zeichen / Operator
Arithmetische Operatoren Addition +
Subtraktion -
Multiplikation *
Division /
Ganzzahlige Division \
Potenz ^
Modulo Mod
Textverkettung Concatenation &, +
Logische Operatoren und AND
oder OR
nicht NOT
exklusives oder (entweder das eine oder das andere)
XOR
logische Äquivalenz EQV
Implikation IMP
Vergleichsoperatoren gleich =
kleiner als <
kleiner oder gleich <=
größer als >
größer oder gleich >=
ungleich <>
Vergleichsoperatoren für Text
entspricht LIKE
Vergleichsoperatoren für Objekte
entspricht IS
23
2 Operatoren, Verknüpfungen und Verzweigungen
Die Verknüpfungsmöglichkeiten können in einer Tabelle aufgelistet werden:
Tab. 2.2:Die Konjunktoren
in VBA
Ergebnisse werden dabei immer von der rechten Seite des Gleichheitszeichensauf die linke übergeben.
Während mit dem Vergleichsoperator »=« nur exakte Gleichheit überprüft wer-den kann, kann mit Like mit Platzhaltern gearbeitet werden. Beispiele:
"Struwwelpeter" = "Struwwelpeter"
ergibt »True«.
"Struwwelpeter" = "Struwelpeter"
ergibt dagegen »False«. »True« liefern folgende drei Vergleiche:
"Struwwelpeter" Like "Struwwel*""Struwwelpeter" Like "*peter""Struwwelpeter" Like "S?ruwwelpe?er"
»False« ist das Ergebnis von folgendem Vergleich:
"STRUWWELPETER" Like "Struwwelpeter"
Wird dagegen vor den Prozeduren, im allgemeinen Deklarationsteil folgenderBefehl eingefügt:
Option Compare Text
dann wird nicht zwischen Groß- und Kleinschreibung unterschieden. Das be-deutet, dass im obigen Beispiel »True« das Ergebnis ist. Explizit unterschiedenwird zwischen Groß- und Kleinbuchstaben, wenn sich vor der ersten Prozedurfolgender Befehl befindet:
Option Compare Binary
Wert 1 Wert 2 And Or Xor Imp Eqv
Wahr Wahr Wahr Wahr Falsch Wahr Wahr
Wahr Falsch Falsch Wahr Wahr Falsch Falsch
Falsch Wahr Falsch Wahr Wahr Wahr Falsch
Falsch Falsch Falsch Falsch Falsch Wahr Wahr
Wahr Leer Falsch Wahr Wahr Falsch Falsch
Falsch Leer Falsch Falsch Falsch Wahr Wahr
Leer Wahr Falsch Wahr Wahr Wahr Falsch
Leer Falsch Falsch Falsch Falsch Wahr Wahr
24
Verzweigungen I
2.2 Verzweigungen IDie bekannteste (und vielleicht am häufigsten gebrauchte) Wenn-Verzweigungkann einzeilig:
If Bedingung Then [Anweisungen] [Else elseAnweisungen]
oder im Block auf mehrere Zeilen geschrieben werden:
If Bedingung Then[Anweisungen][ElseIf Bedingung-n Then[elseifAnweisungen] ...[Else[elseAnweisungen]End If
2.3 Verzweigungen IIEine (sehr selten verwendete) Verzweigung hat die folgende Syntax:
IIf(expr, truepart, falsepart)
2.4 Verzweigungen IIIWährend IIf sich nur zwischen einer von zwei Auswahlmöglichkeiten entschei-den kann, so kann die Funktion Choose aus einer Reihe von Argumenten aus-wählen. Die Syntax lautet:
Choose(Index, Auswahl-1[, Auswahl-2, ... [, Auswahl-n]])
Im folgenden Beispiel wählt die Funktion Auswahl zwischen vier Werten aus,die ihr übergeben wurden:
Function Auswahl(i As Integer) As String
Auswahl = Choose(i, "München", "Hamburg", "Berlin", "Köln")
End Function
2.5 Verzweigungen IVFür sehr viele Fälle eignet sich die übersichtliche Select Case-Schleife:
Select Case Testausdruck[Case Ausdrucksliste-n[Anweisungen-n]] ...[Case Else[elseAnw]]End Select
25
2 Operatoren, Verknüpfungen und Verzweigungen
Dabei ist zu beachten, dass Vergleichsoperatoren nur mit einem IS-Statementverwendet werden können, beispielsweise:
Select Case VariableCase Is > 1
Verschiedene Argumente können durch Kommata getrennt hintereinander ge-schrieben werden:
Case 2, 3, 4
Bereiche können mit To zusammengefasst werden:
Case 2 To 4
2.6 InformationsabfragenIn der folgenden Liste finden Sie sämtliche Informationen über Variablen, dieabgefragt werden können:
Tab. 2.3:Die Liste der Infor-mationsabfragen
Funktion Bedeutung Beispiel
IsDate überprüft, ob es sich um ein Datum handelt.
IsDate(28.2.2001) liefert »True«.IsDate(29.2.2001) liefert »False«.
IsNumeric überprüft, ob es sich um eine Zahl handelt.
IsNumeric(3) liefert »True«.IsNumeric(»drei«) liefert »False«.
IsNull überprüft, ob eine Variable leer ist. IsNull() liefert »True«.IsNull(»drei«) liefert »False«.
IsEmpty überprüft, ob eine Variable initiali-siert wurde.
IsArray überprüft, ob es sich bei einer Vari-ablen um ein Datenfeld handelt.
IsMissing überprüft, ob Argumente überge-ben wurden.
IsObject überprüft, ob es sich um ein Objekt handelt.
IsError überprüft, ob es sich um ein Fehler-objekt handelt.
26
Übungen
Übung 1
Im rechtwinkligen Dreieck gilt für die drei Seiten:
a² + b² = c²
Der Benutzer gibt die Werte von a und b ein und erhält die Länge der Hypo-thenusen c.
Übung 2
Lassen Sie sich in einem Meldungsfenster folgenden Text anzeigen:
Das »Gute« – dieser Satz steht fest –Ist stets das Böse, das man lässt.
W. Busch, Die Fromme Helene
Übung 3
Schreiben Sie eine Prozedur, in der die Benutzerin oder der Benutzer nach ihrem/ seinem Geschlecht (»w« oder »m«) gefragt wird. Wird der korrekte Buchstabeeingetippt, dann wird sie / er nach ihrem / seinem Namen gefragt und dieseswird ausgegeben. Beim Vertippen wird sie / er darauf hingewiesen.
Übung 4
Gesucht ist die Lösung der Gleichung
0 = x² + a*x + b
Der Benutzer gibt die Werte für a und b ein. Die Lösung der Gleichung lautet:
Sie funktioniert nur, wenn
Überprüfen Sie dies und melden Sie dann dem Benutzer, dass es keine odereine (welche?) Lösung gibt oder dass zwei Lösungen existieren (welche?).
2.7 Übungen
���
� −
±−=
�
�����
��
�
≥−
��
27
2 Operatoren, Verknüpfungen und Verzweigungen
Übung 5
Der Benutzer gibt eine Jahreszahl ein. Es wird überprüft, ob es sich um einSchaltjahr handelt. Diese Information wird ausgegeben.
Tipp zu Übung 2
Achten Sie auf die korrekten Anführungszeichen!
Tipp zu Übung 3
Zu dieser Lösung existieren zwei Varianten, wie der Benutzer ein großes oderein kleines »m« (oder »w«) eingeben kann. Die eine Variante verwendet denKonjunktor And, die zweite Variante benutzet die Funktion LCase, mit der dieSchreibung in Kleinbuchstaben geändert wird.
Tipp zu Übung 5
Die Regel für die Schaltjahrbestimmung lautet: Ein Jahr ist dann Schaltjahr,wenn es durch 4 teilbar ist. Ist es durch 100 teilbar, dann ist es kein Schaltjahr.Bei 400 ist es allerdings wieder Schaltjahr. Man kann dies über Verzweigungenprogrammieren. Dabei stehen mehrere Varianten zur Verfügung.
Lösung 1
Sub RechtwinklDreieck()Dim dblSeiteA As DoubleDim dblSeiteB As DoubledblSeiteA = InputBox("Bitte die Länge der ersten Kathete!")dblSeiteB = InputBox("Bitte die Länge der zweiten Kathete!")MsgBox "Die Länge der Hypothenuse beträgt " & _ (dblSeiteA ^ 2 + dblSeiteB ^ 2) ^ 0.5End Sub
Lösung 2
Sub Meldung()MsgBox "Das ""Gute"" – dieser Satz steht fest -" & vbCr & _ "Ist stets das Böse, das man lässt." & vbCr & vbCr & _ vbTab & "W. Busch, Die Fromme Helene"End Sub
2.8 Tipps
2.9 Lösungen
28
Lösungen
oder analog die zweite Variante:
Sub Meldung()MsgBox "Das " & Chr(34) & _ "Gute" & Chr(34) & _ " – dieser Satz steht fest -" & Chr(13) & _ "Ist stets das Böse, das man lässt." & _ Chr(13) & Chr(13) & Chr(9) & _ "W. Busch, Die Fromme Helene"End Sub
Sollen sich innerhalb einer Zeichenketten Anführungszeichen geschrieben wer-den, so kann man sie in doppelte Anführungszeichen setzen. Oder man kanndas Zeichen für Gänsefüßchen (Chr(34)) verketten. Analog steht für Zeilen-wechsel vbLf oder Chr(10), für (¢) vbCr oder Chr(13). Der Tabulator wirddurch vbTab oder Chr(9) ausgedrückt.
Lösung 3
Sub Begrüßung()Dim strName As StringDim strGeschlecht As StringstrGeschlecht = InputBox("Wie lautet dein Geschlecht?" & _vbCr & "Bitte ""m"" oder ""w"" eingeben!", "Name")
If strGeschlecht = "w" Or strGeschlecht = "W" Then strName = InputBox("Wie lautet dein Name?", "Name") MsgBox "Hallo, liebe " & strNameElseIf LCase(strGeschlecht) = "m" Then strName = InputBox("Wie lautet dein Name?", "Name") MsgBox "Hallo, lieber " & strNameElse MsgBox "Walnusshirn: Bitte ""m"" oder ""w"" eingeben!"End If
End Sub
Lösung 4
Sub Quadratische_Gleichung()Dim strZeile1 As StringDim strZeile2 As StringDim strGleichungszeile As StringDim dbla As DoubleDim dblb As DoubleDim dblD As DoubleDim dblx1 As DoubleDim dblx2 As Double
29
2 Operatoren, Verknüpfungen und Verzweigungen
strZeile1 = "0 = x² + a*x + b"strZeile2 = "Quadratische Gleichung"
MsgBox "Wir berechnen die Lösung der Gleichung " & _ strZeile1 & ". Bitte geben Sie die Werte für a " & _ "und für b ein!", , strZeile2dbla = InputBox("Wie lautet die Zahl a?", strZeile1)dblb = InputBox("Wie lautet die Zahl b?", strZeile1)dblD = (dbla / 2) ^ 2 – dblbstrGleichungszeile = "Die Gleichung 0 = x² + " & dbla & _ "*x + " & dblb
If dblD < 0 Then MsgBox strGleichungszeile & " hat keine Lösung. Schade!" _ , , strZeile2ElseIf dblD = 0 Then MsgBox strGleichungszeile & " hat eine Lösung: " & _ -dbla / 2, , strZeile2ElseIf dblD > 0 Then dblx1 = -(dbla / 2) + dblD ^ 0.5 dblx2 = -(dbla / 2) – dblD ^ 0.5 MsgBox strGleichungszeile & " hat zwei Lösungen: " & _ dblx1 & " und " & dblx2, , strZeile2End IfEnd Sub
Lösung 5
Sub Schaltjahr()Dim intJahreszahl As IntegerDim strAusgabe As String
intJahreszahl = InputBox("Bitte ein gültiges Jahr eingeben!")strAusgabe = " ist kein Schaltjahr."
If intJahreszahl Mod 4 = 0 Then strAusgabe = " ist Schaltjahr." If intJahreszahl Mod 100 = 0 Then strAusgabe = " ist kein Schaltjahr." If intJahreszahl Mod 400 = 0 Then strAusgabe = " ist Schaltjahr." End If End IfEnd If
MsgBox intJahreszahl & strAusgabe
End Sub
30
Lösungen
Man kann in diesem Beispiel auch den umgekehrten Weg gehen:
Sub Schaltjahr2()Dim intJahreszahl As IntegerDim strAusgabe As String
intJahreszahl = InputBox("Bitte ein gültiges Jahr eingeben!")
If intJahreszahl Mod 4 <> 0 Then strAusgabe = " ist kein Schaltjahr."Else If intJahreszahl Mod 100 <> 0 Then strAusgabe = " ist Schaltjahr." Else If intJahreszahl Mod 400 <> 0 Then strAusgabe = " ist kein Schaltjahr." Else strAusgabe = " ist Schaltjahr." End If End IfEnd If
MsgBox intJahreszahl & strAusgabe
End Sub
31
Wenn Sie eine Funktion suchen, die VBA zur Verfügung stellt, dann können Sieden Objektkatalog verwenden. Dort werden in der Bibliothek »VBA« in derListe der Klassen alle Funktionen aufgelistet.
Hier nun ein Überblick über die wichtigsten Funktionen:
3.1 Die mathematischen Funktionen:
Tab. 3.1: Die mathemati-schen Funktionen
3 Eingebaute Funktionen
Abbildung 3.1: Der Objektkatalog
Funktions-name Bedeutung
Sqr Quadratwurzel
Sin Sinus
Cos Cosinus
Tan Tangens
Atn der Arkustangens, die Umkehrfunktion des Tangens
Exp Exponentialfunktion auf Basis e
33
3 Eingebaute Funktionen
3.2 Die finanzmathematischen Funktionen:
Tab. 3.2:Die finanzmathe-
matischenFunktionen
Log der natürliche Logarithmus zur Basis e
Abs gibt den Absolutwert einer Zahl zurück:3 = Abs(3)3 = Abs(-3)
Int gibt einen Wert zurück, der den gleichen Typ wie der übergebene Wert hat und den ganzzahligen Anteil einer Zahl enthält.8 = Int(8.4)-9 = Int(-8.4)
Fix gibt einen Wert zurück, der den gleichen Typ wie der übergebene Wert hat und den ganzzahligen Anteil einer Zahl enthält.8 = Fix(8.4)-8 = Fix(-8.4)
Sgn das Vorzeichen einer Zahl:Wert von Zahl Rückgabewert von SgnGrößer als Null 1Gleich Null 0Kleiner als Null -1Beispiel: 1 = Sgn(7), -1 = Sgn(-7), 0 = Sgn(0)
Round Rundet eine Zahl auf oder ab.Beispiel: Round(2.4824, 2) ergibt 2,48; Round(2.4824, 1) ergibt 2,5
RndRandomize
Eine ZufallszahlWert von Zahl generierte Zufallszahlkleiner als Null immer dieselbe Zahl, die als Startwert Zahl verwendet wird.größer als Null die nächste Zufallszahl in der Folgegleich Null die zuletzt generierte Zahlnicht angegeben die nächste Zufallszahl in der FolgeWichtig: Die Rnd-Funktion gibt einen Wert zurück, der kleiner als 1, aber größer oder gleich Null ist.
Funktions-name Bedeutung
Funktions-name
Funktions-name in Excel Bedeutung
DDB GDA die Abschreibung eines Anlageobjekts nach der geo-metrisch degressiven Methode für einen spezifischen Zeitraum
SYD DIA die Abschreibung eines Anlageobjekts nach der arith-metisch degressiven Methode für einen spezifischen Zeitraum
SLN LIA die Abschreibung eines Anlageobjekts nach der linea-ren Methode für einen spezifischen Zeitraum
34
Die String-Funktionen:
3.3 Die String-Funktionen:
Tab. 3.3: Die String-Funktionen
FV ZW der Endwert einer Annuität ausgehend von regelmäßi-gen Zahlungen und einem konstanten Zinssatz
RATE ZINS der Zinssatz einer Annuität
IRR IKV der interne Zinsfluss für regelmäßige Cash-Flows
MIRR QIKV der modifizierte interne Zinsfluss für regelmäßige Cash-Flows
IPMT ZINSZ der Zinsanteil einer Annuität für einen spezifischen Zeitraum
PMT RMZ die Zahlung einer Annuität
PPMT KAPZ der Kapitalanteil einer Annuität
NPV NBW der Netto-Barwert für regelmäßige Cash-Flows
PV BW der Barwert einer Annuität
Funktions-name
Funktions-name in Excel Bedeutung
Funktions-name Bedeutung Beispiel
Left$ schneidet eine bestimmte Anzahl von Zeichen von links ab.
Left$("Heinrich Hoffmann", 4) ergibt "Hein"
Right$ schneidet eine bestimmte Anzahl von Zeichen von rechts ab.
Right$("Heinrich Hoffmann ", 4) ergibt "mann"
Mid$ schneidet eine bestimmte Anzahl von Zeichen aus der »Mitte« he-raus, das heißt, ab einer bestimm-ten Position.
Mid$("Heinrich Faust", 5, 4) ergibt "rich Hoffmann"
InStr überprüft, ob eine Zeichenfolge in-nerhalb einer Zeichenkette vorhan-den ist und gibt die Position an.
InStr("Heinrich Hoffmann", "ff") ergibt 12InStr("Heinrich Hoffmann", "h") ergibt 8InStr("Heinrich Hoffmann", "öy") ergibt 0
Ltrim$ löscht Leerzeichen am Anfang ei-nes Strings.
LTrim(" Heinrich Hoffmann ") ergibt ("Heinrich Hoffmann ")
Rtrim$ löscht Leerzeichen am Ende eines Strings.
RTrim(" Heinrich Hoffmann ") ergibt (" Heinrich Hoffmann")
Trim$ löscht Leerzeichen am Anfang und Ende eines Strings.
Trim(" Heinrich Hoffmann ") ergibt ("Heinrich Hoffmann ")
Len ermittelt die Länge einer Zeichen-kette.
Len("Heinrich Hoffmann") ergibt 17
35
3 Eingebaute Funktionen
Chr wandelt einen ASCII-Code in einen String um.
Chr(13) ergibt ¶
Asc wandelt einen String in die entspre-chende Zahl des ASCII-Codes um.
Asc("A") ergibt 65
Str$ wandelt eine Zahl in einen String um.
Str$(65) = "65"
Val wandelt einen String in eine Zahl um.
Val("65") = 65
Lcase wandelt eine Zeichenkette in Klein-buchstaben um.
Lcase("Heinrich Hoffmann") ergibt "heinrich hoffmann"
Ucase wandelt eine Zeichenkette in Groß-buchstaben um.
Ucase("Heinrich Hoffmann") ergibt "HEINRICH HOFFMANN"
StrConv wandelt eine Zeichenkette um. StrConv("heinrich hoffmann", vbProperCase) ergibt "Heinrich Hoffmann". Ebenso stehen die beiden Parameter vbLowerCase und vbUpperCase zur Verfügung
StrComp »vergleicht« zwei Zeichenketten, das heißt, es wird überprüft, wel-che zuerst im Alphabet steht. Ist die erste Zeichenkette »größer« als die zweite, wird -1 zurückgegeben, im umgekehrten Fall 1. Sind beide gleich: 0. Ist einer der beiden Strings leer, so wird Null überge-ben.
StrComp("Heinrich", "Heinrich") ergibt 0StrComp("Heinrich", "Hoff-mann") ergibt – 1StrComp("Robert", "Heinrich") ergibt 1
Space gibt eine Folge von Leerzeichen aus.
"Heinrich" & Space(2) & "Hoff-mann" ergibt "Heinrich Hoff-mann"
String wiederholt eine Zeichenfolge. "Heinrich" & String("/", 2) & "Hoffmann" ergibt "Hein-rich//Hoffmann"
Split trennt eine Zeichenfolge und liefert einen Array.
Split("Heinrich Hoffmann") ergibt"Heinrich""Hoffmann"
Join setzt eine Zeichenfolge zusammen.
Filter durchsucht eine Zeichenfolge.
In-StrRev(»abcd«, »ä«)
überprüft, ob eine Zeichenfolge in einer anderen vorhanden ist.
InStrRev("Heinrich Hoffmann", "ä") ergibt 0 ("falsch"), In-StrRev("Heinrich Hoffmann", "a") ergibt 1 ("wahr")
Funktions-name Bedeutung Beispiel
36
Die Uhrzeit- und Datumsfunktionen
3.4 Die Uhrzeit- und Datumsfunktionen
Tab. 3.4: Die Uhrzeit- und Datumsfunktionen
Funktionsname Bedeutung
Date setzt das aktuelle Systemdatum einoder stellt das Systemdatum um.
Now gibt das Systemdatum und die aktuelle Systemzeit zurück.
Timer gibt einen Wert vom Typ Single zurück, der die Anzahl der seit Mitternacht vergangenen Sekunden angibt. Diese Funktion wird verwendet, wenn Zeitdifferenzen berechnet werden sollen.
Time setzt die aktuelle Systemzeit einoder stellt die Systemzeit um.
DateSerial gibt die fortlaufende Datumszahl eines Datums zurück:DateSerial (Year, Month, Day).
DateValue gibt das Datum eines String-Arguments zurück.
TimeSerial gibt einen fortlaufenden Zeitwert für eine aus Stunden, Minuten und Sekunden bestehenden Uhrzeit zurück.
TimeValue wandelt einen String in eine Uhrzeit um.
DateAdd addiert oder subtrahiert ein angegebenes Intervall zu einem oder von einem Datum.Syntax: DateAdd(Intervall, Anzahl, Datum)Dabei wird das Intervall als String ausgegeben (vergleiche Date-Diff).
DateDiff gibt die Anzahl der Zeitintervalle zurück, die zwischen zwei Da-tumsangaben liegenSyntax: DateDiff(Intervall, Date1, Date2[, FirstDayofWeek] [, First-DayofYear]
Intervall wird als String angegeben. Es bedeuten:
D Tag
Y Kalendertag
W Wochentag
WW Woche
M Monat
Q Quartal
YYYY Jahr
S Sekunde
N Minute
H Stunde
Date1, Date2 die beiden Datumsangaben, deren Diffe-renz berechnet werden soll
FirstDayOfWeek gibt den ersten Wochentag an. Ohne Angaben wird Sonntag als erster gesetzt, sonst:
37
3 Eingebaute Funktionen
VbUseSytem 0 Einstellung der Applikation
VbSunday 1 Sonntag
VbMonday 2 Montag
VbTuesday 3 Dienstag
VbWednesday 4 Mittwoch
VbThursday 5 Donnerstag
VbFriday 6 Freitag
VbSaturday 7 Samstag
FirstWeekofYear gibt die erste Woche des Jahres an. Ohne Angabe wird die Woche verwendet, die den 1. Jan. enthält. (Wichtig zur Berech-nung von Kalenderwochen!)
VbUseSystem 0 Einstellung der Applikation
VbFirstJan1 1 Woche mit 1. Januar
VbFirstFourDays 2 Woche mit mindestens vier Tagen des neuen Jahres (zur Berechnung von Ka-lenderwochen (laut DIN 1355))
VbFirstFullWeek 3 erste komplette Woche im neuen Jahr
DatePart berechnet, zu welchem Teil eines angegebenen Intervalls ein Da-tum gehört:DatePart(Intervall, Date [, FirstDayofWeek] [, FirstDayofYear]Die Zahlen und Variablen entsprechen denen von DateDiff.
Day filtert den Tag aus einem Datum.
Month filtert den Monat aus einem Datum.
Year filtert das Jahr aus einem Datum.
Weekday gibt eine Zahl zwischen 1 und 7 zurück, die dem Wochentag ent-spricht:Weekday(Date, [FirstDayofWeek])Dabei entsprechen Date einem Datum und FirstDayofWeek der gleichen Variable wie bei DateDiff. Der zurückgegebene Wert ist ebenso eine Zahl von 1 bis 7 oder von vbSunday bis vbSaturday
Hour filtert die Stunde aus einer Uhrzeit.
Minute filtert die Minutenanzahl aus einer Uhrzeit.
Second filtert die Sekundenanzahl aus einer Uhrzeit.
Funktionsname Bedeutung
38
Die Funktion Format
3.5 Die Funktion FormatFormat(Ausdruck[,Format[,firstdayofweek[,firstweekofyear]]])
Ihre Argumente:
Tab. 3.5: Die Funktion For-mat und Zahlen
Zeichen Beschreibung Beispiel
Kein Zeichen zeigt die Zahl ohne For-matierung an.
0 beliebige Ziffer Format(1234, "0") liefert 1234Format(1234, "0.00") liefert 1234,00Format(1234.5678, "0") liefert 1235Format(1234.5678, "0.00") liefert 1234,57
# Platzhalter für eine Zif-fer, die nur angezeigt wird, wenn sich an die-ser Stelle eine Ziffer be-findet, gedacht für Tau-sendertrennzeichen.
Format(1234, "0") liefert 1234Format(1234, "#,##0") liefert 1.234Format(123, "#,##0") liefert 123
. und , Der Punkt dient als Trennzeichen für Dezi-malzeichen, das Komma für Tausendertrennzei-chen. Also umgekehrt als im Deutschen!
Siehe oben
% multipliziert die Zahl mit 100 und fügt ein %-Zei-chen an.
Format(0.15, "#,##0.00%") liefert 15,00%Format(0.125, "0.00 %") liefert 12,50 %
E- E+ e- e+ wissenschaftliche Zah-lenschreibweise
Format(1250000, "0.00 E+00") liefert1,25 E+06Format(1250000, "0.00 E-00") liefert1,25 E06Format(1250000, "0.00 e+0") liefert1,25 e+6Format(0.125, "0.00 e-0") liefert1,25 e-1Format(0.000125, "0.00 E-00") liefert1,25 E-04
+, – Leerzei-chen und $
können zur Darstellung direkt in die Formatie-rung eingefügt werden.
Format(1234, "#,##0.00 $") liefert1.234,00 $
\ Das nächste Zeichen wird als Zeichen und nicht als Formatierung ausgegeben. Das »\« verschwindet in der An-zeige.
Format(1234, "#,##0.00 \L\i\r\e") liefert1.234,00 Lire
39
3 Eingebaute Funktionen
Es können bis zu vier verschiedene Zahlenformate in Abschnitten ausgegebenwerden. Dabei bedeuten:
Tab. 3.6:Die Funktion For-
mat und Zahlenund Abschnitte
Datumsformatierungen:
Tab. 3.7:Die Funktion For-mat und Datums-
formatierungen
Zeichen Beschreibung Beispiel
nur ein Ab-schnitt
alle Werte
zwei Ab-schnitte
Der erste Abschnitt be-zieht sich auf positive Werte und die Null, der zweite auf negative.
Format(123, "0;(0)") liefert123
drei Ab-schnitte
Wie zwei Abschnitte; der dritte Abschnitt bezieht sich auf die Null.
Format(-123, "0;(0);\N\i\x") liefert(123)
vier Ab-schnitte
Wie drei Abschnitte; der vierte Abschnitt bezieht sich auf Null-Werte.
Format(0, "0;(0);\N\i\x") liefertNix
Zeichen Beschreibung Beispiel
/ Datumstrennzeichen
d zeigt den Tag als Zahl. Format("2.3.2000", "d/m/yy") liefert 2.3.00
dd zeigt den Tag als Zahl und Tage zwischen 1 und 9 mit führender Null an.
Format("2000", "dd/mm/yyyy") liefert02.03.2000
ddd zeigt den Wochentag als Abkürzung.
Format("2.3.2000", "ddd") liefert So
dddd zeigt den Wochentag ausgeschrieben.
Format("2 / 3 / 2000", "dddd, \d\e\n dd. mmmm. yyyy") liefertSonntag, den 02. März 2000
ddddd zeigt das vollständige Da-tum gemäß der System-steuerung im Kurzfor-mat an (dd.mm.yy).
Format("2 / 3 / 2000", "ddddd") liefert02.03.00
dddddd zeigt das vollständige Da-tum gemäß der System-steuerung im Langformat an (dd.mmmm.yyyy).
Format("2 / 3 / 2000", "dddddd ") liefertSonntag, 02 März 2000
w der Wochentag als Zahl (1 = Sonntag, 7 = Sams-tag
Format("2.3.2000", "w") liefert 5
40
Die Funktion Format
Die Zeitangaben:
Tab. 3.8: Die Funktion Format und Zeitformatierungen
ww die Kalenderwoche (1–54)
Format("2.3.2000", "ww") liefert 10, was falsch ist. Die korrekte Funktion für Europa muss lauten:Format("2.3.2000", "ww", , vbFirstFour-Days)
m der Monat als Zahl (1–12)
mm der Monat als Zahl. Mo-nate zwischen 1 und 9 mit führender Null
mmm Monat als Text mit drei Buchstaben (Jan–Dez)
mmmm vollständiger Monats-name
q Quartal Format("2.3.2000", "q") liefert 1
yy Jahr als zweistellige Zahl (00-99)
yyyy Jahr als vierstellige Zahl (100-9999)
Zeichen Beschreibung Beispiel
Zeichen Beschreibung Beispiel
: Zeittrennzeichen
h Stunde als Zahl ohne füh-rende Null
Format(»2:4«, »h:m«) liefert 2:4
hh Stunde als Zahl mit füh-render Null
Format(»2:4«, »hh:mm«) liefert 02:04
n oder m die Minute ohne füh-rende Null
Format(»15:4«, »hh:mm«) liefert 15:04
nn oder mm die Minute mit führender Null
s die Sekunden ohne füh-rende Null
ss die Sekunden mit führen-der Null
ttttt die vollständige Zeitan-gabe
Format(»2:4«, »ttttt«) liefert 02:04:00
AM/PM, am/pm, A/P, A/p, AMPM
verschiedene 12-Stun-den-Formate
41
3 Eingebaute Funktionen
Zeichenformatierungen:
Tab. 3.9:Die Funktion For-mat und Zeichen-
formatierungen
3.6 Umwandlungsfunktionen
Tab. 3.10:Umwandlungs-
funktionen
Zeichen Beschreibung Beispiel
@ Platzhalter für ein Zeichen. Ist die Variable leer, wird ein Leerzeichen ausgegeben.
Format("Sonnenschein", "@") liefert"Sonnenschein"
& Platzhalter für ein Zeichen. Ist die Variable leer, wird ein Nichts ausgegeben.
Format("Sonnenschein", "&") liefert"Sonnenschein"
! Auffüllen aller Platzhalter von links nach rechts.
Format("Sonnenschein", "!") liefert"Sonnenschein"
< zeigt den Text in Kleinbuch-staben.
Format("Sonnenschein", "<") liefert"sonnenschein"
> zeigt den Text in Großbuch-staben.
Format("Sonnenschein", ">") liefert"SONNENSCHEIN"
Funktion Rückgabetyp Bereich des Arguments Ausdruck
Cbool Boolean Eine gültige Zeichenfolge oder ein gültiger numeri-scher Ausdruck
Cbyte Byte 0 bis 255
Ccur Currency -922.337.203.685.477,5808 bis 922.337.203.685.477,5807.
Cdate Date Ein beliebiger gültiger Datumsausdruck.
CDbl Double -1,79769313486231E308 bis -4,94065645841247E-324 für negative Werte; 4,94065645841247E-324 bis 1,79769313486232E308 für positive Werte.
CDec Decimal +/-79.228.162.514.264.337.593.543.950.335 für skalierte Ganzzahlen, d.h. Zahlen ohne Dezimalstellen. Für Zahlen mit 28 Dezimalstellen gilt der Bereich +/-7,9228162514264337593543950335. Die kleinste mögliche Zahl ungleich Null ist 0,0000000000000000000000000001.
CInt Integer -32.768 bis 32.767; Nachkommastellen werden ge-rundet.
CLng Long -2.147.483.648 bis 2.147.483.647; Nachkommastel-len werden gerundet.
CSng Single -3,402823E38 bis -1,401298E-45 für negative Werte; 1,401298E-45 bis 3,402823E38 für positive Werte.
42
Umwandlungsfunktionen
Übung 1
Berechnen Sie Ostersonntag! Die Lösung dieses Problems stammt vom Mathe-matiker, Astronom und Physiker Carl Friedrich Gauß, und sieht wie folgt aus:Die Jahreszahl sei J und J – 1900 sei a. Der Rest von a/19 wird schlicht b ge-nannt. Jetzt wird vom Ausdruck (7*b+1)/19 der ganzzahlige Quotient genom-men, der c genannt wird. Mit d wird der Rest von (11*b+4-c)/29 bezeichnetund der Quotient von a/4 mit e. Dann bleibt noch der Rest von (a+e+31-d)/7.Und dieser soll f genannt werden. Daraus folgt, dass für das Osterdatum Aprildie Formel 25 – d – f gilt.
Soll beispielsweise von 1999 der Ostersonntag berechnet werden, so ergebensich folgende Werte:
� J = 1999
� a = 99
� b = REST(99;19) = 4
� c = QUOTIENT(7*4+1;19) = 1
� d = REST(11+4+4-1;29) = 18
� e = QUOTIENT(99;4) = 24
� f = REST(99+24+31-18;7) = 3
� Ostern =DATUM(1999;4;25-18-1) = 04.04.1999
Analog für das Jahr 2000:
� a = 100; b = 5; c = 1; d = 0; e = 25; f = 2; Ostern = 23.04.2000
Übung 2
Die Funktion Round rundet nur Stellen nach dem Dezimalzeichen. Lassen Sie mitihrer Hilfe vor dem Komma runden, also beispielsweise 1.234.567 ergibt auf 2Stellen vor dem Komma 1.234.600 und auf 6 Stellen: 1.000.000.
Cvar Variant Numerische Werte im Bereich des Typs Double. Nicht-numerische Werte im Bereich des Typs String.
CStr String Rückgabe für CStr hängt vom Argument Ausdruck ab.
3.7 Übungen zu den mathematischen Funktionen
Funktion Rückgabetyp Bereich des Arguments Ausdruck
43
3 Eingebaute Funktionen
Übung 3
Schreiben Sie eine Prozedur, die einen Namen mit Vornamen und Zunamen inVor- und Zunamen zerlegt.
Übung 4
Schreiben Sie eine Prozedur, die aus einem Dateipfad den Dateinamen (ohneEndung) herausliest.
Übung 5
Schreiben Sie eine Prozedur, die überprüft, ob von einem eingegebenen Textdas erste Zeichen eine Ziffer ist.
Übung 6
Der Benutzer oder die Benutzerin wird aufgefordert, ein »m« oder ein »w« fürdas Geschlecht einzugeben. Gibt er oder sie weder ein »w«, »W«, »m« nochein »M« ein, dann wird er oder sie darauf hingewiesen.
Übung 7
Der Benutzer gibt sein Geburtsdatum ein und erhält als Ergebnis sein Alter.
Übung 8
Der Benutzer gibt sein Geburtsdatum ein. Daraufhin wird überprüft, ob er Ge-burtstag hat (oder wie viele Tage bis zu seinem Geburtstag fehlen), an welchemWochentag er Geburtstag hatte und an welchem Wochentag er im aktuellenJahr Geburtstag hatte oder haben wird.
Übung 9
In Übung 1 des Kapitels 2 (»Operatoren, Verknüpfungen und Verzweigungen«)wird die Hypothenuse aus der Länge zweier Katheten berechnet. FormatierenSie die Ausgabe so, dass das Ergebnis immer auf 4 Stellen nach dem Komma er-scheint.
3.8 Übungen zu den Textfunktionen
3.9 Übungen zu den Datumsfunktionen
3.10 Übungen zu den Formatfunktionen
44
Tipps
Übung 10
Ein Benutzer gibt seinen Arbeitsbeginn und sein Arbeitsende ein. Daraus wirddie Differenz berechnet. Für jede Stunde erhält er 15,75 Euro. Schließlich wirdsein berechneter Arbeitslohn angezeigt.
Tipp zu Übung 3
Wenn Sie mit der Funktion InStr arbeiten, dann achten Sie darauf, dass sie einbestimmtes Zeichen von links ermittelt. Was für den Vornamen problemlosfunktioniert, klappt für den Nachnamen nicht! Neben InStr stehen Ihnen aller-dings auch noch andere Funktionen zur Verfügung.
Tipp zu Übung 7
Achtung: Um das Alter zu bestimmen, dürfen Sie nicht einfach die Jahreszahldes heutigen Datums von der Jahreszahl des Geburtsdatums abziehen. Wennheute beispielsweise der 20. Oktober 2000 ist, der Benutzer allerdings 10. No-vember 1980 eingibt, so ist er nicht 20 Jahre, sondern nur 19. Auch die Diffe-renz in Tagen geteilt durch 365,25 kann zu Ungenauigkeiten führen.
Lösung 1
Sub Ostersonntag()Dim intJahreszahl As IntegerDim a As Integer, b As Integer, c As IntegerDim d As Integer, e As Integer, f As IntegerintJahreszahl = InputBox("Bitte eine Jahreszahl eingeben!")a = intJahreszahl – 1900b = a Mod 19c = (7 * b + 1) \ 19d = (11 * b + 4 – c) Mod 29e = a \ 4f = (a + e + 31 – d) Mod 7MsgBox Format(DateSerial(intJahreszahl, 4, 25 – d – f), _ "dd.mm.yyyy")End Sub
3.11 Tipps
3.12 Lösungen
45
3 Eingebaute Funktionen
Lösung 2
Sub RundenVorKomma()Dim dblZahl As DoubleDim intRundZahl As Integer
dblZahl = InputBox("Bitte eine Zahl eingeben!")intRundZahl = InputBox("Auf wie viele Stellen vor dem " & _ "Komma soll gerundet werden?")
dblZahl = dblZahl / 10 ^ intRundZahldblZahl = Round(dblZahl, 0)dblZahl = dblZahl * 10 ^ intRundZahlMsgBox dblZahlEnd Sub
Lösung 3
Sub NamenZerlegen1()Dim strGanzName As StringDim strVorname As StringDim strNachname As String
strGanzName = InputBox("Wie heißen Sie?", "Vor- und Zuname")If strGanzName = "" Then MsgBox "Sie haben nichts eingegeben!"ElseIf InStr(strGanzName, " ") = 0 Then MsgBox "Sie haben nur einen Namen eingegeben!" Exit SubEnd IfstrVorname = Left$(strGanzName, InStr(strGanzName, " ") – 1)
strNachname = Right$(strGanzName, Len(strGanzName) – _ InStr(strGanzName, " "))
MsgBox "Der Vorname lautet: " & strVorname & _ " und der Nachname lautet: " & strNachnameEnd Sub
Der Zuname kann auch anders herausgelöst werden:
strNachname = Right(strGanzName, _ Len(strGanzName) – Len(strVorname))
Oder so:
strNachname = Mid$(strGanzName, InStr(strGanzName, " ") + 1)
46
Lösungen
VBA 6.0 stellt neue String-Funktionen zur Verfügung: Split, Join, Filter undInStrRev. Mit der Funktion Split kann die Aufgabe ebenso gelöst werden:
Sub NamenZerlegen3()Dim strTeilnamen() As StringDim strGanzName As StringstrGanzName = InputBox("Wie heißen Sie?", "Vor- und Zuname")strTeilnamen = Split(strGanzName)
If strTeilnamen(UBound(strTeilnamen)) = _ strTeilnamen(0) Then MsgBox "Der Vorname lautet: " & strTeilnamen(0)Else MsgBox "Der Vorname lautet: " & strTeilnamen(0) & _ " und der Nachname lautet: " & _ strTeilnamen(UBound(strTeilnamen))End IfEnd Sub
Umgekehrt setzt die Funktion Join einen String wieder zusammen, wobei sieebenfalls einen Array verlangt. Im folgenden Beispiel werden die einzelnenKomponenten wieder zusammengefügt:
Sub NamenZerlegenUndZusammensetzen()Dim strTeilnamen() As StringDim i As IntegerDim strGanzName As String
strGanzName = InputBox("Wie heißen Sie?", "Alle Namen")strTeilnamen = Split(strGanzName)
For i = 0 To UBound(strTeilnamen) strGanzName = Join(strTeilnamen, "")Next
MsgBox strGanzNameEnd Sub
Lösung 4
Die folgenden Befehle können nur in Word verwendet werden. In Excel heißtder vollständige Dateiname ActiveWorkbook.FullName.
Sub DateiNamenZerlegen1()Dim strDateiName As StringDim i As Integer
strDateiName = ActiveDocument.FullNameMsgBox strDateiName
47
3 Eingebaute Funktionen
For i = Len(strDateiName) To 1 Step -1 If Mid(strDateiName, i, 1) = "\" Then strDateiName = Right(strDateiName, _ Len(strDateiName) – i) Exit For End IfNext i
strDateiName = Left(strDateiName, _ InStr(strDateiName, ".") – 1)MsgBox strDateiNameEnd Sub
Ein andere Variante (ohne Schleife) sieht folgendermaßen aus:
Sub DateiNamenZerlegen2()Dim strDateiName As StringDim strTeilNamen() As String
strDateiName = ActiveDocument.FullNameMsgBox strDateiNamestrTeilNamen = Split(strDateiName, "\")strDateiName = strTeilNamen(UBound(strTeilNamen))strDateiName = Left(strDateiName, _ InStr(strDateiName, ".") – 1)MsgBox strDateiNameEnd Sub
Lösung 5
Sub ZifferPrüfung()Dim strEingabeText As String
strEingabeText = InputBox("Bitte einen Text eingeben")If IsNumeric(Left(strEingabeText, 1)) Then MsgBox "Ziffer"Else MsgBox "Zeichen"End If
End Sub
Lösung 6
Sub Geschlechterprüfung1()Dim strGeschlecht As StringstrGeschlecht = InputBox("Bitte ein ""m"" oder ein ""w""" & _ "für das korrekte Geschlecht eingeben!")If strGeschlecht <> "m" And strGeschlecht <> "M" And _
48
Lösungen
strGeschlecht <> "w" And strGeschlecht <> "W" Then MsgBox "Es wurde weder ""m"" noch ""w"" eingegeben." Exit SubEnd If
End Sub
Man kann ebenso die eingegebene Zeichenkette in Kleinbuchstaben verwan-deln:
Sub Geschlechterprüfung2()Dim strGeschlecht As StringstrGeschlecht = InputBox("Bitte ein ""m"" oder ein ""w""" & _ "für das korrekte Geschlecht eingeben!")If LCase(strGeschlecht) <> "m" And _ LCase(strGeschlecht) <> "w" Then MsgBox "Es wurde weder ""m"" noch ""w"" eingegeben." Exit SubEnd IfEnd Sub
Die Bedingung kann auch folgendermaßen abgefragt werden:
If Format(strGeschlecht, "<") <> "m" And _ Format(strGeschlecht, "<") <> "w" Then
Da die Anzahl der Möglichkeiten überschaubar sind, kann auch mit einer Se-lect Case-Anweisung gearbeitet werden:
Sub Geschlechterprüfung4()Dim strGeschlecht As StringstrGeschlecht = InputBox("Bitte ein ""m"" oder ein ""w""" & _ "für das korrekte Geschlecht eingeben!")Select Case strGeschlechtCase "w", "W", "m", "M"Case Else MsgBox "Es wurde weder ""m"" noch ""w"" eingegeben."End SelectEnd Sub
Lösung 7
Sub Alter_in_Jahren()Dim datGebdatum As DateDim intAlter As IntegerdatGebdatum = InputBox("Wann bist du geboren?")intAlter = Year(Date) – Year(datGebdatum)If Month(Date) < Month(datGebdatum) Then intAlter = intAlter – 1Else
49
3 Eingebaute Funktionen
If Month(Date) = Month(datGebdatum) Then If Day(Date) < Day(datGebdatum) Then intAlter = intAlter – 1 End If End IfEnd IfMsgBox "Sie sind " & intAlter & " Jahre alt. "End Sub
Oder noch eleganter:
Sub Alter_in_Jahren2()Dim datGebDatum As DateDim intAlter As IntegerdatGebDatum = InputBox("Wann bist du geboren?")intAlter = Year(Date) – Year(datGebDatum)If DateSerial(Year(Date), Month(datGebDatum), _ Day(datGebDatum)) > Date Then intAlter = intAlter – 1End IfMsgBox "Sie sind " & intAlter & " Jahre alt. "End Sub
Beide Lösungen ziehen vom aktuellen Jahr das Geburtsjahr ab. Die Differenzmuss allerdings noch nicht das Lebensalter sein, denn wenn der Benutzer imlaufenden Jahr noch nicht Geburtstag hatte, dann muss von der Differenz 1 ab-gezogen werden. Das erste Programm überprüft nun Geburtsmonat und Ge-burtstag, während das zweite Programm aus Geburtstag, Geburtsmonat undaktuellem Jahr ein Datum zusammensetzt und dies mit dem heutigen Tag ver-gleicht. In beiden Lösungen wird die Zahl 1 subtrahiert.
Lösung 8
Sub Geburtstag()Dim intTag As IntegerDim intMonat As IntegerDim datGebDatum As DateDim intAnzahlTage As IntegerDim strZukunft As String
datGebDatum = InputBox("Wie lautet Ihr Geburtsdatum?")
intTag = Day(datGebDatum)intMonat = Month(datGebDatum)
If intTag = Day(Date) And intMonat = Month(Date) Then MsgBox "Happy Birthday" strZukunft = "Heute ist "Else
50
Lösungen
intAnzahlTage = DateDiff("D", _ Date, DateSerial(Year(Date) + 1, intMonat, intTag))
If intAnzahlTage >= 365 Then intAnzahlTage = DateDiff("D", _ Date, DateSerial(Year(Date), intMonat, intTag)) strZukunft = " Geburtstag haben." End If
MsgBox "Sorry, Sie haben erst in " & intAnzahlTage & _ " Tagen Geburtstag."
End If
MsgBox "Sie sind an einem " & _ Format(datGebDatum, "DDDD") & " geboren."
If strZukunft = " Geburtstag haben." Then MsgBox "Sie werden in diesem Jahr an einem " & _ Format(DateSerial(Year(Date), intMonat, intTag), _ "DDDD") & strZukunftElseIf strZukunft = "Heute ist " Then MsgBox "Heute ist Ihr Geburtstag." & _ vbCr & strZukunft & Format(Date, "DDDD")Else MsgBox "Sie hatten in diesem Jahr an einem " & _ Format(DateSerial(Year(Date), intMonat, intTag), _ "DDDD") & " Geburtstag."End IfEnd Sub
Lösung 9
Sub RechtwinklDreieck()Dim dblSeiteA As DoubleDim dblSeiteB As DoubledblSeiteA = InputBox("Bitte die Länge der ersten Kathete!")dblSeiteB = InputBox("Bitte die Länge der zweiten Kathete!")MsgBox "Die Länge der Hypothenuse beträgt " & _ Format(Sqr(dblSeiteA ^ 2 + dblSeiteB ^ 2), "0.0000")End Sub
Lösung 10
Sub Lohnberechnen()Dim datBeginn As DateDim datEnde As DateDim datArbeitszeit As Date
51
3 Eingebaute Funktionen
Const curLohn = 15.75
datBeginn = InputBox("Bitte den Arbeitsbeginn eingeben!")datEnde = InputBox("Bitte das Arbeitsende eingeben!")
datArbeitszeit = datEnde – datBeginn
MsgBox "Sie erhalten für Ihre " & _ Format(datArbeitszeit, "hh:mm") & _ " gearbeiteten Stunden " & _ Format(datArbeitszeit * curLohn * 24, "0.00 \E\u\r\o")
End Sub
52
4.1 AufrufWenn eine Prozedur eine andere aufruft, dann kann dies mit dem SchlüsselwortCall geschehen, oder einfach, indem der Name der zweiten Prozedur auf-taucht. Danach wird die erste Prozedur an der Stelle weitergeführt, an der diezweite aufgerufen wurde.
Sub A()Call BEnd Sub
Sub B()MsgBox "Nun ist Ende"End Sub
Zu dem Namen der Prozedur bei der Anweisung Call B kann auch der Namedes Moduls hinzugefügt werden:
Sub A()Call Modul1.BEnd Sub
Alle Lösungen funktionieren nur, wenn B public deklariert wurde. Die Prozedurwird also nicht in einem anderen Modul gefunden, wenn B folgendermaßenaussieht:
Private Sub B()End Sub
4.2 Globale VariablenWird eine Variable in mehreren Prozeduren verwendet, dann wird der Wert»global«, das heißt »modulweit« oder »projektweit«, deklariert. Dies ist vor al-lem in den Ereignisprozeduren der Dialoge sehr wichtig. Im folgenden Beispielwird der Inhalt der Variablen strAnzeigeText in den beiden Prozeduren A undB, die sich im gleichen Modul befinden, verwendet.
Dim strAnzeigeText As StringSub A()strAnzeigeText = "Nun ist Ende"Call BEnd Sub
4 Selbsterzeugte Funktionen, Aufrufe, Parameterübergabe
53
4 Selbsterzeugte Funktionen, Aufrufe, Parameterübergabe
Sub B()MsgBox strAnzeigeTextEnd Sub
4.3 ÜbergabeSoll dagegen eine Variable explizit übergeben werden, dann kann die erste Pro-zedur (A) diese Werte auf zweierlei Weise an Prozedur B übergeben: Werdendie alten Werte in der Prozedur noch verwendet, dann geschieht die Übergabe»Call by Value«, das heißt, die alten Werte sind in der Prozedur A noch vorhan-den. Wird dagegen Prozedur B mit »Call by Reference« aufgerufen, dann wirdder veränderte Werte in A verwendet. Die Prozedur B könnte so aussehen:
Sub B(ByRef X As Integer, ByVal Y As Integer)
End Sub
Im ersten Fall werden die Werte 1 und 2 von A an B übergeben. Dort wird zu ih-nen ein Wert addiert – und so werden sie am Ende der Prozedur A angezeigt(als 2 und 4):
Sub A()Dim X As Integer, Y As IntegerX = 1: Y = 2B X, YMsgBox "x: " & X & " y: " & YEnd Sub
Sub B(ByRef X As Integer, ByRef Y As Integer)X = X + 2: Y = Y + 2End Sub
Anders dagegen in folgendem Fall: Die Werte werden »By Value« übergeben,das heißt bei der Rückgabe halten sich die alten Werte. In Prozedur A werdenalso 1 und 2 angezeigt.
Sub A()Dim X As Integer, Y As IntegerX = 1: Y = 2B X, YMsgBox "x: " & X & " y: " & YEnd Sub
Sub B(ByVal X As Integer, ByVal Y As Integer)X = X + 2: Y = Y + 2End Sub
54
Übergabe
Beachten Sie, dass hinter der Prozedur B ein Leerzeichen steht! Wird nicht nurder Inhalt einer Variablen sondern eines Arrays übergeben, dann kann dies mitdem Befehl ParamArray geschehen. Im folgenden Beispiel werden drei Werteübergeben, wo sie in einem Datenfeld gespeichert und weiter verarbeitet wer-den:
Sub A()Dim X As Integer, Y As Integer, Z As IntegerX = 1: Y = 2: Z = 3B X, Y, ZEnd Sub
Sub B(ParamArray Werte())Dim intErgebnis As IntegerDim Element As VariantFor Each Element In Werte intErgebnis = intErgebnis + Element ^ 2NextMsgBox intErgebnisEnd Sub
Das Ergebnis, das in B angezeigt wird, lautet 14.
Wird eine Prozedur verwendet, um einen Wert zu übergeben und einen (nur ei-nen!) Wert zurückzugeben, dann kann als Funktion geschrieben werden:
Sub A()Dim X As Integer, Y As Integer, Z As IntegerX = 1: Y = 2Z = B(X, Y)MsgBox "Z: " & ZEnd Sub
Function B(X As Integer, Y As Integer) As IntegerB = X + YEnd Function
Da die Funktion B direkt zurückgegeben wird, wird sie immer als »By Refe-rence« aufgerufen. Somit ist die genaue Spezifizierung überflüssig!
55
4 Selbsterzeugte Funktionen, Aufrufe, Parameterübergabe
Welcher Wert wird gemeldet?
Übung 1
Sub Meldung01()Dim x As Integerx = 1.25MsgBox xEnd Sub
Übung 2
Sub Meldung02()Dim x As Integer x = 7 Meldung03End Sub
Sub Meldung03()Dim x As Integer MsgBox xEnd Sub
Übung 3
Dim y As IntegerSub Meldung04() y = 7 Meldung05End Sub
Sub Meldung05() MsgBox yEnd Sub
Übung 4
Sub Meldung06()Dim x As Integer x = 7 Meldung07 xEnd Sub
Sub Meldung07(y) MsgBox yEnd Sub
4.4 Übungen
56
Übungen
Übung 5
Sub Meldung08()Dim x As IntegerDim y As Integer x = 3 y = 4 Meldung09 x, yEnd Sub
Sub Meldung09(ByRef a As Integer, ByVal b As Integer) MsgBox a ^ 2 + b ^ 2End Sub
Übung 6
Sub Meldung10()Dim x As IntegerDim y As Integer x = 3 y = 4 Meldung11 x, y MsgBox x + yEnd Sub
Sub Meldung11(ByRef x As Integer, ByVal y As Integer) x = x ^ 2 y = y ^ 2End Sub
Übung 7
Sub Meldung12()Dim x As IntegerDim y As Integer x = 3 y = 4 MsgBox Meldung13(x, y)End Sub
Function Meldung13(ByRef a As Integer, ByVal b As Integer) Meldung13 = a ^ 2 + b ^ 2End Function
57
4 Selbsterzeugte Funktionen, Aufrufe, Parameterübergabe
Lösung 1
Es wird 1 gemeldet. Grund: Die Variable x wurde falsch (zu klein) deklariert.
Lösung 2
Es wird 0 gemeldet. Grund: Die Variable x wurde in jeder Prozedur deklariertund deshalb beim Aufruf von Meldung03 nicht übergeben.
Lösung 3
Es wird 7 gemeldet. Grund: Die Variable y wurde global (modulweit) deklariertund deshalb beim Aufruf von Meldung05 übergeben.
Lösung 4
Es wird 7 gemeldet. Grund: Die Variable x wird als Parameter übergeben. Dabeistört nicht, dass in Meldung07 ein anderer Variablenname verwendet wird.
Lösung 5
Es wird 25 gemeldet. Grund: Die Variablen x und y werden als Parameter über-geben. Dabei stört weder, dass in Meldung09 andere Variablennamen verwen-det werden, noch die Art der Übergabe.
Lösung 6
Es wird 13 gemeldet. Grund: Die Variable x wird als Parameter »by Reference«übergeben. Sie wird in der Prozedur Meldung11 quadriert und so zurückgege-ben. Nun wird mit 9 und nicht mehr mit 3 weitergerechnet. Da y »by Value«übergeben wird, wird sein Wert (4) nicht verändert.
Lösung 7
Es wird 25 gemeldet. Grund: Die Variablen x und y werden an eine Funktionübergeben. Dabei spielt die Art keine Rolle. Die Funktion selbst (Meldung13)übergibt nun das Ergebnis. Die Übergabe der Variablen y »by Value« ist deshalbunsinnig!
4.5 Lösungen
58
Schleifen haben die Aufgabe, eine oder mehrere Anweisungen mehrmals zuwiederholen. Dabei stehen Ihnen zwei verschiedene Arten zur Verfügung. Beieiner Zählerschleife (oder unbedingten Schleife) wird eine feste Anzahl vonSchritten durchlaufen. In der Regel weiß man zu Beginn schon, wie oft dieseSchleife durchlaufen werden soll. In Bedingungsschleifen wird die Wiederho-lung so lange ausgeführt, bis die Bedingung erfüllt ist.
Wichtig: Beim Testen können leicht Endlosschleifen entstehen. Um eine solchezu unterbrechen, kann das Programm mit Hilfe der Tastenkombination(Strg)+(Pause) angehalten werden!
5.1 ZählerschleifenDie Zählerschleife For ... Next:
For Zähler = Anfang To Ende [Step Schritt][Anweisungen][Exit For][Anweisungen]Next [Zähler]
Die Syntax für die For…Next-Anweisung besteht aus folgenden Teilen:
Tab. 5.1: Die Elemente der For...Next-Schleife
VBA stellt für Objektsammlungen eine spezielle Form der Zählerschleife zur Ver-fügung: die For Each ... Next-Schleife. Die Syntax lautet:
For Each Element In Gruppe[Anweisungen][Exit For][Anweisungen]Next [Element]
5 Schleifen, rekursives Programmieren
Teil Beschreibung
Zähler ist eine numerische Variable, die als Schleifenzähler dient.
Anfang Der Startwert von Zähler
Ende Der Endwert von Zähler
Schritt ist optional. Es ist ein Betrag, um den Zähler bei jedem Schleifendurch-lauf verändert wird. Falls kein Wert angegeben wird, ist die Voreinstel-lung für Schritt eins. Schritt lässt ganze und Dezimalzahlen zu.
Exit For Mit diesem Befehl kann die Schleife vorzeitig beendet werden.
59
5 Schleifen, rekursives Programmieren
Die Syntax für die For...Each...Next-Anweisung besteht aus folgenden Teilen:
Tab. 5.2:Die Elemente derFor...Each...Next-
Schleife
Die erste und zweite verschachtelte Schleife im folgenden Beispiel durchläuftdie Werte von 1 bis 8, beziehungsweise von A bis H. An das Feld strSchachFel-der werden diese Zeichenketten übergeben. Die dritte Schleife durchläuft nunalle Felder des zweidimensionalen Arrays und zeigt die einzelnen Werte an.
Sub SchachSchleife()Dim strSchachFelder(1 To 8, 1 To 8) As StringDim varSchachFeld As VariantDim i As ByteDim j As Byte
For i = 1 To 8 For j = 1 To 8 strSchachFelder(i, j) = Chr(64 + i) & j Next jNext i
For Each varSchachFeld In strSchachFelder MsgBox varSchachFeldNext
End Sub
5.2 BedingungsschleifenDie Bedingung kann entweder am Anfang oder Ende einer Bedingungsschleifestehen. Man spricht auch von kopf- und fußgesteuerten Schleifen. Steht die Be-dingung am Ende, dann wird die Schleife immer (mindestens) einmal betreten.Steht sie am Kopf, so wird überprüft, ob die Schleife überhaupt betreten wer-den darf. Die Syntax lautet:
Do [{While | Until} Bedingung][Anweisungen][Exit Do][Anweisungen]Loop
Oder:
Teil Beschreibung
Element ist eine Variable zum Durchlauf durch die Elemente der Auflistung oder des Datenfeldes. Bei Datenfeldern ist für Element nur eine Variable vom Typ Variant zulässig.
Gruppe ist der Name einer Objektauflistung oder eines Datenfeldes (außer Da-tenfeldern mit benutzerdefinierten Typen).
60
Bedingungsschleifen
Do[Anweisungen][Exit Do][Anweisungen]Loop [{While | Until} Bedingung]
Ein Anfangskapital wird zu 7,5% verzinst. Wie viele Jahre benötigt man, damites sich verdoppelt hat? Man kann diese Aufgabe mit allen vier Möglichkeitenberechnen lassen. Der Vollständigkeit halber sollen sie angezeigt werden:
Variante 1:
Sub KapitalVerdoppeln1()Dim curKapital As CurrencyDim curZielKapital As CurrencyDim intJahre As Integer
curKapital = InputBox("Wie viel möchten Sie anlegen?")curZielKapital = curKapital * 2
Do Until curKapital >= curZielKapital curKapital = curKapital * 1.075 intJahre = intJahre + 1Loop
MsgBox intJahre & " Jahre werden zum Verdoppeln benötigt."End Sub
Variante 2:
Sub KapitalVerdoppeln2()Dim curKapital As CurrencyDim curZielKapital As CurrencyDim intJahre As Integer
curKapital = InputBox("Wie viel möchten Sie anlegen?")curZielKapital = curKapital * 2
Do While curKapital < curZielKapital curKapital = curKapital * 1.075 intJahre = intJahre + 1Loop
MsgBox intJahre & " Jahre werden zum Verdoppeln benötigt."End Sub
61
5 Schleifen, rekursives Programmieren
Variante 3:
Sub KapitalVerdoppeln3()Dim curKapital As CurrencyDim curZielKapital As CurrencyDim intJahre As Integer
curKapital = InputBox("Wie viel möchten Sie anlegen?")curZielKapital = curKapital * 2
Do curKapital = curKapital * 1.075 intJahre = intJahre + 1Loop While curKapital < curZielKapital
MsgBox intJahre & " Jahre werden zum Verdoppeln benötigt."End Sub
Variante 4:
Sub KapitalVerdoppeln4()Dim curKapital As CurrencyDim curZielKapital As CurrencyDim intJahre As Integer
curKapital = InputBox("Wie viel möchten Sie anlegen?")curZielKapital = curKapital * 2
Do curKapital = curKapital * 1.075 intJahre = intJahre + 1Loop Until curKapital >= curZielKapital
MsgBox intJahre & " Jahre werden zum Verdoppeln benötigt."End Sub
Übrigens: finanzmathematisch ist dieses Beispiel Unsinn. Wird ein Kapital x zueinem Prozentsatz von 7,5% Zinsen angelegt, dann beträgt das Kapital nach nJahren:
Setzt man nun KEnde = KStart * 2, dann folgt aus der Formel:
2 = (1+p)n
oder:
n = log(1+p)2 = lg(2)/lg(1+p)
�
������������ ��� +×=
62
Rekursionen
Für p = 0,075 ergibt sich aus der Formel: n ≈ 9,584. Das heißt, dass sich das Ka-pital bei 7,5% Zinsen nach zehn Jahren verdoppelt hat – unabhängig vom ur-sprünglichen Kapital.
Daneben findet sich noch (aus historischen Gründen) die While … Wend-Schleife.Auf sie soll an dieser Stelle nicht eingegangen werden: Sie ist nicht so flexibelwie die Do … Loop-Schleifen. Es gibt keinen Fall, in dem sie Vorteile gegenüberden anderen Schleifen hätte.
5.3 RekursionenEine besondere Art der Schleifen sind Funktionen, die sich selbst aufrufen. Da-mit sie sich nicht unendlich oft aufrufen, stehen diese Aufrufe in der Regel in ei-ner Verzweigung. Das Standardbeispiel für Rekursionen ist das Berechnen derFakultät. Die Fakultät einer Zahl ist das Produkt aller Zahlen (ab 1) bis zu derZahl. Die Fakultät von 5 lautet 120, da
5! = 1*2*3*4*5
oder allgemein:
n! = n*(n-1)*(n-2)* ... * 2 * 1
Dies kann über eine Zählerschleife berechnet werden:
Sub Fakultät1()Dim intZahl As IntegerDim dblFakultät As DoubleDim intZähler As Integer
intZahl = InputBox("Bitte eine Zahl zur Fakultätsberechnung")dblFakultät = 1
For intZähler = 1 To intZahl dblFakultät = dblFakultät * intZählerNext
MsgBox "Die Fakultät von " & intZahl & _ " lautet: " & dblFakultät
End Sub
Oder mit einer Bedingungsschleife:
Sub Fakultät2()Dim intZahl As IntegerDim dblFakultät As Double
intZahl = InputBox("Bitte eine Zahl zur Fakultätsberechnung")
63
5 Schleifen, rekursives Programmieren
dblFakultät = 1
Do While intZahl > 1 dblFakultät = dblFakultät * intZahl intZahl = intZahl – 1Loop
MsgBox "Die Fakultät von " & intZahl & _ " lautet: " & dblFakultät
End Sub
Oder schließlich rekursiv. Die Funktion Fakultät3 wird solange aufgerufen, bisintZahl den Wert 1 erreicht hat (beim Herabzählen).
Function Fakultät3(intZahl As Integer) As DoubleIf intZahl > 1 Then Fakultät3 = intZahl * Fakultät3(intZahl – 1)Else Fakultät3 = 1End IfEnd Function
Dies kann mit folgender Prozedur aufgerufen werden:
Sub FakultätBerechnen()Dim intZahl As IntegerDim dblFakultät As DoubleintZahl = InputBox("Bitte eine Zahl zur Fakultätsberechnung")dblFakultät = Fakultät3(intZahl)
MsgBox "Die Fakultät von " & intZahl & _ " lautet: " & dblFakultätEnd Sub
Oder auch mit einer aufsteigenden Zählung:
Dim intZahl As IntegerDim intEndZahl As IntegerFunction Fakultät4(intZahl As Integer) As Double
Fakultät4 = 1
If intZahl <= intEndZahl Then Fakultät4 = intZahl * Fakultät4(intZahl + 1)End IfEnd Function
Sub FakultätBerechnen()
64
Rekursionen
Dim intZahl As Integer
intZahl = InputBox("Bitte eine Zahl zur Fakultätsberechnung")
intEndZahl = intZahldblFakultät = Fakultät4(1)
MsgBox "Die Fakultät von " & intZahl & _ " lautet: " & dblFakultät
End Sub
Zugegeben: die erste Variante ist natürlich eleganter!
Übung 1
Eine Schnecke sitzt vor einer 4,5 Meter hohen Mauer. Jeden Tag klettert sie 50cm nach oben, in jeder Nacht rutscht sie 10% ihrer Gesamthöhe nach unten.Wann ist sie oben?
Also: Sie beginnt bei 0 m, klettert am ersten Tag auf 0,5 m, rutscht um 0,05 mnach unten, so dass sie den zweiten Tag bei 0,45 m beginnt. Von dort klettertsie auf 0,95 m, um in der folgenden Nacht auf 0,95 m – 0,095 m = 0,855 m zulanden. Dann klettert sie auf 1,355 m und rutscht auf 1,2195 m herunter. Undso weiter. Die Rekursion lässt sich gut in eine Schleife einbauen. Versuchen Sieverschiedene Varianten!
Übung 2
Horst wird gefragt, wie alt seine vier Kinder sind. Er gibt als Antwort: »Das Pro-dukt ihrer Alter beträgt 1536, die Summe 30.« Er überlegt und fügt hinzu: »DieJüngste heißt Claudia.« Wie alt sind seine Kinder?
Übung 3
Eine Benutzerin oder ein Benutzer wird nach ihrem oder seinem Geschlecht ge-fragt. Nun soll diese Frage penetrant so lange wiederholt werden, bis sie oder erein korrektes »w« oder »m« eingibt.
Übung 4
Der Benutzer gibt eine Zahl ein, die daraufhin überprüft wird, ob es sich umeine Primzahl handelt oder nicht.
5.4 Übungen
65
5 Schleifen, rekursives Programmieren
Übung 5
Der Benutzer gibt zwei Zahlen ein, von denen das kleinste gemeinsame Vielfa-che (kgV) und der größte gemeinsame Teiler (ggT) ermittelt wird.
Übung 6
Zwar wurde vor einiger Zeit die Fermat’sche These gelöst, aber dennoch gibt eseine Reihe von Problemen, die noch nicht gelöst sind. Das Collatz’sche Problemgehört dazu:
Man nehme eine beliebige Zahl. Ist diese Zahl gerade, dann wird sie durch 2 ge-teilt. Ist sie dagegen ungerade, dann wird sie mit drei multipliziert und um einsvergrößert; beispielsweise 20:
20 → 10 → 5 → 16 → 8 → 4 → 2 → 1 → 4 → 2 → 1 → 4 → 2 → 1 → ...
oder 21:
21 → 64 → 32 → 16 → 8 → 4 → 2 → 1 → 4 → 2 → 1 → ...
oder 19:
19 → 58 → 29 → 88 → 44 → 22 → 11 → 34 → 17 → 52 → 26 → 13 → 40 →20 → ...
Jede Reihe endet schließlich in der Folge 1 → 4 → 2 → 1. Schreiben Sie ein Pro-gramm, bei dem der Benutzer eine Zahl eingibt, die mit der Collatz’schen Me-thode auf 1 zurückgeführt wird.
Übung 7
Schreiben Sie eine Funktion, die die Quersumme einer Zahl berechnet. Entwi-ckeln Sie daraus eine rekursive Funktion, die die Endquersumme berechnet.
Übung 8
Leonardo Fibonacci (1170 – 1250) entdeckte eine Reihe, die mit 1 und 1 be-ginnt. Jede folgende Zahl entsteht als Summe der beiden Vorgänger. Also:
1, 1, 2, 3, 5, 8, 13, 21, 34 und so weiter.
Programmieren Sie eine Fibonacci-Reihe iterativ und rekursiv!
Tipp zu Übung 1
In dieser Aufgabe steckt ein umgangssprachliches Problem! Wenn man sagt,dass man von einer Zahl 10% abzieht, so darf nicht x – 10% gerechnet werden,
5.5 Tipps
66
Tipps
sondern x – x*10%. Andererseits interessieren nicht die 10%, sondern die übri-gen 90%. Und da VBA nicht mit Prozentwerten rechnen kann, so kann dieNachthöhe mit 0.9 multipliziert werden.
Tipp zu Übung 2
Man kann diese Aufgabe recht einfach durch mehrere ineinander verschach-telte Schleifen lösen. Die erste Schleife läuft vom Produkt 1536 bis 1 herunter.Die zweite Schleife nur noch von der Zahl der ersten Schleife bis 1, die dritte vonder Zahl der zweiten Schleife und so weiter. In jeder Schleife wird überprüft, obder Schleifenzähler ein Teiler von 1536 ist. Falls ja, dann läuft die nächsteSchleife los. Im Inneren der vierten Schleife wird die Summe und das Produktder vier Zahlen gezogen. Beträgt die Summe 30 und das Produkt 1536, dann isteine Lösung gefunden. Für diese Aufgabe existieren zwei Lösungen: (16/6/4/4)und (12/8/8/2). Da es eine jüngste Tochter gibt, muss die zweite Lösung die kor-rekte sein. Dies kann übrigens auch in die (innere) Schleife eingebaut werden.
Tipp zu Übung 4
Eine Primzahl ist eine Zahl, die nur durch 1 und durch sich selbst teilbar ist. Alsomuss man von allen Zahlen zwischen einschließlich 2 und der Zahl -1 überprü-fen, ob sie ein Teiler der Zahl sind. Es genügt sogar bei √(Zahl) aufzuhören.Hätte beispielsweise die Zahl 25 einen Teiler < 5, dann hätte sie auch einen (zu-gehörigen) Teiler > 5.
Tipp zu Übung 5
Natürlich könnte man eine Primfaktorzerlegung vornehmen. Vom program-miertechnischen Aufwand her ist es einfacher, für das ggT alle Zahlen kleiner alsdie kleinste der beiden Zahlen zu überprüfen, ob sie Teiler von beiden Zahlen ist.Für das kgV werden alle Zahlen größer als die größte der beiden Zahlen über-prüft, ob beide Zahlen Teiler von dieser Zahl sind.
Tipp zu Übung 7
Es existieren zwei Lösungsvarianten für dieses Problem. Eine unschöne Variantewandelt die Zahl in eine Zeichenkette um, die nun Zeichen für Zeichen durch-laufen wird, eine elegante Variante löst die Aufgabe »mathematisch«, dasheißt: es wird mittels geschicktem Runden die letzte Ziffer herausgelöst. Ist eineder beiden Lösungen gefunden, dann kann die Endquersumme schnell berech-net werden.
Tipp zu Übung 8
Die iterative Lösung stellt sicherlich kein Problem dar. Die rekursive Lösung ruftsich selbst auf. Dabei muss man wissen, dass F(x) = F(x-1) + F(x-2).
67
5 Schleifen, rekursives Programmieren
Lösung 1
Sub Schneckenproblem1()Dim intTage As IntegerDim dblMorgenHöhe As Double, dblAbendhöhe As Double
dblMorgenHöhe = 0intTage = 0
Do While dblAbendhöhe < 4.5 intTage = intTage + 1 dblAbendhöhe = dblMorgenHöhe + 0.5 dblMorgenHöhe = dblAbendhöhe * 0.9Loop
MsgBox "Die Schnecke benötigt " & intTage & " Tage."End Sub
Analog kann die Schleife auch begonnen werden:
Do Until dblAbendhöhe >= 4.5
Oder man formuliert die Bedingung am Schleifenrumpf:
Sub Schneckenproblem2()Dim intTage As IntegerDim dblMorgenHöhe As Double, dblAbendhöhe As Double
dblMorgenHöhe = 0intTage = 0
Do intTage = intTage + 1 dblAbendhöhe = dblMorgenHöhe + 0.5 dblMorgenHöhe = dblAbendhöhe * 0.9Loop Until dblAbendhöhe >= 4.5
MsgBox "Die Schnecke benötigt " & intTage & " Tage."End Sub
Oder analog:
Loop While dblAbendhöhe < 4.5
Lösung 2
Sub KindAlterBerechnen()Const KProdukt = 1536
5.6 Lösungen
68
Lösungen
Const KSumme = 30
Dim intAlter1 As DoubleDim intAlter2 As DoubleDim intAlter3 As DoubleDim intAlter4 As Double
For intAlter1 = KProdukt To 1 Step -1 If KProdukt Mod intAlter1 = 0 Then For intAlter2 = intAlter1 To 1 Step -1 If (KProdukt / intAlter1) Mod intAlter2 = 0 Then For intAlter3 = intAlter2 To 1 Step -1 If (KProdukt / intAlter2) Mod intAlter3 = _ 0 Then For intAlter4 = intAlter3 To 1 Step -1 If (KProdukt / intAlter3) Mod _ intAlter4 = 0 Then If (intAlter1 + intAlter2 + _ intAlter3 + intAlter4 = _ KSumme) And (intAlter1 * intAlter2 _ * intAlter3 * intAlter4 = _ KProdukt) Then MsgBox "Horsts Kinder haben " & _ "folgendes Alter:" _ & vbCr & intAlter1 & "/" & _ intAlter2 & "/" & intAlter3 & _ "/" & intAlter4 End If End If Next End If Next End If Next End IfNextEnd Sub
Man muss nur die innere Schleife modifizieren in:
For intAlter4 = intAlter3 – 1 To 1 Step -1
dann wird nur die eine Lösung angezeigt. Natürlich kann man die Lösung nochbesser ausfeilen. Die vierte, innere Schleife ist überflüssig, da sich die vierte Zahlals Quotient von Kprodukt und dem Produkt aus intAlter1, intAlter2 undintAlter3 berechnet. Sicherlich könnte man die Schleifen auch in einer Funk-tion auslagern. Dies sei dem Leser überlassen.
69
5 Schleifen, rekursives Programmieren
Lösung 3
Sub Begrüßung1()Dim strname As StringDim strgeschlecht As StringDostrgeschlecht = InputBox("Wie lautet Ihr Geschlecht?" & _vbCr & "Bitte ""m"" oder ""w"" eingeben!", "Name")
If strgeschlecht = "w" Or strgeschlecht = "W" Then strname = InputBox("Wie lautet Ihr Name?", "Name") MsgBox "Hallo, liebe " & strnameElseIf LCase(strgeschlecht) = "m" Then strname = InputBox("Wie lautet Ihr Name?", "Name") MsgBox "Hallo, lieber " & strnameEnd IfLoop Until LCase(strgeschlecht) = "w" Or _ LCase(strgeschlecht) = "m"
End Sub
Die Loop-Schleife kann auch anders formuliert werden:
Loop While LCase(strgeschlecht) <> "w" And _ LCase(strgeschlecht) <> "m"
Lösung 4
Sub Primzahl()Dim dblZahl As DoubleDim dblZähler As Double
dblZahl = InputBox _ ("Von welcher Zahl soll überprüft werden" & _ ", ob es sich um eine Primzahl handelt?", "Prim")
For dblZähler = 2 To Sqr(dblZahl) If dblZahl Mod dblZähler = 0 Then MsgBox dblZahl & " ist keine Primzahl" Exit Sub End IfNext dblZähler
MsgBox dblZahl & " ist eine Primzahl"
End Sub
70
Lösungen
Man könnte auch in Zweierschritten hoch zählen, da nur die ungeraden Zahleninteressant sind. Dann müssen allerdings die ersten Werte überprüft werden.Oder man arbeitet mit einer Bedingungsschleife:
Sub Primzahl2()Dim dblZahl As DoubleDim dblZähler As Double
dblZahl = InputBox("Von welcher Zahl soll überprüft " _"werden, ob es sich um eine Primzahl handelt?", "Prim")
dblZähler = 2
Do Until dblZähler > Sqr(dblZahl) If dblZahl Mod dblZähler = 0 Then MsgBox dblZahl & " ist keine Primzahl." & _ vbCr & "Ein Zähler lautet: " & dblZähler Exit Sub End If dblZähler = dblZähler + 1Loop
MsgBox dblZahl & " ist eine Primzahl"
End Sub
Lösung 5
Sub ggT()Dim dblZahl1 As DoubleDim dblZahl2 As DoubleDim dblKleinsteZahl As DoubleDim dblZähler As Double
dblZahl1 = InputBox("Von welchen Zahlen soll das " & _ "ggT berechnet werden?", "ggT: Zahl1")dblZahl2 = InputBox("Von welchen Zahlen soll das " & _ "ggT berechnet werden?", "ggT: Zahl2")
If dblZahl1 < dblZahl2 Then dblKleinsteZahl = dblZahl1Else dblKleinsteZahl = dblZahl2End If
For dblZähler = dblKleinsteZahl To 1 Step -1 If dblZahl1 Mod dblZähler = 0 And _ dblZahl2 Mod dblZähler = 0 Then
71
5 Schleifen, rekursives Programmieren
MsgBox "Der ggT von " & _ dblZahl1 & " und " & dblZahl2 & _ " lautet: " & dblZähler Exit Sub End IfNext dblZähler
End Sub
Analog das kgV:
Sub kgV()Dim dblZahl1 As DoubleDim dblZahl2 As DoubleDim dblGrößteZahl As DoubleDim dblZähler As Double
dblZahl1 = InputBox("Von welchen Zahlen soll das " & _ "kgV berechnet werden?", "kgV: Zahl1")dblZahl2 = InputBox("Von welchen Zahlen soll das " & _ "kgV berechnet werden?", "kgV: Zahl2")
If dblZahl1 > dblZahl2 Then dblGrößteZahl = dblZahl1Else dblGrößteZahl = dblZahl2End If
For dblZähler = dblGrößteZahl To dblZahl1 * dblZahl2 If dblZähler Mod dblZahl1 = 0 And _ dblZähler Mod dblZahl2 = 0 Then MsgBox "Das kgV von " & _ dblZahl1 & " und " & dblZahl2 & _ " lautet: " & dblZähler Exit Sub End IfNext dblZähler
End Sub
Lösung 6
Sub CollatzschesProblem()Dim dblZahl As DoubleDim strAText As String
dblZahl = InputBox("Welche Zahl soll getestet werden?")strAText = dblZahl
72
Lösungen
Do Until dblZahl = 1 If dblZahl Mod 2 = 0 Then dblZahl = dblZahl / 2 Else dblZahl = dblZahl * 3 + 1 End IfstrAText = strAText & ", " & dblZahlLoop
MsgBox strATextEnd Sub
Lösung 7
Sub QuerBerechnen()Dim dblZahl As DoubledblZahl = InputBox("Bitte eine Zahl eingeben.", "Quersumme")MsgBox "Die Quersumme von " & dblZahl & " lautet: " & _ Quersumme(dblZahl)End Sub
Die unschöne Variante wandelt die Zahl in eine Zeichenkette um, die nun Zei-chen für Zeichen durchlaufen wird:
Function Quersumme(Zahl As Double) As LongDim dblÜbergabewert As DoubleDim dblInkrement As DoubleDim dblZähler As LongdblÜbergabewert = 0dblInkrement = 0
For dblZähler = 1 To Len(Str$(Zahl)) dblInkrement = Val(Mid(Str$(Zahl), dblZähler, 1)) dblÜbergabewert = dblÜbergabewert + dblInkrementNext
Quersumme = dblÜbergabewertEnd Function
Eleganter ist die »mathematische« Lösung, die vorsieht, mittels der FunktionFix die letzte Ziffer herauszulösen:
Function Quersumme(Zahl As Double) As LongDim dblÜbergabewert As DoubleDim dblInkrement As DoubleDim lngZähler As LongDim lngLänge As LongDim dblNeueZahl As Double
dblÜbergabewert = 0
73
5 Schleifen, rekursives Programmieren
dblInkrement = 0
lngLänge = Fix(Log(Zahl) / Log(10)) + 1dblNeueZahl = Zahl
For lngZähler = 1 To lngLänge dblInkrement = dblNeueZahl – Fix(dblNeueZahl / 10) * 10 dblÜbergabewert = dblÜbergabewert + dblInkrement dblNeueZahl = Fix(dblNeueZahl / 10)Next
Quersumme = dblÜbergabewertEnd Function
Die erste Variante sieht modifiziert dann wie folgt aus:
Function EndQuersumme(Zahl) As LongDim dblÜbergabewert As DoubleDim dblInkrement As DoubleDim dblZähler As LongdblÜbergabewert = 0dblInkrement = 0
For dblZähler = 1 To Len(Str$(Zahl)) dblInkrement = Val(Mid(Str$(Zahl), dblZähler, 1)) dblÜbergabewert = dblÜbergabewert + dblInkrementNextIf dblÜbergabewert > 9 Then dblÜbergabewert = EndQuersumme(dblÜbergabewert)End IfEndQuersumme = dblÜbergabewertEnd Function
Die zweite könnte folgendermaßen aussehen:
Function Quersumme(Zahl As Double) As LongDim dblÜbergabewert As DoubleDim dblInkrement As DoubleDim lngZähler As LongDim lngLänge As LongDim dblNeueZahl As Double
dblÜbergabewert = 0dblInkrement = 0
lngLänge = Fix(Log(Zahl) / Log(10)) + 2dblNeueZahl = Zahl
For lngZähler = 1 To lngLänge
74
Lösungen
dblInkrement = dblNeueZahl – Fix(dblNeueZahl / 10) * 10 dblÜbergabewert = dblÜbergabewert + dblInkrement dblNeueZahl = Fix(dblNeueZahl / 10)Next
If dblÜbergabewert > 9 Then dblÜbergabewert = Quersumme(dblÜbergabewert)End If
Quersumme = dblÜbergabewertEnd Function
Es werden lediglich die drei Zeilen
If dblÜbergabewert > 9 Then dblÜbergabewert = Quersumme(dblÜbergabewert)End If
eingefügt.
Lösung 8
Sub Fibonacci_Zahlen1()Dim i1 As Double, i2 As Double, i3 As DoubleDim bytAntwort As ByteDim strFibonacci As String
i1 = 1: i2 = 1strFibonacci = "1, 1"
Do Until bytAntwort = vbNo i3 = i1 + i2 strFibonacci = strFibonacci & ", " & Format(i3, "#,##0") i1 = i2: i2 = i3 bytAntwort = MsgBox("Die letzte Fiboccizahl war " & _ Format(i3, "#,##0") & _ "." & vbCr & "Die Reihe lautet: " & _ strFibonacci & vbCr & vbCr & _ "Möchten Sie eine weitere sehen?", vbYesNo)Loop
End Sub
Die rekursive Variante ruft sich selbst auf. Dabei muss man wissen, dass F(x) =F(x-1) + F(x-2). So ergibt sich die rekursive Funktion:
Function Fibonacci_Berechnen(dblAnzahl)
If dblAnzahl < 3 Then Fibonacci_Berechnen = 1
75
5 Schleifen, rekursives Programmieren
Else Fibonacci_Berechnen = Fibonacci_Berechnen(dblAnzahl – 1) _ + Fibonacci_Berechnen(dblAnzahl – 2)End If
End Function
Diese Funktion könnte beispielsweise über folgende Prozedur aufgerufen wer-den:
Sub Fibonacci_Zahlen2()Dim dblAnzahl As Double
dblAnzahl = InputBox("Welche Fibonaccizahl wird berechnet?")MsgBox "Die " & dblAnzahl & _ ". Fibonaccizahl lautet: " & _ Format(Fibonacci_Berechnen(dblAnzahl), "#,##0")
End Sub
76
Das Kapitel »Zugriff auf Dateien« hat mehrere Komponenten, die hier bespro-chen werden sollen. Zum einen geht es generell um die Frage, wie auf Dateienauf einen Dateiträger zugegriffen wird. Dabei stehen die »klassischen« Themenwie Dateien kopieren, verschieben, löschen, Ordner erstellen und umbenennenim Zentrum. Daneben erlaubt VBA allerdings auch den Zugriff auf »ini-Da-teien« und auf »sequentielle Dateien«. Auch wenn beide Möglichkeiten in derletzten Zeit immer mehr an Bedeutung verlieren, so stellen sie doch interes-sante, einfache und schnelle Zugriffsmöglichkeiten auf eine überschaubareMenge an Daten zur Verfügung. Auch in der »Registry« können Informationen(für den Benutzer unsichtbar und fast nicht auffindbar) abgespeichert werden.Auch dies soll angesprochen werden. Aus nicht erklärlichen Gründen funktio-niert der Zugriff auf ini-Dateien und auf die Registry leider nur in Word. Jedochwird in Kapitel 17 angesprochen, wie der Datenaustausch funktioniert. So ste-hen die Word-VBA-Befehle auch in den anderen Applikationen zur Verfügung,wenn dieses Programm verwendet wird. In Kapitel 9 wird erläutet, wie mandurch Einbinden von »api-Funktionen« die gleiche Funktionalität erreicht.
6.1 Der Zugriff auf DateienNoch aus »Urzeiten« der DOS-Ebene stehen Ihnen die bekannten Befehle zurVerfügung:
Tab. 6.1: Die Befehle für Dateien
6 Dateizugriff
Befehl Bedeutung Beispiel
GetAttr bestimmt die Attribute einer Datei. GetAttr("c:\setuplog.txt")
SetAttr legt Attribute einer Datei fest. Dabei steht:vbNormal 0vbReadOnly 1vbHidden 2vbSystem 4vbDirectroy 16vbArchive 32
SetAttr("c:\setuplog.txt")
FileDateTime gibt das Datum und die Zeit der letz-ten Änderung oder der Erstellung zu-rück.
FileDateTime("c:\setup-log.txt")
FileLen gibt die Länge einer Datei in Bytes an.
FileLen("c:\setuplog.txt")
77
6 Dateizugriff
Ähnliche Befehle stehen auch für Ordner zur Verfügung:
Tab. 6.2:Die Befehle für
Ordner
Der Befehl Dir funktioniert, laut Hilfe, folgendermaßen:
Dim Datei1, Pfad1 , Name1' Unter Microsoft Windows:' Liefert "WIN.INI" (unter Microsoft Windows), falls die Datei existiert.Datei1 = Dir("C:\WINDOWS\WIN.INI")
' Liefert einen Dateinamen mit der angegebenen Erweiterung. Existieren' mehrere Dateien mit der Erweiterung .INI, so wird der erste gefundene' Dateiname zurückgegeben.Datei1 = Dir("C:\WINDOWS\*.INI")
' Dir erneut ohne Argumente aufrufen, um die nächste Datei mit der' Erweiterung .INI im selben Verzeichnis zurückzugeben.Datei1 = Dir
' Die erste versteckte Datei mit der Erweiterung *.TXT zurückgeben.Datei1 = Dir("*.TXT", vbHidden)
FileCopy kopiert eine Datei. FileCopy("c:\setup.txt" "c:\Eigene Dateien\se-tup.txt")
Name ändert ein Datei oder Verzeichnis-name.
Name "c:\Versuch.txt" As "c:\Test.txt"
Kill löscht eine oder mehrere Dateien. Kill("c:\setuplog.txt")
Befehl Bedeutung Beispiel
Befehl Bedeutung Beispiel
CurDir gibt den aktuellen Pfad an. CurDir("C")
ChDir wechselt den aktuellen Ordner oder das aktuelle Laufwerk.
ChDir "D:\WINDOWS\SYS-TEM"
ChDrive wechselt das aktuelle Laufwerk. ChDrive "D"
MkDir erstellt einen neuen Ordner. MkDir "D:\Eigene Dateien2"
RmDir löscht einen vorhandenen Ordner. RmDir "D:\Eigene Dateien2"
Dir liefert den Namen einer Datei oder eines Ordners, der in einem Ordner oder auf einem Laufwerk gefunden wird.
Dir("C:\WINDOWS\")siehe auch unten
78
Übungen
' Namen in C:\ anzeigen, die Verzeichnisse darstellen.Pfad1 = "c:\" ' Pfad setzen.Name1 = Dir(Pfad1, vbDirectory) ' Ersten Eintrag abrufen.Do While Name1 <> "" ' Schleife beginnen. ' Aktuelles und übergeordnetes Verzeichnis ignorieren. If Name1 <> "." And Name1 <> ".." Then ' Mit bit-weisem Vergleich sicherstellen, daß Name1 ein ' Verzeichnis ist. If (GetAttr(Pfad1 & Name1) And vbDirectory) = vbDirectory Then Debug.Print Name1 ' Eintrag nur anzeigen, wenn es sich End If ' um ein Verzeichnis handelt. End If Name1 = Dir ' Nächsten Eintrag abrufen.Loop
Übung 1
Überprüfen Sie, ob auf Laufwerk »C:\« ein Ordner Eigene Dateien existiert. Fallsnicht, dann soll er erstellt werden.
Übung 2
Überprüfen Sie, ob im Ordner C:\Eigene Dateien eine Datei Makro.ini existiert.Falls ja, ermitteln Sie das Speicherdatum.
Übung 3
Zählen Sie die vorhanden Dateien im Ordner C:\Rechnungen und generieren Siedaraus eine neue Rechnungsnummer.
Mit dem Befehl Dir kann sowohl die Existenz einer Datei oder eines Verzeichnis-ses überprüft werden, als auch alle Dateien eines Ordner durchlaufen werden.Dieser Befehl wird in allen drei Aufgaben verwendet.
6.2 Übungen
6.3 Tipps
79
6 Dateizugriff
Lösung 1
Sub OrdnerPrüfen()If Dir("C:\Eigene Dateien\", vbDirectory) <> "" Then MsgBox "Der Ordner ""Eigene Dateien"" existiert."Else MkDir "C:\Eigene Dateien"End IfEnd Sub
Lösung 2
Sub DateiPrüfen()If Dir("C:\Eigene Dateien\Makro.ini") <> "" Then MsgBox "Die Datei wurde erstellt am: " & vbCr _ & FileDateTime("C:\Eigene Dateien\Makro.ini")Else MsgBox "Die Datei ""Makro.ini"" existiert " & _ "nicht im Ordner ""Eigene Dateien""."End IfEnd Sub
Lösung 3
Sub RechnungsNummerErmitteln()Dim strDateiname As StringstrDateiname = Dir("C:\Rechnungen\")Dim intRechnungsnummer As Double
Do While strDateiname <> "" If strDateiname <> "." And strDateiname <> ".." Then intRechnungsnummer = intRechnungsnummer + 1 End If strDateiname = DirLoopMsgBox Year(Date) * 100 + intRechnungsnummer + 1End Sub
6.5 ini-DateienUm Informationen in eine ini-Datei einzutragen oder aus ihr auszulesen, genügtein Befehl:
System.PrivateProfileString (Filename, Section, Key)
Dieser Befehl steht Ihnen übrigens nur in Word-VBA zur Verfügung!
6.4 Lösungen
80
Übungen
1. Übung
Beim Schließen eines (Word)-Dokuments wird eine Information in C:\Win-dows\Makro.ini eingetragen – beispielsweise den Namen der letzten Datei.
2. Übung
Beim Öffnen eines (Word)-Dokuments wird eine Information aus C:\Win-dows\Makro.ini ausgelesen.
3. Übung
Beim Erstellen einer neuen Datei aus einer Word-Dokumentvorlage wird der Be-nutzer nach seinem Zunamen gefragt. Heißt er »Maier«, »Huber« oder»Bauer«, dann wird er mit seinem korrekten Vornamen begrüßt, der in einerini-Datei gespeichert ist.
Lösung 1
Private Sub Document_Close()System.PrivateProfileString _ ("C:\Windows\Makro.ini", "Dateiname", "Letzte Datei") = _ ActiveDocument.FullNameEnd Sub
Lösung 2
Private Sub Document_Open()MsgBox System.PrivateProfileString _ ("C:\Windows\Makro.ini", "Dateiname", "Letzte Datei")End Sub
Natürlich ist dieses Beispiel wenig sinnvoll. Man könnte besser in der Nor-mal.dot den Befehl hinterlegen, mit dem die zuletzt verwendete Datei geöffnetwird:
Sub autoexec()Documents.Open FileName:=System.PrivateProfileString _ ("C:\Windows\Makro.ini", "Dateiname", "Letzte Datei")End Sub
6.6 Übungen
6.7 Lösungen
81
6 Dateizugriff
Lösung 3
Die ini-Datei Namen.ini ist folgendermaßen aufgebaut:
[Namen]Huber=GustavMaier=GudrunBauer=Gundula
Wählt der Benutzer aus der Liste der Dokumentvorlagen eine bestimmte aus, sowird folgendes Makro gestartet:
Private Sub Document_New()Dim strZuname As StringDim strVorname As String
strZuname = InputBox("Bitte Ihren Namen!")strVorname = System.PrivateProfileString _ ("C:\Windows\Namen.ini", "Namen", strZuname)If strVorname = "" Then MsgBox "Schade " & strZuname & _ ", aber Sie existieren nicht!"Else MsgBox "Guten Morgen " & strVorname _ & " " & strZunameEnd IfEnd Sub
6.8 Zugriff auf die RegistryDer Befehl, mit dem auf die Registry, oder genauer: auf den Ordner
HKEY_CURRENT_USER
der Registry zugegriffen werden kann, ist der gleiche, wie im vorigen Kapitel:
System.PrivateProfileString
Auch er funktioniert, ebenso wie der Zugriff auf die ini-Dateien, leider nur inWord.
Übung
Ermitteln Sie den aktuellen Benutzer!
6.9 Übung
82
Lösung
Lösung
Der Benutzername steht an mehreren Stellen in der Registry. Beispielsweise inWord:
Sub NamenErmitteln()MsgBox System.PrivateProfileString _ ("", "HKEY_CURRENT_USER\Software\Microsoft\" _ & "Office\9.0\Word\Options", "ReplyMessageComment")End Sub
6.11 Sequentielle DateienWie der Name schon sagt, werden die Daten hintereinander in einer Datei ge-speichert. Bevor man mit einer sequentiellen Datei arbeiten kann, muss diesemit
Open
geöffnet werden. Die vollständige Syntax lautet:
Open Name$ For Modus As [#]Dateinummer
Dabei bedeuten:
Tab. 6.3: Die Elemente des Befehls Open
6.10 Lösung
Begriff Erläuterung
Name$ ist der vollständige Name der zu öffnenden Datei. Also beispielsweise:»C:\Eigene Dateien\Namensliste.txt«oder auch der Name des Gerätetreibers:»LPT1«Die Namen stehen immer in Hochkommata.
Modus entspricht der Art, wie die Datei geöffnet werden soll:Input Die Datei wird zum Lesen geöffnet.Output Die Datei wird zum Schreiben geöffnet.Append Die Datei wird zum Schreiben geöffnet, aber die neuen Da-
ten überschreiben nicht die alten, sondern hängen sich an sie an.
Anmerkung: Wenn Sie eine Datei im Modus For Input öffnen, muss die Datei vorhanden sein, sonst kommt es zu einer Fehlermeldung. »For Output« und »For Append« verlangen dies nicht: Sie erzeugen eine Datei, falls sie nicht gefunden wird.
[#]Datei-nummer
ist eine Zahl zwischen 1 und 4. Über diese Zahl kann die geöffnete se-quentielle Datei angesprochen werden.
83
6 Dateizugriff
Hierzu ein Beispiel: Die Datei Ziel.txt wird im Modus For Output geöffnet. Dabeiist der vollständige Namen anzugeben, also zum Beispiel: C:\Windows\Ziel.txt.Nun werden die neuen Datensätze eingetragen und die alten gelöscht. DieNummerierung beginnt bei 1. In die erste Zeile wird mit Write die Überschrif-tenzeile eingetragen, das heißt die Beschriftung der Spalten. Und mit Hilfe einerSchleife werden die einzelnen Personen und deren Geschlecht eingelesen. NachBeendigung wird die Datei Ziel.txt geschlossen.
Sub PersonenEinlesen()Dim strPersName As StringDim strGeschlecht As StringDim intAntwort As Integer
Open "c:\Windows\Ziel.txt" For Output As #1Write #1, "Name", "Geschlecht"
intAntwort = vbYesDo While intAntwort = vbYes strPersName = InputBox("Bitte einen Namen eingeben!") strGeschlecht = InputBox("Bitte das Geschlecht " & _ " (""m"" oder ""w"") eingeben!") Write #1, strPersName, strGeschlecht intAntwort = MsgBox("Möchten Sie noch einen " & _ "Namen eingeben?", vbYesNo)Loop
Close #1
End Sub
Umgekehrt können die Datensatzeinträge wieder ausgelesen werden:
Sub PersonenAuslesen()Dim strPersName As StringDim strGeschlecht As StringDim i As Integer
Open "C:\Windows\ziel.txt" For Input As #1 Do While Not EOF(1) Input #1, strPersName, strGeschlecht MsgBox strPersName & ", " & strGeschlecht Loop
Close #1
End Sub
84
Übungen
Übung 1
In Kapitel 5 »Schleifen, rekursives Programmieren« Übung 2 wird von einer Zahlüberprüft, ob es sich um eine Primzahl handelt. Lassen Sie Primzahlen generie-ren und diese in eine sequentielle Datei schreiben: der Benutzer gibt eine Zahlein, beispielsweise 5. Nun wird die fünfte Primzahl erzeugt und alle Primzahlenabgespeichert, beispielsweise so:
Übung 2
Lassen Sie alle Primzahlen aus Übung 1 auslesen!
Übung 3
Die Eulersche Zahl e (≈ 2,718) kann durch eine Folge dargestellt werden:
Das bedeutet, dass e folgendermaßen aufgebaut werden kann:
e ≈ (1+1/1)1; (1+1/2)2; (1+1/3)3; (1+1/4)4; ...
oder anders dargestellt:
e ≈ 2; 2,25; 2,3703; 2,4414
Schreiben Sie in eine sequentielle Datei n Glieder dieser Folge!
Übung 4
Lassen Sie alle Glieder aus Übung 3 auslesen!
6.12 Übungen
Nummer Primzahl
1 2
2 3
3 5
4 7
5 11
�
��
� ��
�����
+∞→
=
85
6 Dateizugriff
Tipp zu Übung 1
In der folgenden Lösung wird in der Prozedur PrimzahlenEinlesen die DateiPrimzahlen.txt erzeugt oder geöffnet. In sie werden die Überschrift und die ers-ten beiden Lösungen geschrieben. Ein Zähler läuft dabei durch alle ungeradenZahlen, die in einer zweiten Prozedur (PrimErzeugen) darauf hin überprüft wer-den, ob es sich um Primzahlen handelt. Falls ja, dann wird das Ergebnis in die(noch geöffnete) Datei geschrieben.
Lösung 1
Sub PrimzahlenEinlesen()Dim dblEingabezahl As DoubleDim dblzählerE As DoubleDim dblZahl As Double
dblEingabezahl = InputBox("Wie viele Primzahlen sollen " _ & "generiert werden?")
Open "c:\Primzahlen.txt" For Output As #1Write #1, "Nummer", "Primzahl"Write #1, 1; 2Write #1, 2; 3
dblZahl = 5dblzählerE = 3
Do While dblzählerE <= dblEingabezahl
PrimErzeugen dblZahl, dblzählerE
dblZahl = dblZahl + 2
Loop
Close #1
MsgBox "Es wurden " & dblEingabezahl & _ " Primzahlen generiert."
End Sub
6.13 Tipp
6.14 Lösungen
86
Lösungen
Sub PrimErzeugen(dblZahl, dblzählerE)Dim dblZähler As Double
For dblZähler = 3 To Sqr(dblZahl) Step 2 If dblZahl Mod dblZähler = 0 Then Exit Sub End If Next dblZähler
Write #1, dblzählerE, dblZahl dblzählerE = dblzählerE + 1
End Sub
Lösung 2
Sub PrimzahlenAuslesen()Dim strNummer As StringDim strPrimzahl As StringDim strAusgabeText As String
Open "c:\Primzahlen.txt" For Input As #1 Do While Not EOF(1) Input #1, strNummer, strPrimzahl strAusgabeText = strAusgabeText & vbCr & _ strNummer & ":" & vbTab & strPrimzahl LoopClose #1
MsgBox strAusgabeTextEnd Sub
Lösung 3
Sub EulerscheZahlGenerieren()Dim dblEingabezahl As DoubleDim dblzähler As DoubleDim dblZahl As Double
dblEingabezahl = InputBox("Wie viele Zahlen sollen " & _ "generiert werden?")
Open "c:\EulerscheZahlen.txt" For Output As #1Write #1, "Nummer", "Eulersche Zahlen"
For dblzähler = 1 To dblEingabezahl dblZahl = (1 + 1 / dblzähler) ^ dblzähler Write #1, dblzähler; dblZahl
87
6 Dateizugriff
Next
Close #1MsgBox "Es wurden " & dblEingabezahl & " Zahlen generiert."End Sub
Lösung 4
Sub EulerZahlenAuslesen()Dim strNummer As StringDim strEulerzahl As StringDim strAusgabeText As String
Open "c:\EulerscheZahlen.txt" For Input As #1 Do While Not EOF(1) Input #1, strNummer, strEulerzahl strAusgabeText = strAusgabeText & vbCr & _ strNummer & ":" & vbTab & strEulerzahl Loop
Close #1
MsgBox strAusgabeTextEnd Sub
88
7.1 Was sind Klassen?Mit Klassen können Objekte definiert werden. Eine Klasse legt nicht nur dieNamen und Datentypen eines Objekts fest, sondern auch seine Methoden undEigenschaften. Ein Klassenmodul ist ein Modul in einem VBA-Projekt.
Die Syntax lautet:
Property Get
[Public | Private] [Static] Property Get Name _ [(ArgListe)] [As Typ][Anweisungen][Name = Ausdruck][Exit Property][Anweisungen][Name = Ausdruck]End Property
Property Let
[Public | Private] [Static] Property Let Name _ ([ArgListe,] Wert)[Anweisungen][Exit Property][Anweisungen]End Property
Property Set
[Public | Private] [Static] Property Set Name _ ([ArgListe,] Verweis)[Anweisungen][Exit Property][Anweisungen]End Property
Statt vieler Erklärungen ein Beispiel. Lassen Sie uns aus einer 3 * 3-Matrix dieDeterminante berechnen.
Dazu sollen eine neue Methode und eine neue Eigenschaft definiert werden.Zuerst wird ein Klassenmodul erzeugt (über das Menü EINFÜGEN / KLASSEN-MODUL). Es wird in den Eigenschaften in »Matrix« umbenannt. Zuerst wirddort eine Variable deklariert, die »intern« verwendet wird:
Private MxA1 As Double
7 Klassen
89
7 Klassen
7.2 Eigenschaften von ObjektenDiese Variable dient zur Ausgabe. Sie wird intern verwendet, wenn innerhalbder beiden folgenden Prozeduren ein Wert übergeben werden kann:
Property Let A1(WertA1 As Double) MxA1 = WertA1End Property
Property Get A1() As Double A1 = MxA1End Property
Dabei bedeutet Property Let das Zuweisen des Werts, Property Get ermög-licht das Lesen. Damit ist schon eine Eigenschaft eines Matrixwerts definiert.Property Let wird aufgerufen, wenn die Eigenschaft A1 einen Wert erhält. Pro-perty Get wird dagegen aufgerufen, wenn die Eigenschaft abgefragt wird. Inden Programmen existieren einige (wenige) Eigenschaften, die nur abgefragtund nicht gesetzt werden können, beispielsweise
Application.NameApplication.Path
und ähnliche. Für sie würde Property Get genügen. Diese Eigenschaft für dieZelleigenschaft A1 wird nun auch für A2, A3, B1, B2, B3, C1, C2 und C3 erzeugt. Fürsie werden ebenfalls die privaten Variablen MxA2, MxA3, MxB1, ... angelegt.
7.3 MethodeNun wird eine Methode erstellt, die die Determinante berechnet. Dazu genügteine einzige Prozedur. Ihr werden die neun Parameter übergeben, in ihr wird dieBerechnung ausgeführt; das Ergebnis wird an die Variable DetErgebnis überge-ben. Die Methode DeterminanteBerechnen gibt selbst keinen Wert zurück –sonst wäre sie eine Funktion.
Sub DeterminanteBerechnen () DetErgebnis = A1 * B2 * C3 + A2 * B3 * C1 + _ A3 * B1 * C2 – A3 * B2 * C1 – A1 * B3 * C2 – A2 * B1 * C3End Sub
In der Methode wird lediglich der Wert berechnet. Damit er ausgegeben wer-den kann, muss er einer Eigenschaft zugewiesen werden:
Property Let DetErgebnis(tmpDetErgebnis As Double) MxDetErgebnis = tmpDetErgebnisEnd Property
Property Get DetErgebnis() As Double DetErgebnis = MxDetErgebnisEnd Property
90
Methode
Natürlich muss die Variable MxDetErgebnis für das gesamte Klassenmodul de-klariert werden. Damit ist die Klasse »Matrix« komplett. Nun kann in jedemModul damit gearbeitet werden. Zuerst wird die Klasse instanziert:
Private M As Matrix
Dann wird auf die Objektvariable (hier: M) das Objekt gelegt:
Set M = New Matrix
Schließlich berechnet die Methode DeterminanteBerechnen das Ergebnis. Die Ei-genschaft DetErgebnis liefert das Ergebnis. Über mehrere Inputboxen könntedies folgendermaßen gelöst werden:
Option Explicit
Private M As Matrix
Sub DetAusrechnen()
Set M = New MatrixM.A1 = InputBox("Bitte einen Wert für A1 eingeben")M.B1 = InputBox("Bitte einen Wert für B1 eingeben")M.C1 = InputBox("Bitte einen Wert für C1 eingeben")
M.A2 = InputBox("Bitte einen Wert für A2 eingeben")M.B2 = InputBox("Bitte einen Wert für B2 eingeben")M.C2 = InputBox("Bitte einen Wert für C2 eingeben")
M.A3 = InputBox("Bitte einen Wert für A3 eingeben")M.B3 = InputBox("Bitte einen Wert für B3 eingeben")M.C3 = InputBox("Bitte einen Wert für C3 eingeben")
M.DeterminanteBerechnen
MsgBox M.DetErgebnis
End Sub
Weitaus eleganter und bequemer in der Eingabe ist natürlich eine Userform.Diese werden im Kapitel 10 behandelt.
Im Objektkatalog erscheinen nun die Methoden und Eigenschaften der neuenKlasse. Programme, die mit Klassen arbeiten, bieten einige Vorteile: Sie sind kla-rer strukturiert, leicht erweiterbar, weniger fehleranfällig und können leichtweitergegeben werden, da Klassen (ebenso wie Module) exportiert werdenkönnen.
91
7 Klassen
Natürlich hätte die Methode DeterminanteBerechnen auch einen Wert überge-ben können. Dann hätte man sie folgendermaßen aufrufen müssen:
Sub DeterminanteBerechnen _ (A1 As Double, A2 As Double, A3 As Double, _ B1 As Double, B2 As Double, B3 As Double, _ C1 As Double, C2 As Double, C3 As Double)
DetErgebnis = A1 * B2 * C3 + A2 * B3 * C1 + _ A3 * B1 * C2 – A3 * B2 * C1 – A1 * B3 * C2 – A2 * B1 * C3End Sub
Dann wird sie mit
M.DeterminanteBerechnen M.A1, M.A2, M.A3, _ M.B1, M.B2, M.B3, _ M.C1, M.C2, M.C3
MsgBox M.DetErgebnis
aufgerufen. Die Methode übergibt selbst keinen Wert – sonst wäre es eineFunktion. Aber auch das klappt:
Function DetErgebnis(A1 As Double, A2 As Double, _ A3 As Double, B1 As Double, B2 As Double, B3 As Double, _ C1 As Double, C2 As Double, C3 As Double)
Abbildung 7.1:Im Objektkatalog
wird die neueKlasse mit ihren
Eigenschaftenund Methoden
angezeigt.
92
Methode
DetErgebnis = A1 * B2 * C3 + A2 * B3 * C1 + _ A3 * B1 * C2 – A3 * B2 * C1 – A1 * B3 * C2 – A2 * B1 * C3
End Function
Sie wird folgendermaßen aufgerufen:
MsgBox M.DetErgebnis(M.A1, M.A2, M.A3, _ M.B1, M.B2, M.B3, _ M.C1, M.C2, M.C3)
Das folgende Bild zeigt im linken Fenster den Code des Moduls, im rechtenFenster den Code des Klassenmoduls:
Übung 1
In Kapitel 5 »Schleifen, rekursives Programmieren« Übung 1 wird eine Prozedurgeschrieben, die die Anzahl der Tage berechnet, die von der Schnecke benötigtwerden. Ändern Sie die Lösung um, indem Sie vier Eigenschaften definieren, inwelchen die Morgenhöhe, die Abendhöhe, die Mauerhöhe und die Anzahl derTage gespeichert wird. Berechnen Sie dann die Aufgabe mit Hilfe einer Me-thode.
Abbildung 7.2: Das Klassenmodul
7.4 Übungen
93
7 Klassen
Übung 2
In Kapitel 2 »Operatoren, Verknüpfungen und Verzweigungen« Übung 1 wirddie Länge der Hypothenuse eines rechtwinkligen Dreiecks über die Länge derbeiden Katheten berechnet. Ändern Sie die Lösung um, indem Sie zwei Eigen-schaften definieren, in welchen die eingegebenen Zahlen gespeichert wird. Be-rechnen Sie dann die Aufgabe mit Hilfe einer Methode.
Übung 3
In Kapitel 5 »Schleifen, rekursives Programmieren« Übung 4 wird eine Prozedurgeschrieben, die überprüft, ob eine Zahl eine Primzahl ist. Ändern Sie die Lö-sung um, indem Sie eine Eigenschaft definieren, in welcher die eingegebeneZahl gespeichert wird. Berechnen Sie dann die Aufgabe mit Hilfe einer Funk-tion.
Übung 4
In Kapitel 5 »Schleifen, rekursives Programmieren« Übung 7 wird eine Prozedurgeschrieben, die die Quersumme einer Zahl ermittelt. Ändern Sie die Lösungum, indem Sie eine Eigenschaft definieren, in welchr die eingegebene Zahl ge-speichert wird. Berechnen Sie dann die Aufgabe mit Hilfe einer Methode.
Übung 5
In Kapitel 2 »Operatoren, Verknüpfungen und Verzweigungen« Übung 4 wirddie Lösung einer quadratischen Gleichung berechnet. Ändern Sie die Lösungum, indem Sie drei Eigenschaften definieren, in welchen die eingegebenen Zah-len für a und b gespeichert werden und in der der Wert der Diskriminante fest-gelegt wird. Berechnen Sie dann die Aufgabe.
Lösung 1
Sicherlich gibt es mehrere Lösungen, diese Aufgabe in Klassenmodulen zu lö-sen. Sie können als Makro in einem beliebigen Modul Folgendes deklarieren:
Option ExplicitPrivate S As clsSchnecke
Sub Schnecki()Set S = New clsSchnecke
S.TageBerechnen
7.5 Lösungen
94
Lösungen
MsgBox S.TageZahl
End Sub
Dazu muss ein Klassenmodul clsSchnecke angelegt werden, in dem sich fol-gender Code befindet:
Option ExplicitPrivate SchneckMorgen As DoublePrivate SchneckAbend As DoublePrivate SchneckTage As IntegerPrivate SchneckMauerhöhe As Double
Private Sub Class_Initialize()SchneckMauerhöhe = 4.5End Sub
Property Get TageZahl() As Integer TageZahl = SchneckTageEnd Property
Sub TageBerechnen() Do While SchneckAbend < SchneckMauerhöhe SchneckAbend = SchneckMorgen + 0.5 SchneckMorgen = SchneckAbend * 0.9 SchneckTage = SchneckTage + 1 Loop
End Sub
Man kann die Schleife natürlich auch in der Prozedur laufen lassen:
Option ExplicitPrivate S As clsSchnecke
Sub Schnecki()Set S = New clsSchneckeDo While S.Abendhöhe < S.Mauerhöhe S.Abendhöhe = S.Morgenhöhe + 0.5 S.Morgenhöhe = S.Abendhöhe * 0.9 S.TageZahl = S.TageZahl + 1Loop
MsgBox S.TageZahl
End Sub
95
7 Klassen
Dann gestaltet sich die Klasse clsSchnecke wie folgt:
Option ExplicitPrivate SchneckMorgen As DoublePrivate SchneckAbend As DoublePrivate SchneckTage As IntegerPrivate SchneckMauerhöhe As Double
Property Get Morgenhöhe() As Double Morgenhöhe = SchneckMorgenEnd Property
Property Let Morgenhöhe(dblMorgenhöhe As Double) SchneckMorgen = dblMorgenhöheEnd Property
Property Get Abendhöhe() As Double Abendhöhe = SchneckAbendEnd Property
Property Let Abendhöhe(dblAbendhöhe As Double) SchneckAbend = dblAbendhöheEnd Property
Property Let TageZahl(intTage As Integer) SchneckTage = intTageEnd Property
Property Get TageZahl() As Integer TageZahl = SchneckTageEnd Property
Property Get Mauerhöhe() As Double Mauerhöhe = SchneckMauerhöheEnd Property
Sub TageBerechnen()
End Sub
Private Sub Class_Initialize()SchneckMauerhöhe = 4.5End Sub
Wie man sieht, ist die Prozedur Tageberechnen hier überflüssig.
Sicherlich gibt es hier, wie bei allen anderen Aufgaben, mehrere alternative Lö-sungen.
96
Lösungen
Lösung 2
Im Modul findet sich folgender Code:
Option ExplicitPrivate RD As clsRechtwDreieck
Sub HypoRechnung()Set RD = New clsRechtwDreieckRD.Kathete1 = InputBox _ ("Bitte die Länge der ersten Kathete angeben.")RD.Kathete2 = InputBox _ ("Bitte die Länge der zweiten Kathete angeben.")RD.HypoBerechnen
MsgBox "Die Länge der Hypothenuse beträgt: " & RD.Hypothenuse
End Sub
In der Klasse clsRechtwDreieck stehen folgende Eigenschaften und folgendeMethode:
Option Explicit
Private RDKathete1 As DoublePrivate RDKathete2 As DoublePrivate RDHypothenuse As Integer
Property Get Kathete1() As Double Kathete1 = RDKathete1End Property
Property Let Kathete1(dblKathete1 As Double) RDKathete1 = dblKathete1End Property
Property Get Kathete2() As Double Kathete2 = RDKathete2End Property
Property Let Kathete2(dblKathete2 As Double) RDKathete2 = dblKathete2End Property
Property Get Hypothenuse() As Double Hypothenuse = RDHypothenuseEnd Property
Property Let Hypothenuse(dblHypothenuse As Double)
97
7 Klassen
RDHypothenuse = dblHypothenuseEnd Property
Sub HypoBerechnen() RDHypothenuse = Sqr(RDKathete1 ^ 2 + RDKathete2 ^ 2)End Sub
Zugegeben: viel zu viel Code für eine einzige Rechenoperation, aber man weißja nicht, vielleicht wird die Rechnung ausgebaut ...
Lösung 3
Folgende Prozedur liefert das Ergebnis:
Option ExplicitPrivate P As clsPrim
Sub PrimZahlenTest()Set P = New clsPrimP.Zahl = InputBox _ ("Von welcher Zahl soll überprüft werden" & _ ", ob es sich um eine Primzahl handelt?", "Prim")If P.Zahl < 2 Then MsgBox "Die eingegebene Zahl ist zu klein!" Exit SubElseIf Fix(P.Zahl) < P.Zahl Then MsgBox "Die Zahl darf keine Dezimalstellen haben!" Exit SubEnd If
If P.PrimPrüf(P.Zahl) = True Then MsgBox P.Zahl & " ist eine Primzahl"Else MsgBox P.Zahl & " ist keine Primzahl"End If
End Sub
Und in der Klasse clsPrim wird dies berechnet:
Option Explicit
Private PZahl As Double
Property Get Zahl() As Double Zahl = PZahlEnd Property
Property Let Zahl(dblzahl As Double) PZahl = dblzahl
98
Lösungen
End Property
Function PrimPrüf(dblzahl As Double) As BooleanDim dblZähler As Double
For dblZähler = 2 To Sqr(dblzahl) If dblzahl Mod dblZähler = 0 Then PrimPrüf = False Exit Function End IfNext dblZähler
PrimPrüf = True
End Function
Lösung 4
Die Prozedur im Modul:
Option ExplicitPrivate Q As clsQuer
Sub QuersummeBerechnen()Set Q = New clsQuerQ.Zahl = InputBox("Von welcher Zahl soll " _ & " die Quersumme berechnet werden?")
MsgBox "Die Quersumme lautet: " & Q.Quersumme(Q.Zahl)
End Sub
Und die Klasse clsQuer:
Option Explicit
Private QZahl As Double
Property Get Zahl() As Double Zahl = QZahlEnd Property
Property Let Zahl(dblzahl As Double) QZahl = dblzahlEnd Property
Function Quersumme(dblzahl As Double) As DoubleDim dblÜbergabewert As DoubleDim dblInkrement As Double
99
7 Klassen
Dim lngZähler As LongDim lngLänge As Long
dblÜbergabewert = 0dblInkrement = 0
lngLänge = Log(dblzahl) / Log(10) + 1
For lngZähler = 1 To lngLänge dblInkrement = dblzahl – Fix(dblzahl / 10) * 10 dblÜbergabewert = dblÜbergabewert + dblInkrement dblzahl = dblzahl / 10Next
Quersumme = dblÜbergabewert
End Function
Analog kann dann auch die Endquersumme berechnet werden:
Sub EndQuersummeBerechnen()Set Q = New clsQuerQ.Zahl = InputBox("Von welcher Zahl soll " _ & " die Endquersumme berechnet werden?")Do Until Q.Zahl < 10 Q.Zahl = Q.Quersumme(Q.Zahl)Loop
MsgBox "Die Endquersumme lautet: " & Q.Zahl
End Sub
Übrigens: Würde man die Stellenanzahl runden, also statt
lngLänge = Log(dblzahl) / Log(10) + 1
schreiben:
lngLänge = Fix(Log(dblzahl) / Log(10)) + 1
oder:
lngLänge = Int(Log(dblzahl) / Log(10)) + 1
dann käme es für die Zahlen 10, 100, 1000, ... zu einem Fehler. VBA berechnetden log(10) intern als einen Wert, der kleiner ist als der echte log(10). Damitwird für log(10)/log(10) mit einem (etwas) kleineren Wert als 1 weitergerech-net. Somit wird mit
lngLänge = Fix(Log(dblzahl) / Log(10)) + 1
der Wert 1 auf 0 (!) »abgerundet«, was zum Schluss zu einem Fehler führt!
100
Lösungen
Lösung 5
Die Prozedur im Modul:
Option ExplicitPrivate QG As clsQuadGleichung
Sub QuadratischeGleichungBerechnen()Set QG = New clsQuadGleichungDim strZ1 As StringDim strZ2 As StringDim strGl As StringDim dblx1 As DoubleDim dblx2 As Double
strZ1 = "0 = x² + a*x + b"strZ2 = "Quadratische Gleichung"
MsgBox "Wir berechnen die Lösung der Gleichung " & _ strZ1 & ". Bitte gib die Werte für a und für b ein!", _ , strZ2QG.a = InputBox("Wie lautet die Zahl a?", strZ1)QG.b = InputBox("Wie lautet die Zahl b?", strZ1)
strGl = "Die Gleichung 0 = x² + " & QG.a & _ "*x + " & QG.b
If QG.Det < 0 ThenMsgBox strGl & " hat keine Lösung. Schade!", _ , strZ2ElseIf QG.Det = 0 ThenMsgBox strGl & " hat eine Lösung: " & _ -QG.a / 2, , strZ2ElseIf QG.Det > 0 Thendblx1 = -(QG.a / 2) + QG.Det ^ 0.5dblx2 = -(QG.a / 2) – QG.Det ^ 0.5MsgBox strGl & " hat zwei Lösungen: " & dblx1 & _ " und " & dblx2, , strZ2End If
End Sub
Und die Klasse clsQuadGleichung:
Option Explicit
Private Qa As DoublePrivate Qb As DoublePrivate QDet As Double
101
7 Klassen
Property Get a() As Double a = QaEnd Property
Property Let a(dbla As Double) Qa = dblaEnd Property
Property Get b() As Double b = QbEnd Property
Property Let b(dblb As Double) Qb = dblbEnd Property
Property Get Det() As Double Det = (a / 2) ^ 2 – bEnd Property
Property Let Det(dblDet As Double) QDet = dblDetEnd Property
102
Das schlimme und schwierige Kapitel »Fehler« hat zwei Komponenten: Fehler,die Sie als Programmierer beim Erstellen von Routinen machen und Fehler, diewährend der Laufzeit auftreten oder Fehler, die der Benutzer bei der Eingabemachen kann. Erstere sollten vor dem Ausliefern eines Programms gefundenwerden, auf letztere kann (und sollte) per Programmiercode reagiert werden.
8.1 ProgrammierfehlerAn dieser Stelle folgen einige Tipps, wie man weniger Fehler machen kann.
Schalten Sie im Menü EXTRAS / OPTIONEN im Registerblatt »Editor« die Option»Variablendeklaration erforderlich« ein. Dann wird in neuen VBA-Modulen zuBeginn der Befehl
Option Explicit
auftauchen, der Sie zwingt, jede Variable zu deklarieren. So kann es nicht vor-kommen, dass eine als strEingabe deklarierte Variable im Code als strEingabendurchgehen wird. Sie erhalten beim Testen sofort eine Fehlermeldung, die da-rauf hinweist.
Rücken Sie ein! So können Anfang und Ende von With ... End With-Klam-mern, von Verzweigungen und Schleifen sichtbar gemacht werden. So verges-sen Sie keine Zeile.
Schreiben Sie nach der If-Zeile gleich die End If-Zeile. Nach Do While gleichLoop. Und so weiter. Auch so kann man das lästige Vergessen von Zeilen ver-meiden.
Vergeben Sie vernünftige Variablennamen. Strukturieren Sie Ihre Programme,indem Sie es in verschiedene Module unterteilen. So halten Sie Ordnung. Kom-mentieren Sie! Am besten jede Zeile. Schlimm genug, wenn man in einemfremden Makro auf Befehle wie
Liste.Füllen
stößt. Was das ist, kann nur durch den Einzelschrittmodus getestet werden.
Tippfehler sind lästig. Deshalb tippe ich alle VBA-Befehle in Kleinbuchstaben einund kontrolliere nach Betätigen der (¢)-Taste, ob VBA sie in Groß/Kleinschrei-bung umwandelt, das heißt, ob VBA sie erkennt. Falls nicht, dann liegt ein Tipp-fehler vor.
8 Fehler
103
8 Fehler
Zum Testen stehen Ihnen folgende Optionen zur Verfügung:
8.2 Fehler zur LaufzeitEinige Fehler, zum Beispiel bei der Eingabe, können durch einen einfachen If-Befehl abgefangen werden. Gibt der Benutzer beispielsweise eine Zahl ein, vonder überprüft werden soll, ob es sich um eine Primzahl handelt, dann mussdiese Zahl positiv sein. Also kann überprüft werden:
If dblEingabezahl < 1 Then[...]
Ebenso können die Informations-Funktionen (IsDate, IsEmpty, IsError, IsMis-sing, IsNull, und IsNumeric) eingesetzt werden (sie wurden in Kapitel 2 aufge-listet):
If Not IsNumeric(dblEingabezahl) Then[...]
Was aber, wenn ein ganz anderer Fehler auftritt? Dann steht Ihnen der BefehlOn Error zur Verfügung:
On Error Resume Next
Der Fehler wird übersprungen und das Programm wird mit der Zeile fortgesetzt,die unmittelbar auf die Zeile folgt, die den Fehler verursacht. Dies ist eine ge-fährliche Sache, da nicht auf den Fehler adäquat reagiert wird.
On Error GoTo 0
Befehl Menüpunkt Tastenkombination
Einzelschritt DEBUGGEN – EINZELSCHRITT (F8)
Einzelschritt. Unterproze-duren werden übersprun-gen
DEBUGGEN – PROZEDUR-SCHRITT
(ª)+(F8)
Aktuelle Werte anzeigen den Mauszeiger auf die Vari-able setzen
Haltepunkte DEBUGGEN – HALTEPUNKT EIN/AUS
(F9)
Sprung bis zur Cursorpo-sition
DEBUGGEN – AUSFÜHREN BIS CURSORPOSITION
(Strg)+(F8)
Sprung bis zum Prozedu-rende
DEBUGGEN – PROZEDUR AB-SCHLIESSEN
(ª)+(Strg)+(F8)
Überwachungsausdrücke DEBUGGEN – ÜBERWA-CHUNG HINZUFÜGEN
ANSICHT – ÜBERWACHUNGS-FENSTER
ANSICHT – LOKALSFENSTER
104
Fehler zur Laufzeit
Dieser Befehl deaktiviert alle benutzerdefinierten Fehlerroutinen. Diese Zeilekann für die Testphase und die Analyse eines Programmverhaltens interessantsein.
On Error GoTo Sprungmarke
Tritt ein Fehler auf, so wird eine Sprungmarke angesprungen, die sich in der Re-gel am Ende der Prozedur befindet. Dort kann auf den Fehler adäquat reagiertwerden. Vor der Sprungmarke sollte allerdings das Programm beendet werdenmit:
Exit Sub
Innerhalb der Sprungmarke kann der Fehler über die Fehlerobjektvariable Errspezifiziert werden. Err besitzt folgende Eigenschaften und Methoden:
Tab. 8.1: Die Eigenschaften und Methoden von Err
Soll nach dem behandelten Fehler die Prozedur an der gleichen Stelle aufgeru-fen werden und ab dieser Stelle weitergearbeitet werden, dann geschieht diesmit dem Befehl
Resume
Dazu sollte der Fehlerwert natürlich wieder zurückgesetzt werden. Liegt keinFehler vor, dann hat er den Wert 0. Also:
[...]Err.ClearResume
Soll eine Zeile tiefer weitergearbeitet werden, dann mit
Resume Next
Über Fehler und ihre Behandlungsmöglichkeiten ließe sich noch viel sagen. InFachzeitschriften werden diese Themen und Strategien dazu stark diskutiert.Was hier vorgestellt wurde, ist lediglich das Gerüst, das nun ausbaufähig ist.
Eigenschaften von Err Beschreibung
Number eine spezifische Nummer des Fehlers
Description Beschreibung des Fehlers, die dem Benutzer angezeigt werden kann
Source Fehlerquelle
HelpContext, HelpFile Hilfedatei, die an einen bestimmten Fehler gebunden ist
Methoden von Err Beschreibung
Clear löscht den Fehler.
Raise erzeugt einen Fehler.
105
8 Fehler
Übung 1
Man kann von Word mit dem Befehl
Set xlApp = GetObject(, "Excel.Application")
auf das geöffnete Excel zugreifen. Fangen Sie den Fehler ab, der auftaucht, fallsExcel nicht offen ist.
Übung 2
Ein Benutzer tippt einen Laufwerksbuchstaben in eine Inputbox, in der sich einOrdner befindet, in dem eine Datei liegt (\SCHWUNG\Schwung.ini). Nun kön-nen eine Reihe Fehler überprüft werden:
1. Der Benutzer hat keinen Buchstaben eingetippt.
2. Das Verzeichnis existiert nicht.
3. Der Benutzer hat kein Leserecht auf dieses Verzeichnis.
4. Im (Diskettenlaufwerk) liegt keine Diskette.
5. Im angegebenen Laufwerk existiert der Ordner nicht.
6. Das Laufwerk existiert, der Ordner auch, allerdings ist die Datei nicht vor-handen.
Erzeugen Sie (künstliche) Fehler mit dem Befehl GettAttr, fangen Sie den Fehlerab und melden Sie ihn dem Benutzer.
Übung 3
In Kapitel 5 Übung 4 wird das kgV berechnet. Fangen Sie mögliche Fehler ab:
1. Der Benutzer gibt statt einer Zahl etwas anderes ein.
2. Der Benutzer gibt keine ganze Zahl ein.
3. Der Benutzer gibt eine Zahl < 1 ein.
4. Das Ergebnis wird zu groß (Überlauf).
Übung 4
Laut »Microsoft Office 2000 Visual Basic Programmierhandbuch« sind für dasError-Objekt die ersten 512 Zahlen als Fehlernummern reserviert. Die übrigenZahlen (bis 65.536) stehen dem Benutzer für eigene Fehler zur Verfügung. Diesist nicht korrekt, da in einigen Applikationen Fehlernummern vergeben sind,die größer als 512 sind. Dennoch: Lassen Sie sich die ersten 512 Fehlernum-mern mit ihrer Bedeutung auflisten.
8.3 Übungen
106
Lösungen
Lösung 1
Eine direkte Möglichkeit könnte wie folgt aussehen:
Dim xlApp As ObjectConst err_Excel_LäuftNicht = 429On Error Resume Next
Set xlApp = GetObject(, "Excel.Application")If Err.Number = err_Excel_LäuftNicht Then Set xlApp = CreateObject("Excel.Application")End IfOn Error GoTo err_handler[...]Set xlApp = Nothing[...]Exit Suberr_handler:[...]
Lösung 2
Sub Laufwerk_und_Ordner_und_Datei()Dim strLaufwerk As String
On Error Resume Next
strLaufwerk = InputBox("Bitte einen Laufwerksbuchstaben" & _ " eingeben")strLaufwerk = Left(strLaufwerk, 1)strLaufwerk = UCase(strLaufwerk)
If Asc(strLaufwerk) < Asc("A") Or _ Asc(strLaufwerk) > Asc("Z") Then MsgBox "Sie haben Unsinn getippt!", _ vbCritical, "SCHWUNG" EndEnd If
GetAttr (strLaufwerk & ":\") If Err.Number = 5 Then MsgBox "Es wurde keine Diskette/CD-Rom in Laufwerk " _ & strLaufwerk & " eingelegt!", vbCritical, "SCHWUNG" End ElseIf Err.Number = 76 Then
8.4 Lösungen
107
8 Fehler
MsgBox "Das Laufwerk " & strLaufwerk & _ " existiert nicht auf Ihrem Rechner", _ vbCritical, "SCHWUNG" End ElseIf Err.Number = 70 Then MsgBox "Sie haben kein Leserecht auf das Laufwerk " & _ strLaufwerk, vbCritical, "SCHWUNG" End ElseIf Err.Number > 0 Then MsgBox "Es ist ein Fehler eingetreten auf Laufwerk " _ & strLaufwerk & _ vbCr & vbCr & Err.Description, vbCritical, "SCHWUNG" End End If
GetAttr (strLaufwerk & ":\SCHWUNG\Schwung.ini") If Err.Number = 76 Then MsgBox "Der Ordner ""SCHWUNG"" existiert nicht " & _ "in Laufwerk " & strLaufwerk, vbCritical, "SCHWUNG" End ElseIf Err.Number = 53 Then MsgBox "Die Datei ""Schwung.ini"" existiert " & _ "nicht in " & strLaufwerk & ":\SCHWUNG", _ vbCritical, "SCHWUNG" End ElseIf Err.Number > 0 Then MsgBox "Es ist ein Fehler eingetreten beim " & _ "Zugriff auf " & strLaufwerk & _ ":\SCHWUNG\Schwung.ini" & vbCr & vbCr & _ Err.Description, vbCritical, "SCHWUNG" End End If
End Sub
Lösung 3
Teile des Abfangens können über eine If-Bedingung erledigt werden:
Sub kgV()Dim dblZahl1 As DoubleDim dblZahl2 As DoubleDim dblGrößteZahl As DoubleDim dblZähler As DoubleConst err_Überlauf = 6 'die FehlerkonstantenConst err_KeineZahl = 13Const err_NegativeZahl = 998Const err_KeineGanzeZahl = 999
108
Lösungen
On Error GoTo err_kgV
dblZahl1 = InputBox("Von welchen Zahlen soll das " & _ "kgV berechnet werden?", "kgV: Zahl1")dblZahl2 = InputBox("Von welchen Zahlen soll das " & _ "kgV berechnet werden?", "kgV: Zahl2")
'mögliche Fehler werden erzeugt und abgefangenIf dblZahl1 < 1 Or dblZahl2 < 1 Then Err.Raise err_NegativeZahlEnd If
If Fix(dblZahl1) < dblZahl1 Or Fix(dblZahl2) < dblZahl2 Then Err.Raise err_KeineGanzeZahlEnd If
'der eigentliche ProgrammteilIf dblZahl1 > dblZahl2 Then dblGrößteZahl = dblZahl1Else dblGrößteZahl = dblZahl2End If
For dblZähler = dblGrößteZahl To dblZahl1 * dblZahl2 If dblZähler Mod dblZahl1 = 0 And _ dblZähler Mod dblZahl2 = 0 Then MsgBox "Das kgV von " & _ dblZahl1 & " und " & dblZahl2 & _ " lautet: " & dblZähler Exit Sub End IfNext dblZähler
Exit Sub'die Sprungmarke und Fehlerroutineerr_kgV:
If Err.Number = err_KeineZahl Then MsgBox "Es wurde keine Zahl eingegeben"ElseIf Err.Number = err_KeineGanzeZahl Then MsgBox "Es wurde keine ganze Zahl eingegeben"ElseIf Err.Number = err_NegativeZahl Then MsgBox "Es wurde eine negative Zahl eingegeben"ElseIf Err.Number = err_Überlauf Then MsgBox "Das Ergebnis kann nicht berechnet werden – es ist zu groß!"ElseMsgBox "Fehlernummer: " & Err.Number & _
109
8 Fehler
vbCr & "Fehler: " & Err.Description & _ vbCr & "Fehlerquelle: " & Err.SourceEnd If
End Sub
Lösung 4
Sub Fehlernummern()Dim i As IntegerDim strFehlerListe As StringOn Error Resume Next
For i = 1 To 512Err.Raise i strFehlerListe = strFehlerListe & vbCr & i & ":" _ & vbTab & Err.Description Err.ClearNextMsgBox strFehlerListeEnd Sub
Dieses Ergebnis kann man sich natürlich in eine Word- oder Excel-Datei schrei-ben lassen.
110
Die vorhergehenden Kapitel haben gezeigt, dass ein Zugriff von VBA bis auf Da-teiebene und in die Registry möglich ist. Manchmal genügt das allerdings nicht,und es werden noch weitere Funktionen benötigt. Dazu zählen mathematischeRoutinen, die mit mehr als 15 Nachkommastellen rechnen, Schnittstellen zu an-deren Programmen, die VBA nicht zur Verfügung stellt oder der Zugriff auf Teiledes Systems, das nur über das API direkt angesprochen werden kann.
Seit Windows 95 und Windows NT werden die meisten der offengelegten Ei-genschaften in DLLs, in Dynamic Link Libraries, untergebracht. Die damit zurVerfügung gestellte Schnittstelle trägt den Namen API, Application Program-ming Interface.
Solche DLLs kann man auch in C++, Delphi oder Visual Basic produzieren, wo-mit das VBA-Programm schnell erweitert werden kann.
Für den Zugriff von VBA auf die DLL benötigt man die Dokumentation derSchnittstelle. Dazu muss man den Namen der DLL wissen, den Namen der Funk-tion und die Parameter, die dabei übergeben werden sollen.
9.1 Aufruf einer API-Funktion
Eine API-Funktion ist eine Funktion, die in einer Systemdatei enthalten ist. AlleAPI-Funktionen sind in DLLs enthalten. Das Problem: API-Funktionen sind nichtdokumentiert! Weder in der VBA-Hilfe, noch in der Hilfe von Visual Basic, noch inirgendeinem Buch! Sollten Sie Visual Basic besitzen oder die Developer-Versionvon VBA, dann verfügen Sie über eine Datei Win32api.txt, in der der API-Katalogzur Verfügung gestellt wird. Mit der Datei Apiload.exe kann auf diese Textdateizugegriffen werden. In diesem Hilfsprogramm können die Declare-Anweisun-gen der meisten API-Funktionen und deren Parameter ermittelt werden.
9.2 Die Declare-AnweisungJede externe Funktion benötigt in VBA eine Declare-Anweisung. Über sie wer-den mitgeteilt: der Name der Funktion, der Name der DLL, in der sie sich befin-det, die Anzahl der Argumente und ihre Datentypen sowie der Datentyp desRückgabewerts. Die allgemeine Syntax lautet:
[Public | Private] Declare Sub Name Lib "BibName" [Alias "Aliasname"] [([ArgListe])]
oder für eine Funktion:
9 Externe DLLs aufrufen
111
9 Externe DLLs aufrufen
[Public | Private] Declare Function Name Lib "BibName" [Alias "Aliasname"] [([ArgListe])] [As Typ]
Dabei bedeuten:
Tab. 9.1:Die Elemente der
API-Funktion
Abbildung 9.1:Der API-Viewer
Teil Beschreibung
Public deklariert Prozeduren, die allen anderen Prozeduren in allen Mo-dulen zur Verfügung stehen.
Private deklariert Prozeduren, die nur innerhalb des Moduls verfügbar sind, in dem sie deklariert wurden.
Sub | Function bedeutet, dass entweder Sub oder Function auftreten muss.
Name Ein beliebiger gültiger Name für eine Prozedur. Beachten Sie, dass bei den Namen der DLL- Einsprungpunkte zwischen Groß-/Klein-schreibung unterschieden wird.
Lib Die deklarierte Prozedur ist in einer DLL oder Code-Ressource ent-halten. Der Lib-Abschnitt ist bei allen Deklarationen erforderlich.
BibName Name der DLL oder Code-Ressource, die die deklarierte Prozedur enthält.
112
Beispiele für den Einsatz von APIs
Das Argument ArgListe hat die folgende Syntax:
[Optional] [ByVal | ByRef] [ParamArray] VarName[( )] [As Typ]
9.3 Beispiele für den Einsatz von APIs
Die Funktion GetSystemMetrics gibt von 75 Konstanten 75 verschiedene Infor-mationen des Betriebssystems zurück. Die Konstante 0 gibt die horizontale Bild-schirmauflösung wieder, die Konstante 1 die vertikale. Nach der Deklaration derFunktion kann sie in einer Prozedur eingebaut werden:
Private Declare Function GetSystemMetrics Lib "User32" _ (ByVal nIndex As Long) As Long
Sub Bildschirmauflösung()Dim intBreite As IntegerDim intHöhe As IntegerintBreite = GetSystemMetrics(0)intHöhe = GetSystemMetrics(1)
MsgBox intBreite & " x " & intHöhe
End Sub
Alias gibt an, dass die aufgerufene Prozedur in der DLL einen anderen Namen hat. Dies ist sinnvoll, wenn der Name einer externen Pro-zedur einem Schlüsselwort entspricht. Alias kann auch verwendet werden, wenn eine DLL-Prozedur denselben Namen hat wie eine öffentliche Variable, Konstante oder eine andere Prozedur mit demselben Gültigkeitsbereich. Alias bietet sich darüber hinaus an, wenn bestimmte Zeichen im Namen der DLL-Prozedur aufgrund der Namenskonvention für DLLs nicht zulässig sind.
Aliasname Name der Prozedur in der DLL oder Code Ressource. Wenn das erste Zeichen nicht das Zeichen # ist, gibt Aliasname den Namen des Einsprungpunktes in der DLL an. Ist das Zeichen # das erste Zeichen, so müssen alle nachfolgenden Zeichen die Ordnungszahl (laufende Nummer) für den Einsprungpunkt in die Prozedur ange-ben.
ArgListe Variablenliste mit den Argumenten, die beim Aufruf an die Proze-dur übergeben werden.
Typ Datentyp des Rückgabewerts einer Function-Prozedur. Zulässige Typen sind: Byte, Boolean, Integer, Long, Currency, Single, Double, Decimal (zur Zeit nicht unterstützt), Date, String (nur Zei-chenfolgen variabler Länge) oder Variant, ein benutzerdefinierter Typ oder ein Objekttyp.
Teil Beschreibung
113
9 Externe DLLs aufrufen
Die Funktion ShowCursor versteckt den Mauscursor oder holt ihn wieder hervor.Sie wird wie folgt deklariert:
Private Declare Function ShowCursor Lib "user32" _ (ByVal lngMouse As Long) As Long
Mit dem Wert 0 verschwindet der Cursor, bei -1 erscheint er wieder. Sie wird imfolgenden Beispiel realisiert:
Dim lngMaus As Long
Sub Mausweg()lngMaus = Not lngMausShowCursor lngMausEnd Sub
Da in den Programmen Word, Excel, Visio, … keine Timer-Funktion zur Verfü-gung steht, kann auf die beiden Funktionen SetTimer und KillTimer zurückge-griffen werden:
Private Declare SetTimer Lib "user32" _ (ByVal hWnd As Long, ByVal nIDEvent As Long _ ByVal uElapse As Long, ByVal lpTimerFunc As Long) As LongPrivate Declare KillTimer Lib "user32" _ (ByVal hWnd As Long, ByVal nIDEvent As Long) As Long
Zum Thema API und dlls ließe sich noch viel sagen und schreiben. Wenn Sie sichauch für dieses Thema interessieren (das hier zugegebenermaßen zu kurz kam),dann informieren Sie sich in weiterführender Literatur. Gerade Bücher überVisual Basic enthalten oft mehrere Kapitel zu diesem Thema.
114
Folgende Standardsteuerelemente für die Dialogprogrammierung stehen Ihnenzur Verfügung:
� Dialogbox (Userform)
� Beschriftungsfeld (Label)
� Textfeld (Textbox)
� Kombinationsfeld (Dropdownfeld, Combobox)
� Listenfeld (Listbox)
� Kontrollkästchen (Checkbox)
� Optionsfeld (Optionbutton)
� Umschaltfeld (Toggelbar)
� Rahmen (Frame)
� Befehlsschaltfläche (Commandbar)
� Register (Tabstrip)
� Multiseiten (Multipage)
� Bildlaufleiste (Scrollbar)
� Drehfeld (Spinbutton)
� Anzeige (Image)
Da die Steuerelemente in der Werkzeugsammlung deutsche Namen tragen, da-gegen in der Eigenschaftenliste englisch beschriftet sind, werden im Folgendenbeide Bezeichnungen verwendet. Hier nun eine Auflistung der wichtigsten Ei-genschaften, Methoden und Ereignisse der Steuerelemente:
10.1 Dialog und Befehlsschaltfläche
Zusammenfassung der Eigenschaften des Formulars (Userform, Dialogbox):
Tab. 10.1: Zusammenfassung der Eigenschaften des Formulars
10 Dialoge
Kategorie Eigenschaft Beschreibung
Bild Picture Die Kategorie »Bild« wird in Abschnitt 4 »Text-felder, Beschriftungsfelder und Anzeige« be-schrieben.
PictureAlignment
115
10 Dialoge
PictureSizeMode
PictureTiling
Bildlauf KeepScrollBarsVi-sible
betrifft die Anzeige und Ansicht von möglichen Bildlaufleisten, wenn die Anzeige größer ist als der Bildschirm.
Scrollbars betrifft die Anzeige und Ansicht von Bildlaufleis-ten. Um Bildlaufleisten zu erhalten, müssen KeepScrollBarsVisible und Scrollbars eingeschal-tet werden.
ScrollHeight gibt die Höhe der Bildlaufleiste an.
ScrollLeft gibt die Entfernung des linken Randes des For-mulars vom linken Rand der Bildlaufleiste an.
ScrollTop gibt die Entfernung des oberen Randes des For-mulars vom oberen Rand der Bildlaufleiste an.
ScrollWidth gibt die Breite der Bildlaufleiste an.
Darstellung BackColor gibt die Hintergrundfarbe an.
BorderColor bedeutet die Farbe des Randes (sie ist nur sicht-bar, wenn ein Rand eingeschaltet und kein SpecialEffect aktiviert ist).
BorderStyle schaltet den Rand ein oder aus.
Caption gibt die Beschriftung des Dialogblatts an – erscheint in der Titelleiste.
ForeColor zeigt die Farbe der Textbeschriftungen.
SpecialEffect beinhaltet fünf verschiedene Effekte, die Rand-darstellung betreffend.
Position Height ist die Höhe der Dialogbox.
Left Wird die StartUpPosition auf Manuell gesetzt, so erscheint die Dialogbox so viele Pixel vom lin-ken Bildschirmrand entfernt.
StartUpPosition bestimmt die Lage der Position, wenn die Dia-logbox aufgerufen wird – in der Mitte des Bild-schirms, links oben (Voreinstellung) oder benut-zerdefiniert.
Top Wird die StartUpPosition auf Manuell gesetzt, so erscheint die Dialogbox so viele Pixel vom oberen Bildschirmrand entfernt.
Width bedeutet die Breite der Dialogbox.
Schriftart Font Die Schriftart erscheint überflüssig. Allerdings werden mit der Schriftart und Größe auf dem Formblatt die Standardschrift für die weiteren Elemente auf diesem Dialogblatt festgelegt.
Kategorie Eigenschaft Beschreibung
116
Dialog und Befehlsschaltfläche
Zusammenfassung der Methoden der Userform
Tab. 10.2: Zusammenfassung der Methoden der Userform
Verhalten Cycle Werden die einzelnen Elemente mit der Tabu-latortaste durchlaufen, so kann entschieden werden, ob nur die sichtbaren oder alle Ele-mente angesprungen werden.
Enabled Wird der Wert auf »False« gesetzt, so erscheint zwar die Dialogbox, die Schaltflächen sind aber nicht aktivierbar, das heißt, die Dialogbox ist nicht eingabefähig und kann auch keine Be-fehle entgegennehmen.
Verschiedenes (Name) ist der Name der Dialogbox, mit der sie ange-steuert, das heißt aufgerufen und geschlossen, werden kann.
DrawBuffer ist der zur Verfügung gestellte Speicher.
HelpContextID ist die Nummer einer Hilfedatei.
MouseIcon ist der Dateiname eines Mauszeigers.
MousePointer Hier kann aus einer Liste von acht verschiede-nen Mauszeigern gewählt werden.
Tag Hier könnten Kommentare stehen, die mögli-cherweise ausgelesen werden.
WhatsThisButton kann nur in Verbindung mit der Option Whats-ThisHelp eingeschaltet werden.
WhatsThisHelp fügt eine Schaltfläche für Hilfefunktionen ne-ben dem Schließen-Symbol ein.
Zoom Die Ansicht kann vergrößert oder verkleinert werden.
Kategorie Eigenschaft Beschreibung
Kategorie Eigenschaft Beschreibung
Zwischen-ablage
CopyPasteCut
schneidet aus, kopiert und fügt ein.
Anzeige HideShow
zeigt die Userform an oder verbirgt sie.
Lage Move verschiebt.
Aktionen PrintFormWhatsThisMode
druckt aus.
RedoActionUndoAction
macht Rückgängig.wiederholt.
117
10 Dialoge
Zusammenfassung der Ereignisse der Userform
Tab. 10.3:Zusammenfassungder Ereignisse der
Userform
Zusammenfassung der Eigenschaften der Befehlsschaltfläche (Commandbutton)
Tab. 10.4:Zusammenfassungder Eigenschaftender Befehlsschalt-
fläche (Command-button)
Kategorie Eigenschaft Beschreibung
Start ActivateInitialize
Initialize wird nur beim Start ausgeführt, Activate auch, wenn von einer Userform auf eine andere gewechselt wird.
Mausereignisse ClickDblClickMouseDownMouseUpMouseMove
KlickDoppelklickDie Maus wird gedrückt.
Die Maus wird über die Form gezogen.
Tastenereig-nisse
KeyDownKeyPressKeyUp
Eine (beliebige) Taste wird gedrückt.
Bewegung ResizeScrollZoom
Größe wird verändert oder gescrollt.
BeforeDragOverBeforeDropAndPaste
Vor dem Ziehen oder Einfügen
Sonstiges AddControlRemoveControlErrorQueryClose
Ein Steuerelement wird hinzugefügt oder gelöscht.Ein Fehler tritt auf.
DeactivateTerminateQueryClose
Terminate wird beim Entladen des Formulars gestartet, Deactivate auch, wenn von einem Formular auf ein anderes gesprungen wird. Mit QueryClose können weitere Schließ-Modalitäten abgefangen werden.
Kategorie Eigenschaft Beschreibung
Darstellung ControlTipText Dieser Text erscheint in einem Quickinfo, wenn der Mauszeiger einige Sekunden auf der Schaltfläche bleibt.
Visible Die Schaltfläche ist sichtbar, wenn »True« / »Ja« gewählt wurde.
Verhalten AutoSize Wird diese Option auf »True« gesetzt, so verändert sich die Größe der Schaltfläche beim Verändern der Caption automatisch so, dass der gesamte Text gerade noch les-bar ist.
118
Dialog und Befehlsschaltfläche
Zusammenfassung der Methoden der Befehlsschaltfläche
Tab. 10.5: Zusammenfassung der Methoden der Befehlsschaltfläche
Cancel Wird »True« / »Ja« eingeschaltet, so wird diese Schaltfläche mit der Taste (Esc) aus-gelöst.
Default Eine der Schaltflächen kann als Standard ausgewählt werden und dann nach Aufru-fen der Dialogbox mit (¢) betätigt werden.
Enabled Auf »False« / »Nein« gesetzt wäre diese Schaltfläche nicht aktivierbar und die Schrift erschiene in einem hellen Grau.
Locked Auf »False« gesetzt wäre diese Schaltfläche nicht aktivierbar, ohne dass die Schrift in ei-nem hellen Grau erscheint.
TakeFocusOnClick Nach dem Klicken auf diese Schaltfläche be-hält sie den Fokus.
WordWrap Erlaubt bei »True« einen Zeilenumbruch bei einem langen Caption-Text, bei »False« ist nur ein einzeiliger Text möglich.
Verschiedenes Accelerator Der Buchstabe, der hier eingegeben wird, muss Teil der Caption sein. Dann erscheint er unterstrichen auf der Schaltfläche. Nun kann die Schaltfläche mit (Alt) + dem Buchstaben aktiviert werden. Wird zweimal derselbe Buchstabe vergeben, so ruft (Alt) + Buchstabe die erste Schaltfläche auf.
TabIndex Die Reihenfolge, mit der beim Drücken der (ÿ)-Taste die einzelnen Schaltflächen an-gesprungen werden. Dies kann auch über ANSICHT – AKTIVIERREIHENFOLGE oder mit der rechten Maustaste (Aktivierreihenfolge) gesteuert werden.
TabStop Wird »False« / »Nein« eingeschaltet, so kann diese Schaltfläche nicht mit der Tabu-latortaste angesprungen werden.
Kategorie Eigenschaft Beschreibung
Kategorie Eigenschaft Beschreibung
Aktivieren SetFocus Der »Focus« wird auf die Befehlsschaltfläche gelegt.
Reihenfolge ZOrder Die Reihenfolge bei gestapelten Steuerele-menten wird festgelegt.
119
10 Dialoge
Die Befehlsschaltfläche verwendet folgende Ereignisse:
Tab. 10.6:Zusammenfassungder Ereignisse der
Befehlsschaltfläche
Übung 1
Ein Klick auf die ABBRECHEN-Schaltfläche meldet, dass die Userform nun beendetwird und schließt diese.
Übung 2
Ein Klick auf eine Schaltfläche verändert die Farbe der Userform, indem ver-schiedene Farben nacheinander angezeigt werden.
Übung 3
Ein Klick auf eine Schaltfläche ändert den Mauszeiger der Userform.
Übung 4
Bei einem Formular steht in der Titelzeile immer die aktuelle Position desCursors.
Übung 5
In einem Formular steht in der Titelzeile das aktuelle Datum.
Übung 6
Auf einem Formular befindet sich eine Befehlsschaltfläche. Versucht der Benut-zer darauf zu klicken, dann springt sie zur Seite. Versucht er auf die neue Schalt-fläche zu klicken, dann sitzt sie wieder an der alten Position.
Kategorie Ereignis Kategorie Ereignis
Start Enter Änderungen BeforeDragOverBeforeDropAndPaste
Mausereignisse ClickDblClickMouseDownMouseUpMouseMove
Sonstiges Error
Tastenereignisse KeyDownKeyPressKeyUp
Ende Exit
10.2 Übungen
120
Tipps
Übung 7
Auf einer Userform befindet sich eine Befehlsschaltfläche mit der Beschriftung»Erweitern«. Klickt der Benutzer auf diese Schaltfläche, dann wird die Formgrößer und der Text ändert sich in »Verkleinern«. Ein weiterer Klick verkleinertdie Form und ändert den Text erneut in »Vergrößern«.
Tipp zu Übung 1
Bitte verwenden Sie nicht die Methode Hide, da dann die Userform noch immerim Arbeitsspeicher wäre. Um sie ganz zu entladen, muss der Befehl Unload ver-wendet werden.
Tipp zu Übung 3
Es gibt sicherlich viele Lösungen mit ganz unterschiedlichen Effekten. Mankönnte den Wert von Me.BackColor von 0 bis 50.000.000 (in einer bestimmtenSchrittfolge) hoch zählen lassen. Oder die Funktion RGB verwenden.
Tipp zu Übung 4
Achtung: Bei dieser Übung wird das Steuerelement »Userform« verwendet mitdem Ereignis »MouseMove«.
Tipp zu Übung 6
Für diesen kleinen, überflüssigen Scherz existieren eine Reihe von Lösungen.Man könnte mit zwei Schaltflächen arbeiten, von denen die eine sichtbar (Vi-sible = True), die andere unsichtbar ist. Dann wird ein Code benötigt, der sieabwechselnd ein- und ausblendet. Die zweite Möglichkeit verwendet die Eigen-schaft Left, um die Position (vom linken UserForm-Rand) neu zu belegen. Diedritte Möglichkeit verwendet die Methode Move und verschiebt die Befehls-schaltfläche (beispielsweise von 12 auf 120 und von 120 auf 12).
Lösung 1
Private Sub cmdAbbrechen_Click()MsgBox "Das war's dann, Leute."Unload MeEnd Sub
10.3 Tipps
10.4 Lösungen
121
10 Dialoge
Lösung 2
Dim lngFarbzähler As LongDim intdummy As IntegerFor lngFarbzähler = 1 To 255 Me.BackColor = RGB(lngFarbzähler, 255 – lngFarbzähler, _ 255 – lngFarbzähler) Me.Repaint For intdummy = 1 To 3200 Sin (Cos(intdummy ^ 2)) Next intdummyNext lngFarbzählerUnload Me
Lösung 3
Private Sub cmdAbbrechen_Click()If Me.MousePointer <> fmMousePointerSizeAll Then Me.MousePointer = Me.MousePointer + 1Else Me.MousePointer = fmMousePointerDefaultEnd IfEnd Sub
Lösung 4
Private Sub UserForm_MouseMove(ByVal Button As Integer, _ByVal Shift As Integer, ByVal X As Single, ByVal Y As Single)Me.Caption = "x: " & Format(X, "000.00") & _ " y: " & Format(Y, "000.00")End Sub
Lösung 5
Private Sub UserForm_Initialize()Me.Caption = "Heutiges Datum: " & DateEnd Sub
Lösung 6
Variante 1:
Private Sub UserForm_Initialize()cmdGehaltserhöhung1.Visible = TruecmdGehaltserhöhung2.Visible = FalseEnd Sub
Private Sub cmdGehaltserhöhung1_MouseMove _ (ByVal Button As Integer, ByVal Shift As Integer, _ ByVal X As Single, ByVal Y As Single)
122
Lösungen
cmdGehaltserhöhung1.Visible = FalsecmdGehaltserhöhung2.Visible = TrueEnd Sub
Private Sub cmdGehaltserhöhung2_MouseMove _ (ByVal Button As Integer, ByVal Shift As Integer, _ ByVal X As Single, ByVal Y As Single)cmdGehaltserhöhung1.Visible = TruecmdGehaltserhöhung2.Visible = FalseEnd Sub
Variante 2:
Private Sub cmdGehaltserhöhung3_MouseMove _ (ByVal Button As Integer, ByVal Shift As Integer, _ ByVal X As Single, ByVal Y As Single)If cmdGehaltserhöhung3.Left = 12 Then cmdGehaltserhöhung3.Left = 120Else cmdGehaltserhöhung3.Left = 12End IfEnd Sub
Variante 3:
Private Sub cmdGehaltserhöhung4_MouseMove _ (ByVal Button As Integer, ByVal Shift As Integer, _ ByVal X As Single, ByVal Y As Single)cmdGehaltserhöhung4.Move Left:=132 – cmdGehaltserhöhung4.LeftEnd Sub
Lösung 7
Dim dblFormgröße As Double
Private Sub UserForm_Initialize()dblFormgröße = Me.HeightMe.cmdErweitern.Caption = "Erweitern"End Sub
Private Sub cmdErweitern_Click()If Me.Height = dblFormgröße Then Me.Height = dblFormgröße * 1.5 Me.cmdErweitern.Caption = "Reduzieren"Else Me.Height = dblFormgröße Me.cmdErweitern.Caption = "Erweitern"End IfEnd Sub
123
10 Dialoge
10.5 Textfelder, Beschriftungsfelder und Anzeige
Zusammenfassung der Eigenschaften des Textfeldes (Textbox):
Tab. 10.7:Zusammenfassungder Eigenschaften
des Textfeldes
Kategorie Eigenschaft Beschreibung
Darstellung PasswordChar Der eingegebene Text wird nicht angezeigt, sondern am Bildschirm nur durch dieses Zeichen dargestellt, beispielsweise: *.
Daten ControlSource bezeichnet die Stelle, wo Daten gespeichert sein können oder von wo sie geholt werden können.
Text Vorgabetext
Verhalten AutoSize vergrößert die Textbox automatisch bei der Eingabe von Text.
AutoTab Ist bei MaxLength ein Wert > 0 eingetragen, so wird nach dieser Zeichenanzahl die Textbox verlassen.
AutoWordSe-lect
Beim Markieren wird das zweite, dritte, ... Wort im-mer ganz markiert.
Enabled Text kann eingegeben werden, wenn der Wert auf »True«/»Ja« steht.
EnterKeyBeha-vior
Das Drücken der (¢)-Taste bewirkt einen Zeilen-umbruch, wenn MultiLine eingeschaltet ist. Sonst wird der OK-Button aufgerufen, wenn sein Default-Wert auf »True« gesetzt ist.
HideSelection gibt an, ob ausgewählter Text weiter markiert bleibt, wenn das Textfeld nicht den Fokus hat.
IntegralHeight zeigt an, ob ein Textfeld ganze Textzeilen oder Teile von Zeilen anzeigt werden.
Locked keine Texteingabe möglich.
MaxLength Maximale Anzahl der Zeichen, die eingegeben wer-den können. Die Vorgabe 0 bedeutet beliebig viele, das heißt: maximal.
MultiLine längerer Text bricht automatisch in die nächste Zeile um
SelectionMar-gin
gibt an, ob der Benutzer eine Textzeile durch Klicken im Bereich links vom Text markieren kann.
TabKeyBeha-vior
ermöglicht die Eingabe eines Tabulators (wenn Au-toTab auf »False« gesetzt wurde).
TextAlign Ausrichtung (linksbündig, rechtsbündig, zentriert)
WordWrap bewirkt einen automatischen Zeilenumbruch (wenn MultiLine auf »True« gesetzt wurde).
Verschiede-nes
DragBehavior Drag&Drop innerhalb der Textbox möglich.
124
Textfelder, Beschriftungsfelder und Anzeige
Zusammenfassung der Ereignisse der Textbox:
Tab. 10.8: Zusammenfassung der Ereignisse der Textbox
Zusammenfassung der Eigenschaften der Anzeige (Image):
Tab. 10.9: Zusammenfassung der Eigenschaften der Anzeige (Image):
Bezeichnungsfeld (Label)
Alle Eigenschaften der Bezeichnungsfelder und der Anzeigen wurden schon beiden obengenannten Steuerelementen beschrieben. Es gibt keine Eigenschaft,die sich per Programmierung einstellen lässt. Die einzigen drei Methoden, diebei beiden Steuerelementen zur Verfügung stehen, sind Move, SetFocus undZOrder. SetFocus setzt beim Bezeichnungsfeld den Focus auf das nächste Steu-erelement, das in der Aktivierreihe festgelegt wurde.
EnterFieldBeha-vior
Ein Sprung mit der Tabulatortaste in die Textbox be-wirkt eine Markierung des Vorgabetexts oder des geschriebenen Texts.
HelpContextID die Nummer der Hilfedatei
IMEMode IME steht für Input Method Editor, mit dem Zeichen-eingaben in Sprachen wie Japanisch oder Chinesisch übersetzt werden.
Kategorie Eigenschaft Beschreibung
Kategorie Ereignis Kategorie Ereignis
Start Enter Änderungen BeforeUpdateAfterUpdateDropButtonClick
Mausereignisse DblClickMouseDownMouseUpMouseMove
BeforeDragOverBeforeDropAndPaste
Tastenereignisse KeyDownKeyPressKeyUpChange
Sonstiges Error
Ende Exit
Kategorie Eigenschaft Beschreibung
Bild Picture gibt das anzuzeigende Bild an.
PictureAlignment zeigt die Ausrichtung des Bildes.
PictureSizeMode präsentiert die Größe des Bildes.
PictureTiling legt fest, ob das Bild mehrmals nebeneinander gekachelt dargestellt wird oder nicht.
125
10 Dialoge
Da ein Bezeichnungsfeld und die Anzeige von außen nur durch die Maus ange-stoßen werden können, stehen nur folgende Ereignisse zur Verfügung:
Click, DblClick, MouseDown, MouseUp, MouseMove, BeforeDragOver, BeforeDropAndPaste und Error.
Excel stellt für die Eingabe eines Zellbereichs ein Steuerelement mit Namen REF-EDIT zur Verfügung. Damit kann der Benutzer auf einer Tabelle einen Bereichmarkieren, der dann in der Form
Tabelle1!$B$4:$D$10
im Steuerelement angezeigt und abgefangen werden kann. Das folgende Bei-spiel zeigt die Zielwertsuche in Excel:
Übung 1
Bei einem Klick auf eine Befehlsschaltfläche soll der Inhalt eines Textfeldes an-gezeigt werden.
Übung 2
Bei der Texteingabe soll der Text auf einem Bezeichnungsfeld angezeigt werden.
Übung 3
Beim Verlassen eines Textfeldes soll der Text in der Titelzeile der Userform ange-zeigt werden.
Übung 4
Beim Verlassen eines Textfeldes wird überprüft, ob der eingegebene Wert eineZahl ist. Falls nicht, dann erfolgt eine Fehlermeldung und der Inhalt des Text-felds wird geleert.
Abbildung 10.1:Ein Beispiel aus
Excel für zwei Ref-Edit-Felder
10.6 Übungen
126
Tipps
Übung 5
Der Benutzer kann in einem Textfeld nur Zahlen und Kommata eingeben.
Übung 6
Die Farbe der Beschriftung eines Bezeichnungsfeldes ändert sich, wenn derMauszeiger darüber fährt.
Übung 7
Ein Text »wandert« über eine Userform. Es wird eine Laufschrift simuliert.
Übung 8
Ein Klick auf eine Bildbeschriftung (Label) lädt ein anderes Bild und ändert denvorhandenen Text.
Übung 9
Klickt der Benutzer mit gedrückter (Strg)-Taste auf ein Bild, dann erscheinenKommentare zum Bild, bei gedrückter (ª)-Taste der Name des Malers und bei(Alt) das Erstellungsjahr. Werden mehrere Tasten gedrückt, dann erfolgt einHinweis, dass nur eine Taste zu drücken ist.
Tipp zu Übung 1 – 4
Achten Sie auf das richtige Ereignis und verwechseln Sie nicht Caption, Nameund Value!
Tipp zu Übung 5
Die folgende Lösung überprüft die vom Benutzer gedrückte Taste. Liegt derAscii-Wert unter Asc("0"), so könnte es sich um ein Komma handeln. Hat derBenutzer ein Komma (oder einen Punkt) gedrückt, so wird nachgeschaut, obschon ein Komma innerhalb der bereits eingegebenen Zeichenkette vorhandenist. Falls nein, so wird ein Komma erzeugt. Ausgeschlossen sind weiterhin alleZeichen mit einem Asciiwert über dem der 9. Bei ihnen geschieht keine Reak-tion. Alle anderen Zeichen (die Ziffern von 0 bis 9) werden problemlos darge-stellt. Man könnte statt des Ereignisses KeyPress auch KeyDown verwenden, al-lerdings nicht KeyUp! Bei KeyDown werden andere Werte für die übergebeneVariable KeyCode verwendet. Außerdem muss nun noch die Taste (Entf) und(Rück) abgefangen werden.
10.7 Tipps
127
10 Dialoge
Tipp zu Übung 6
Wichtig ist hierbei, dass die Farbe des Labels wieder ausgeschaltet wird, bei-spielsweise, wenn sich der Mauszeiger auf der Userform bewegt.
Tipp zu Übung 9
Die Tasten (ª), (Strg) und (Alt) können nicht über das Ereignis Click abgefan-gen werden, sondern über das Ereignis MouseDown. In der Hilfe finden sich dieWerte für die Variable Shift, um die gedrückten Tasten abzufangen.
Lösung 1
Es existieren mehrere Varianten zum Abfangen eines Textes. Man kann die »Ob-jektcascade« hinabsteigen:
Private Sub cmdOk_Click() MsgBox "Bitte zahlen Sie: " & Me.txtBetrag.TextEnd Sub
Oder man kann mit der Eigenschaft Value arbeiten:
Private Sub cmdOk_Click() MsgBox "Bitte zahlen Sie: " & Me.txtBetrag.ValueEnd Sub
Auf das Me kann verzichtet werden:
Private Sub cmdOk_Click() MsgBox "Bitte zahlen Sie: " & txtBetrag.ValueEnd Sub
Da Value die Standardeigenschaft des Textfelds ist, kann auch darauf verzichtetwerden:
Private Sub cmdOk_Click() MsgBox "Bitte zahlen Sie: " & txtBetragEnd Sub
Lösung 2
Private Sub txtBetrag_Change() Me.lblBezeichnung.Caption = Me.txtBetrag.ValueEnd Sub
Oder in der kurzen Variante:
10.8 Lösungen
128
Lösungen
Private Sub txtBetrag_Change() lblBezeichnung = txtBetragEnd Sub
Lösung 3
Private Sub txtBetrag_Exit _ (ByVal Cancel As MSForms.ReturnBoolean) Me.Caption = Me.txtBetrag.ValueEnd Sub
Lösung 4
Private Sub txtBetrag_Exit _ (ByVal Cancel As MSForms.ReturnBoolean) If Not IsNumeric(Me.txtBetrag.Value) Then MsgBox "Es wurde keine Zahl eingegeben!" Me.txtBetrag.Value = "" End IfEnd Sub
Die Bedingung könnte auch formuliert werden:
If IsNumeric(Me.txtBetrag.Value) = False Then
[…]
Sehr schwierig wird es, wenn der Cursor bei einer falschen Eingabe wieder indas Textfeld zurückgesetzt werden soll. Die Ursache der Schwierigkeit liegt da-rin, dass VBA die Steuerelemente in einer bestimmten Reihenfolge abarbeitet.Und diese Reihenfolge kann nicht geändert werden. Das bedeutet: man kannbeim Verlassen eines Textfeldes prüfen, ob ein Wert eine bestimmte Eigenschaftnicht erfüllt und dann den Focus auf ein Steuerelement setzen. Danach wird al-lerdings das ursprüngliche Ereignis (Mausklick oder Tabsprung) abgearbeitet.Die Lösung, mit der der Cursor zurückgesetzt wird, sieht nun wie folgt aus:
Beim Verlassen eines Textfeldes wird überprüft, ob es sich um eine Zahl handelt.Falls nicht, dann wird eine global deklarierte Variable auf »False« gesetzt:
Dim fwert as BooleanPrivate Sub TextBox1_Exit _ (ByVal Cancel As MSForms.ReturnBoolean)If Not IsNumeric(Me.TextBox1.Value) Then fwert = FalseElse fwert = TrueEnd IfEnd Sub
129
10 Dialoge
Nun muss in jedem Steuerelement (mit Ausnahme der Userform und der Labels)jeweils im Ereignis Enter der Wert von fwert überprüft werden. Beispielsweiseso:
Private Sub TextBox2_Enter()If fwert = False Then Me.TextBox1.SetFocusEnd IfEnd Sub
Private Sub cmbListe_Enter()If fwert = False Then Me.TextBox1.SetFocusEnd IfEnd Sub
[...]
Damit werden zwar beim Verlassen des Textfeldes, wenn die Eingabe keine Zahlist, alle Steuerelemente durchlaufen (der Einzelschrittmodus zeigt dies sehrschön), aber zu guter Letzt bleibt der Cursor bei der »falschen« Eingabe imTextfeld sitzen. Dies ist viel Tipp- oder Kopierarbeit. Man kann die Funktionalitätzwar in eine Prozedur auslagern, aber sie muss auch von allen Steuerelementenaufgerufen werden.
Lösung 5
Private Sub txtWert_KeyPress _ (ByVal KeyAscii As MSForms.ReturnInteger)Select Case KeyAsciiCase Is < Asc("0") If (KeyAscii = Asc(",") Or KeyAscii = Asc(".")) _ And InStr(Me.txtWert.Value, ",") = 0 Then KeyAscii = Asc(",") Else KeyAscii = 0 End IfCase Is > Asc("9") KeyAscii = 0End SelectEnd Sub
oder alternativ:
Private Sub txtWert_KeyDown _ (ByVal KeyCode As MSForms.ReturnInteger, _ ByVal Shift As Integer)Select Case KeyCodeCase 8, 46
130
Lösungen
Case Is < Asc("0") KeyCode = 0Case Is > Asc("9") If (KeyCode = 188 Or KeyCode = 190) _ And InStr(Me.txtWert.Value, ",") = 0 Then KeyCode = 188 Else KeyCode = 0 End IfEnd Select
End Sub
Lösung 6
Private Sub lblBezeichnung_MouseMove _ (ByVal Button As Integer, ByVal Shift As Integer, _ ByVal X As Single, ByVal Y As Single) Me.lblBezeichnung.ForeColor = &HFF0000End SubPrivate Sub UserForm_MouseMove _ (ByVal Button As Integer, ByVal Shift As Integer, _ ByVal X As Single, ByVal Y As Single) Me.lblBezeichnung.ForeColor = &H80000012End Sub
Lösung 7
Private Sub UserForm_MouseMove _ (ByVal Button As Integer, ByVal Shift As Integer, _ ByVal X As Single, ByVal Y As Single)Dim i As Integer
Do
If Me.Label1.Left = 10 Then For i = 1 To 1000 Me.Label1.Left = Me.Label1.Left + 0.2 Me.Repaint Next Else
Me.Label1.Left = 10
End If
Loop
End Sub
131
10 Dialoge
Dieses Beispiel hat zwei Nachteile. Zum einen kann es nur noch mit der Tasten-kombination (Strg)+(Unterbrechen) beendet werden. Zum anderen könnenkeine weiteren Ereignisse verarbeitet werden, während diese Prozedur läuft.Vielleicht sollte man die Schleife nur ein Mal durchlaufen lassen ...
Lösung 8
Option ExplicitDim strInfo(1 To 7) As StringDim strBildPfad As String
Private Sub lblBildInfo_Click()Select Case Left(lblBildInfo.Caption, 5)Case "Leona" lblBildInfo.Caption = strInfo(2) imgKunst.Picture = LoadPicture(strBildPfad & "Botti.bmp")Case "Botti" lblBildInfo.Caption = strInfo(3) imgKunst.Picture = LoadPicture(strBildPfad & "Michel.bmp")Case "Miche" lblBildInfo.Caption = strInfo(4) imgKunst.Picture = LoadPicture(strBildPfad & "Rembr.bmp")Case "Rembr" lblBildInfo.Caption = strInfo(5) imgKunst.Picture = LoadPicture(strBildPfad & _ "VanGogh.bmp")Case "Van G" lblBildInfo.Caption = strInfo(6) imgKunst.Picture = LoadPicture(strBildPfad & "Seurat.bmp")Case "Seura" lblBildInfo.Caption = strInfo(7) imgKunst.Picture = LoadPicture(strBildPfad & "Monet.bmp")Case Else lblBildInfo.Caption = strInfo(1) imgKunst.Picture = LoadPicture(strBildPfad & "Vinci.bmp")End Select
End Sub
Private Sub UserForm_Initialize()strBildPfad = "C:\Eigene Dateien\Eigene Bilder\"
strInfo(1) = "Leonardo da Vinci" & vbCr & vbCr & _"ital. Maler, Bildhauer, Architekt, Kunstteheoretiker " & _"Naturforscher u. Mechaniker" & vbCr & _"*1452 – 1519; zuerst Schüler Verocchios in Florenz, " & _" dann (1482 – 99) in Mailand am Hofe, nach Etappen in " & _
132
Lösungen
"Florenz, Mailand und Rom; zuletzt in Frankreich; " & _"universales Genie der Renaissance. In seinen Gemälden " & _"verband L. Körper und Raum durch Umrisse verschleiernde" & _" Lichtwirkung (sfumato). Hptw.: ""Abendmahl"", " & _"""Mona Lisa"" und ""Anna Selbdritt"""
strInfo(2) = "Botticelli, Sandro" & vbCr & vbCr & _"ital. Maler *1444 – 1510;" & vbCr & _"neben wichtigen Porträts " & _"religiöse und allegorische Bilder. Hauptw.: " & _"""Frühling"", ""Geburt d. Venus"", Madonnen, Fresken in" & _" der Sixtinischen Kapelle."
strInfo(3) = "Michelangelo Buonarotti" & vbCr & vbCr & _[...]
strInfo(7) = "Manet, Edouard" & vbCr & vbCr & _[...]imgKunst.Picture = LoadPicture(strBildPfad & "Vinci.bmp")lblBildInfo.Caption = strInfo(1)End Sub
Das Ergebnis kann sich sehen lassen:
Abbildung 10.2: Das Ergebnis
133
10 Dialoge
Übrigens scheint VBA an dieser Stelle einen Bug zu haben: Klickt der Benutzerauf das Bild mit der Eigenschaft Enabled = True, dann wird zwar der Text geän-dert allerdings nicht mehr das Bild!
Lösung 9
Private Sub imgKunst_MouseDown _ (ByVal Button As Integer, _ ByVal Shift As Integer, _ ByVal X As Single, ByVal Y As Single)Select Case ShiftCase 0Case 1 MsgBox "Leonardo da Vinci"Case 2 MsgBox "Die einen halten sie für einen Ausdruck " & _ "kosmischer Sanftmut und Güte, die anderen halten " & _ "das Gemälde für puren Kitsch."Case 4 MsgBox "Die Mona Lisa wurde 1503 gemalt."Case Else MsgBox "Bitte nur eine Taste drücken!"End SelectEnd Sub
10.9 Rahmen, Optionsfeld, Kontrollkästchen und Umschaltfeld
Zusammenfassung der Eigenschaften der Optionsfelder (Optionbutton),Kontrollkästchen (Chekckbox) und Umschaltfelder (Togglebutton)
Tab. 10.10:Zusammenfassungder Eigenschaftender Optionsfelder,Kontrollkästchen
und Umschaltfelder
Die Ereignisse unterschieden sich nicht von den Ereignissen der Textfelder.
Der Rahmen hat eine ästhetische Bedeutung zur Gliederung auf einer Userform.Er hat aber auch eine pragmatische Funktion: Soll aus Gruppen von mehrerenOptionsfeldern jeweils eines ausgewählt werden, dann müssen sie in einem
Kategorie Eigenschaft Beschreibung
Verschiedenes GroupName Hier kann manuell der Name des Gruppenfelds ein-getragen werden.
Darstellung Value »False« bedeutet nicht angeklickt, »True« heißt, dass das Optionsfeld eingeschaltet ist und »Null« heißt weder noch.
Verhalten TripleState legt fest, ob »Null« möglich ist.
134
Übungen
Rahmen zusammengefasst werden. Dazu sollte zuerst der Rahmen gezeichnetwerden und dann sollten die Optionsfelder hineingezogen werden.
Alle Eigenschaften und Methoden des Rahmens sind bereits erwähnt worden.Lediglich per VBA ist es möglich, über die Eigenschaft ActiveControl denOptionsbutton zu bestimmen, der ausgewählt wurde. Allerdings setzt dies einAuswählen des Benutzers voraus. Beim Start der Userform muss deshalb mit derMethode SetFocus ein Steuerelement aktiviert werden, welches so nun zum Ac-tiveControl wurde, falls der Benutzer nichts auswählt. Mit der Sammlung Cont-rols kann auf alle Steuerelemente innerhalb des Rahmens zugegriffen werden.
Ein wichtiger Unterschied existiert zwischen den Optionsfeldern und Kontroll-kästchen (beziehungsweise Umschaltfeldern). Jedes Kontrollkästchen kann ein-und ausgeschaltet werden. Aus einer Reihe von Optionsfeldern kann allerdingsimmer nur eines ausgewählt werden.
Übung 1
Auf einer Userform befinden sich zwei Rahmen. Der erste enthält fünf Options-felder, der zweite vier. Ein Klick auf eine Befehlsschaltfläche zeigt an, welchebeiden Optionsfelder angeklickt wurden. Es existieren mehrere Lösungen!
10.10 Übungen
Abbildung 10.3: Ein Beispiel aus Word, bei dem zwei Gruppen von jeweils fünf beziehungsweise vier Optionsfeldern vorliegen
135
10 Dialoge
Übung 2
Auf einer Userform befinden sich mehrere Kontrollkästchen. Ein Klick auf eineBefehlsschaltfläche zeigt an, welche der Kontrollkästchen angeklickt wurden.Es existieren mehrere Lösungen!
Übung 3
Eine Umschaltfläche leert ein Textfeld.
Übung 4
Wird ein Kontrollkästchen angeklickt, dann steht in einem Textfeld der Vorga-bewert 12, wird es ausgeschaltet, dann wird das Textfeld geleert.
Übung 5
Wird ein Kontrollkästchen eingeschaltet, dann können in zwei Textfelder Dateneingetragen werden. Wird es deaktiviert, dann ist die Eingabe nicht möglich.
Abbildung 10.4:Ein Beispiel ausWord, bei dem
mehrere Kontroll-kästchen vorliegen
136
Übungen
Abbildung 10.5: Ein Beispiel aus Word, bei dem ein Kontrollkästchen einen Wert (10) in ein Textfeld schreibt und es auch wie-der löscht
Abbildung 10.6: Ein Beispiel aus Word, bei dem über ein Kontroll-kästchen zwei Felder (hier: Dropdownfelder) aktiviert und deaktiviert werden können
137
10 Dialoge
Übung 6
In einem Rahmen befinden sich fünf Optionsfelder. Wird der letzte angeklickt,dann erscheint ein Textfeld, in das der Benutzer etwas eingeben kann. Bei denanderen vier verschwindet das Textfeld wieder.
Übung 7
Auf einem Bewertungsformular befinden sich mehrere Reihen (Kategorien) vonKontrollkästchen. Sie sind jeweils mit den Notenwerten 1 bis 5 bezeichnet. DerBenutzer kann nun aus jeder Reihe ein Kästchen auswählen oder zwei neben-einanderliegende auswählen (zum Beispiel für die Noten 2 oder 2 – 3). Es istaber verboten, aus einer Reihe drei Kästchen anzuklicken, ebenso wie die zweiausgewählten Kästchen nebeneinander liegen müssen.
Tipp zu Übung 1
Um zwei Gruppen von Optionsfeldern zu erhalten, können entweder zwei Rah-men gezogen werden, in die die Optionsfelder eingefügt werden, oder den Op-tionsfeldern wird in der Eigenschaft GroupName ein Gruppenname zugewiesen –für die zwei Gruppen also zwei Namen.
Abbildung 10.7:So könnte der
Bewertungsbogenaussehen.
10.11 Tipps
138
Tipps
Um den Wert des ausgewählten Optionsfeldes zu bestimmen, stehen mehrereVarianten zur Verfügung. Mit einer If-Abfrage können alle Optionsfelder ein-zeln überprüft werden. Als weitere Möglichkeit kann die Sammlung der Con-trols durchlaufen werden.
Eine weitere, elegante Variante übergibt einen Wert an eine Variable, wenn einOptionsfeld angeklickt wird. Da die Variable immer mit dem letzten Wert gefülltist, kann dieser schließlich ausgegeben werden. Achtung: wenn nichts ange-klickt wurde, dann wird auch kein Wert übergeben. Folglich muss bei der Initia-lisierung ein Wert festgelegt werden. Und: die Variable, die diesen Wert spei-chert, muss global, das heißt modulweit, deklariert werden.
Tipp zu Übung 2
Wie in Aufgabe 1 kann jedes Kontrollkästchen einzeln abgefragt werden:
Eine Schleife könnte auch alle Controls des Rahmens durchlaufen.
Es existiert allerdings noch eine weitere, sehr elegante Lösung: In einer globalenVariablen wird ein Wert gespeichert. Dabei übergibt chkAkzent den Wert 1,chkAusschneiden 2, chkEinfügen 4 und so weiter. Um nicht mit einer Modulo-Funktion überprüfen zu müssen, welche Werte die Variable enthält, kann dieFunktion Xor verwendet werden. Enthält der Wert schon die Zahl, dann wird sieabgezogen, enthält der Wert sie noch nicht, dann wird sie addiert. Beispiels-weise ergibt 3 Xor 1 das Ergebnis 2, dagegen liefert 2 Xor 1 den Wert 3. So lässtXor den Wert der Variablen stets zwischen zwei Werten springen und funktio-niert als Umschaltfunktion. Achtung: Wenn mehr als acht Werte gespeichertwerden sollen, dann muss der Typ der Variablen größer sein als byte!
Tipp zu Übung 3
Es existieren für diese Aufgabe mehrere Lösungen. Soll ein einfacher Klick dasFeld löschen, dann genügt eine Anweisung. Soll nur beim Hineindrücken dasFeld gelöscht werden und beim erneuten Eingeben von Text der Schalter wiederzurückgesetzt werden, dann wird eine zweite Prozedur benötigt.
Tipp zu Übung 5
Beim Initialisieren wird die Eigenschaft Enabled der beiden Textfelder ausge-schaltet. Damit der Benutzer dies sieht, wird die Hintergrundfarbe auf grau ge-setzt. Auch die Farbe der beiden Bezeichnungsfelder wird grau formatiert.
Im Kontrollkästchen wird nun die Farbe bestimmt. Bei Eigenschaften, die nurzwei Möglichkeiten zulassen, wird die jeweils andere verwendet. Bei Farben istdies nicht möglich, da dort mehrere Optionen zur Verfügung stehen.
139
10 Dialoge
Tipp zu Übung 6
In den Eigenschaften oder beim Initialisieren der Userform wird die EigenschaftVisible auf »False« gesetzt. Ein Klick auf ein Optionsfeld schaltet die Eigen-schaft auf »True«. Auf allen anderen Optionsfeldern muss diese Eigenschaftwieder zurückgesetzt werden.
Bei sehr vielen Optionsfeldern könnte man diese Prozedur auch auslagern.
Tipp zu Übung 7
Sicherlich gibt es zu diesem Problem eine ganze Reihe verschiedener Lösungen.An dieser Stelle sollen zwei vorgestellt werden.
Vernünftigerweise sollte man sich ein System für die Namen der Kontrollkäst-chen überlegen, da auf diese zugegriffen wird. Im folgenden Beispiel wurdensie so benannt:
und so weiter bis:
Die erste Lösung speichert in zwei Variablen (intWert und intSchalter) ab, wieviele Werte schon angeklickt wurden (intSchalter) und welche (intWert). Diesebeiden Werte werden beim Einschalten herausgezählt, beim Ausschalten her-abgezählt. Wird dem Benutzer das fälschlicherweise eingeschaltete Kästchenper Programmierung wieder ausgeschaltet (Me.ActiveControl.Value = False),dann wird leider der Code erneut aufgerufen, dies muss bei der Programmie-rung beachtet werden.
Die zweite Lösung überprüft alle Kontrollkästchen. Dabei läuft eine Schleifedurch sämtliche Steuerelemente (Controls). Von ihnen wird überprüft, ob essich um ein Kontrollkästchen handelt (der Name beginnt mit »chk«). Falls ja, sowird nachgeschaut, ob es in der gleichen Zeile liegt, wie das Steuerelement, aufdas der Benutzer geklickt hat. Falls dies der Fall ist, dann wird überprüft, ob dasKlicken ein Einschalten bewirkt. Falls ja, so wird getestet, ob bereits zwei Kon-trollkästchen eingeschaltet sind. In diesem Falle erhält der Benutzer eine Mel-dung. Falls nur eines eingeschaltet ist, dann wird überprüft, ob das neu »hinzu-geschaltete« direkt neben dem schon eingeschalteten liegt. Falls nicht, dannerhält der Benutzer erneut eine Meldung.
chk0101 chk0102 chk0103 chk0104 chk0105
chk0201 chk0202 chk0203 chk0204 chk0205
chk0301 chk0302 chk0303 chk0304 chk0305
chk1201 chk1202 chk1203 chk1204 chk1205
140
Lösungen
Lösung 1
Variante 1
Private Sub cmdOk_Click()Dim strAusgabe As StringIf Me.optLinks.Value = True Then strAusgabe = "links"ElseIf Me.optZentriert.Value = True Then strAusgabe = "zentriert"ElseIf Me.optRechts.Value = True Then strAusgabe = "rechts"ElseIf Me.optDezimal.Value = True Then strAusgabe = "dezimal"ElseIf Me.optVertikaleLinie.Value = True Then strAusgabe = "vertikale Linie"End If
If Me.opt1.Value = True Then strAusgabe = strAusgabe & " 1"ElseIf Me.opt2.Value = True Then strAusgabe = strAusgabe & " 2"ElseIf Me.opt3.Value = True Then strAusgabe = strAusgabe & " 3"ElseIf Me.opt4.Value = True Then strAusgabe = strAusgabe & " 4"End IfMsgBox strAusgabeEnd Sub
Dies ist sicherlich eine einfache, wenn auch eine unübersichtliche Methode.Wenn mit Rahmen gearbeitet wird, dann muss zuvor mit SetFocus ein Options-button aktiviert werden.
Variante 2
Private Sub UserForm_Initialize() Me.OptLinks.SetFocus Me.opt1.SetFocusEnd Sub
Private Sub cmdOk2_Click()Dim strAusrichtung1 As StringDim strAusrichtung2 As StringstrAusrichtung1 = Me.fraAusrichtung.ActiveControl.NamestrAusrichtung1 = Mid(strAusrichtung1, 4)
10.12 Lösungen
141
10 Dialoge
strAusrichtung2 = Me.fraFüllzeichen.ActiveControl.NamestrAusrichtung2 = Mid(strAusrichtung2, 4)
MsgBox strAusrichtung1 & " " _ & strAusrichtung2End Sub
Variante 3:
Private Sub cmdOk1_Click()Dim ctOptButton As ControlDim strAusgabe As String
For Each ctOptButton In Me.fraAusrichtung.Controls If ctOptButton.Value = True Then strAusgabe = Right(ctOptButton.Name, _ Len(ctOptButton.Name) – 3) End IfNext
For Each ctOptButton In Me.fraFüllzeichen.Controls If ctOptButton.Value = True Then strAusgabe = strAusgabe & Right(ctOptButton.Name, _ Len(ctOptButton.Name) – 3) End IfNext
MsgBox strAusgabe
End Sub
Variante 4:
Dim strAusrichtung As StringDim bytFüllzeichen As Byte
Private Sub UserForm_Initialize()strAusrichtung = "links "bytFüllzeichen = 1End Sub
Private Sub opt1_Click()bytFüllzeichen = 1End Sub
Private Sub opt2_Click()bytFüllzeichen = 2End Sub
Private Sub opt3_Click()
142
Lösungen
bytFüllzeichen = 3End Sub
Private Sub opt4_Click()bytFüllzeichen = 4End Sub
Private Sub optDezimal_Click()strAusrichtung = "dezimal "End Sub
Private Sub optLinks_Click()strAusrichtung = "links "End Sub
Private Sub optRechts_Click()strAusrichtung = "rechts "End Sub
Private Sub optVertikaleLinie_Click()strAusrichtung = "vertikale Linie "End Sub
Private Sub optZentriert_Click()strAusrichtung = "zentriert "End Sub
Private Sub cmdOk3_Click()MsgBox strAusrichtung & bytFüllzeichenEnd Sub
Lösung 2
Variante 1
Private Sub cmdOk1_Click()Dim strAusgabe As StringIf Me.chkAkzent.Value = True Then strAusgabe = "Akzent"End IfIf Me.chkAusschneiden.Value = True Then strAusgabe = strAusgabe & vbCr & "Ausschneiden"End IfIf Me.chkEinfügen.Value = True Then strAusgabe = strAusgabe & vbCr & "Einfügen"End IfIf Me.chkEingabe.Value = True Then strAusgabe = strAusgabe & vbCr & "Eingabe"
143
10 Dialoge
End IfIf Me.chkGroßbuchstaben.Value = True Then strAusgabe = strAusgabe & vbCr & "Großbuchstaben"End IfIf Me.chkTab.Value = True Then strAusgabe = strAusgabe & vbCr & "Tab"End IfIf Me.chkTextbearbeitung.Value = True Then strAusgabe = strAusgabe & vbCr & "Textbearbeitung"End IfIf Me.chkÜberschreiben.Value = True Then strAusgabe = strAusgabe & vbCr & "Überschreiben"End If
If strAusgabe = "" Then MsgBox "Es wurde nichts ausgewählt"Else MsgBox strAusgabeEnd If
End Sub
Variante 2:
Private Sub cmdOk2_Click()Dim ctKästchen As ControlDim strausgabe As String
For Each ctKästchen In Me.fraBearbeiten.Controls If ctKästchen.Value = True Then strausgabe = strausgabe & vbCr & _ Right(ctKästchen.Name, Len(ctKästchen.Name) – 3) End IfNext
If strausgabe = "" Then MsgBox "Es wurde nichts ausgewählt"Else MsgBox strausgabeEnd If
End Sub
In der Praxis ist diese Lösung sicherlich wenig brauchbar, da auf jedes Kontroll-kästchen anders reagiert werden muss.
Wenn auf ein Optionsfeld geklickt wird, dann ist dieses ausgewählt. Wird aufein Kontrollkästchen geklickt, dann ist es entweder ausgewählt oder nicht.
144
Lösungen
Würde man, wie in Beispiel 1 mit dem Klick-Ereignis und einer globalen Variab-len arbeiten, dann müsste man sehr umständlich bei jedem Klick-Ereignis prü-fen:
Variante 3
Private Sub chkAkzent_Click()If Me.chkAkzent.Value = True Then strAusgabe = "Akzent"Else strAusgabe = ""End IfEnd Sub
Variante 4:
Dim bytWert As BytePrivate Sub chkAkzent_Click()bytWert = bytWert Xor 1End Sub
Private Sub chkAusschneiden_Click()bytWert = bytWert Xor 2End Sub
Private Sub chkEinfügen_Click()bytWert = bytWert Xor 4End Sub
Private Sub chkEingabe_Click()bytWert = bytWert Xor 8End Sub[...]
Es wird nun überprüft:
Private Sub cmdOk3_Click()Dim strAusgabe As StringIf (bytWert Xor 1) < bytWert Then strAusgabe = "Akzent"End IfIf (bytWert Xor 2) < bytWert Then strAusgabe = strAusgabe & vbCr & "Ausschneiden"End IfIf (bytWert Xor 4) < bytWert Then strAusgabe = strAusgabe & vbCr & "Einfügen"End IfIf (bytWert Xor 8) < bytWert Then strAusgabe = strAusgabe & vbCr & "Eingabe"End If
145
10 Dialoge
If (bytWert Xor 16) < bytWert Then strAusgabe = strAusgabe & vbCr & "Großbuchstaben"End IfIf (bytWert Xor 32) < bytWert Then strAusgabe = strAusgabe & vbCr & "Tab"End IfIf (bytWert Xor 64) < bytWert Then strAusgabe = strAusgabe & vbCr & "Textbearbeitung"End IfIf (bytWert Xor 128) < bytWert Then strAusgabe = strAusgabe & vbCr & "Überschreiben"End If
If strAusgabe = "" Then MsgBox "Es wurde nichts ausgewählt"Else MsgBox strAusgabeEnd If
End Sub
Lösung 3
Variante 1:
Private Sub togUmschalt_Click()Me.txtBetrag.Value = ""End Sub
Variante 2:
Private Sub txtBetrag_Change()Me.togUmschalt.Value = FalseEnd Sub
Allerdings wird diese Prozedur beim Ereignis togUmschalt_Click auch schonaufgerufen. Damit erhält die Umschaltfläche die Funktion einer Befehlsschalt-fläche.
Lösung 4
Private Sub chkUnterschneidung_Click()If Me.chkUnterschneidung.Value = True Then Me.txtUnterschneidung.Value = 12 Me.txtUnterschneidung.SetFocusElse Me.txtUnterschneidung.Value = ""End IfEnd Sub
146
Lösungen
Oder etwas eleganter und übersichtlicher mit einer With-Anweisung:
Private Sub chkUnterschneidung_Click()With txtUnterschneidung If chkUnterschneidung.Value = True Then .Value = 12 .SetFocus Else .Value = "" End IfEnd WithEnd Sub
Lösung 5
Private Sub UserForm_Initialize()txtFormatvorlage.Enabled = TruetxtTrennzeichen.Enabled = TruetxtFormatvorlage.BackColor = &H8000000FtxtTrennzeichen.BackColor = &H8000000FlblFormatvorlage.ForeColor = &H80000011lblTrennzeichen.ForeColor = &H80000011End Sub
Und für das Ereignis Click wird folgende Prozedur benötigt:
Private Sub chkKapitelnummer_Click()txtFormatvorlage.Locked = Not txtFormatvorlage.LockedtxtTrennzeichen.Locked = txtFormatvorlage.LockedIf txtFormatvorlage.BackColor = &H80000009 Then txtFormatvorlage.BackColor = &H8000000F txtTrennzeichen.BackColor = &H8000000F lblFormatvorlage.ForeColor = &H80000011 lblTrennzeichen.ForeColor = &H80000011Else txtFormatvorlage.BackColor = &H80000009 txtTrennzeichen.BackColor = &H80000009 lblFormatvorlage.ForeColor = &H80000012 lblTrennzeichen.ForeColor = &H80000012End IfEnd Sub
Der sehr unübersichtliche Code kann mittels Konstanten anschaulicher darge-stellt werden:
Private Sub chkKapitelnummer_Click()Const weiß = &H80000009Const hellgrau = &H8000000FConst dunkelgrau = &H80000011Const schwarz = &H80000012
147
10 Dialoge
txtFormatvorlage.Locked = Not txtFormatvorlage.LockedtxtTrennzeichen.Locked = txtFormatvorlage.LockedIf txtFormatvorlage.BackColor = weiß Then txtFormatvorlage.BackColor = hellgrau txtTrennzeichen.BackColor = hellgrau lblFormatvorlage.ForeColor = dunkelgrau lblTrennzeichen.ForeColor = dunkelgrauElse txtFormatvorlage.BackColor = weiß txtTrennzeichen.BackColor = weiß lblFormatvorlage.ForeColor = schwarz lblTrennzeichen.ForeColor = schwarzEnd IfEnd Sub
Werden die Konstanten global deklariert, dann können sie auch für die Initiali-sierungsroutine verwendet werden. Die Farbkonstanten finden Sie in der Eigen-schaftenliste. Übrigens: Da die Farben weiß und hellgrau vom System als Fens-terhintergrund und als inaktiver Bereich festgelegt sind, benötigt man keineEnabled-Eigenschaft. Es genügt, lediglich die Farben umzuschalten. Und: stattweiß und schwarz könnten auch die Systemfarben vbWhite und vbBlack ver-wendet werden.
Lösung 6
Das Initialisieren:
Private Sub UserForm_Initialize()txtAnderesProgramm.Visible = FalseEnd Sub
Ein Klick auf ein Optionsfeld schaltet die Eigenschaft auf »True«:
Private Sub optAnderes_Click()txtAnderesProgramm.Visible = TrueMe.txtAnderesProgramm.SetFocusEnd Sub
Auf allen anderen Optionsfeldern muss diese Eigenschaft wieder zurückgesetztwerden:
Private Sub optExcel_Click()txtAnderesProgramm.Visible = FalseEnd Sub
Private Sub optPowerpoint_Click()txtAnderesProgramm.Visible = FalseEnd Sub
Private Sub optWord_Click()
148
Lösungen
txtAnderesProgramm.Visible = FalseEnd Sub
Bei sehr vielen Optionsfeldern könnte man diese Prozedur auch auslagern. Bei-spielsweise so:
Sub ProgrammEinAus()If optAnderes.Value = True Then txtAnderesProgramm.Visible = True txtAnderesProgramm.SetFocusElse txtAnderesProgramm.Visible = False txtAnderesProgramm.Value = ""End If
End Sub
Diese Routine wird von allen Optionsfeldern aufgerufen:
Private Sub optAnderes_Click()ProgrammEinAusEnd Sub
Private Sub optExcel_Click()ProgrammEinAusEnd Sub
Private Sub optPowerpoint_Click()ProgrammEinAusEnd Sub
Private Sub optWord_Click()ProgrammEinAusEnd Sub
Lösung 7
Variante 1:
Sub WerteTest()Dim intZeile As IntegerDim intSpalte As IntegerintZeile = Mid(Me.ActiveControl.Name, 4, 2)intSpalte = Mid(Me.ActiveControl.Name, 6, 2)Select Case intSchalter(intZeile)Case 2 If Me.ActiveControl.Value = True Then Me.ActiveControl.Value = False intWert(intZeile) = intWert(intZeile) + intSpalte MsgBox "Es wurden bereits zwei Kästchen angekreuzt!"
149
10 Dialoge
intSchalter(intZeile) = 2 Else intSchalter(intZeile) = 1 intWert(intZeile) = intWert(intZeile) – intSpalte End IfCase 1 If Me.ActiveControl.Value = True Then intSchalter(intZeile) = 2 If Abs(intWert(intZeile) – intSpalte) > 1 Then Me.ActiveControl.Value = False MsgBox "Dieses Kästchen kann nicht " & _ "angekreuzt werden!" intSchalter(intZeile) = 1 intWert(intZeile) = intWert(intZeile) + intSpalte Else intWert(intZeile) = intWert(intZeile) + intSpalte End If Else intSchalter(intZeile) = intSchalter(intZeile) – 1 intWert(intZeile) = intWert(intZeile) – intSpalte End IfCase 0 If Me.ActiveControl.Value = True Then intWert(intZeile) = intSpalte intSchalter(intZeile) = intSchalter(intZeile) + 1 Else intSchalter(intZeile) = intSchalter(intZeile) – 1 intWert(intZeile) = 0 End IfEnd Select
End Sub
Dabei werden global deklariert:
Option ExplicitDim intWert(1 To 6) As IntegerDim intSchalter(1 To 6) As Integer
Diese Prozedur wird von allen Kontrollkästchen aufgerufen:
Private Sub chk0101_Click()WerteTestEnd Sub
Private Sub chk0102_Click()WerteTestEnd Sub
150
Lösungen
Private Sub chk0103_Click()WerteTestEnd Sub[...]
Variante 2:
Sub WerteTest02()Dim intZeile As IntegerDim intSpalte As IntegerDim bytSchalter As ByteDim ctl As Control
fMeldungErfolgt = FalseintZeile = Mid(Me.fraGesamt.ActiveControl.Name, 4, 2)intSpalte = Mid(Me.fraGesamt.ActiveControl.Name, 6, 2)
For Each ctl In Me.fraGesamt.Controls If Left(ctl.Name, 3) = "chk" Then If Mid(ctl.Name, 4, 2) = intZeile Then If ctl.Value = True Then If bytSchalter = 2 Then Me.fraGesamt.ActiveControl.Value = False If fMeldungErfolgt = False Then MsgBox "Es wurden bereits zwei " & _ Kästchen angekreuzt!" fMeldungErfolgt = True End If Exit Sub ElseIf bytSchalter = 1 Then If Abs(Mid(ctl.Name, 6, 2) – intSpalte) > 1 Then Me.fraGesamt.ActiveControl.Value = False If fMeldungErfolgt = False Then MsgBox "Dieses Kästchen kann " & _ nicht angekreuzt werden!" fMeldungErfolgt = True End If Exit Sub Else bytSchalter = 2 End If Else bytSchalter = 1 End If End If End If End If
151
10 Dialoge
Next
End Sub
Diese Prozedur benötigt ebenfalls die Deklaration einer globalen VariablenfMeldungErfolgt. Sie dient dazu, dass nicht mehrmals ein Meldungsfenster an-gezeigt wird:
Dim fMeldungErfolgt As Boolean
Und schließlich kann auch diese Prozedur von mehreren Kontrollkästchen auf-gerufen werden:
Private Sub chk1201_Click()WerteTest02End Sub
Private Sub chk1202_Click()WerteTest02End Sub
Private Sub chk1203_Click()WerteTest02End Sub[...]
10.13 Kombinationsfeld und Listenfeld
Zusammenfassung der Eigenschaften des Kombinationsfelds (Combobox)und des Listenfelds (Listbox)
Tab. 10.11:Zusammenfassungder Eigenschaften
des Kombinations-felds und des Lis-
tenfelds
Kategorie Eigenschaft Beschreibung
Darstellung DropButtonStyle (nur bei Kombina-tionsfeld)
Darstellung des Pfeils des Kombinationsfelds
Style (nur bei Kom-binationsfeld)
Art, wie die Liste geöffnet wird
Daten BoundColumn, ... die Anzahl der gebundenen Datenfelder
ColumnCount die Anzahl der Spalten
ColumnHeads legt fest, ob es eine Überschriftszeile gibt.
ColumWidth Breite der Spalten
ControlSource Datenquelle, an die das Steuerelement gebun-den ist
ListRows (nur bei Kombinationsfeld)
die angezeigten Zeilen, wenn das Kombinations-feld geöffnet wird
152
Kombinationsfeld und Listenfeld
ListStyle zeigt den vollständigen Text zum Markieren an oder gibt vor dem Text Kästchen zum Ankreuzen.
ListWidth (nur bei Kombinationsfeld)
Breite der Zeilen
RowSource Datenquelle der Zeilen
Text ändert die ausgewählte Zeile in einem Kombina-tionsfeld-Steuerelement oder in einem Listen-feld-Steuerelement.
TextColumn gibt die Spalte in einem Kombinationsfeld-Steu-erelement oder Listenfeld-Steuerelement an, die in der Text-Eigenschaft gespeichert werden soll, wenn der Benutzer eine Zeile markiert.
TopIndex Bei diesem Wert beginnt die Zählung.
Verhalten MultiSelect legt fest, ob nur ein Eintrag oder mehrere ausge-wählt werden können. Bei der Option fmMulti-SelectMulti muss der Benutzer die (ª)- oder die (Strg)-Taste gedrückt halten, bei fmMultiSelect-Extended führt jeder weitere Mausklick zu einer Auswahl.
Eigenschaf-ten, die in VBA festge-legt werden
CurTargetX ruft die bevorzugte horizontale Position der Ein-fügemarke in einem Kombinationsfeld ab.
CurX gibt die aktuelle horizontale Position der Einfü-gemarke im Kombinationsfeld an.
Default legt die Standardbefehlsschaltfläche eines For-mulars fest.
SelectionMargin gibt an, ob der Benutzer eine Textzeile durch Kli-cken im Bereich links vom Text markieren kann.
SelLength die Anzahl der Zeichen, die in einem Textfeld oder im Textbereich eines Kombinationsfeldes ausgewählt sind.
SelStart bestimmt den Anfang des ausgewählten Textes oder die Position der Einfügemarke, wenn kein Text ausgewählt ist.
SelText gibt den ausgewählten Text eines Steuerele-ments zurück oder legt diesen fest.
List gibt die Listeneinträge zurück oder legt diese fest. Achtung: die Zählung beginnt bei 0!
ListCount gibt die Anzahl der Listeneinträge zurück.
ListIndex bezeichnet das momentan ausgewählte Ele-ment.
Kategorie Eigenschaft Beschreibung
153
10 Dialoge
Zusammenfassung der Methoden des Kombinationsfelds und des Listen-felds
Tab. 10.12:Zusammenfassungder Methoden desKombinationsfeldsund des Listenfelds
Zusammenfassung der Ereignisse des Kombinationsfelds und des Listen-felds
Tab. 10.13:Zusammenfassungder Ereignisse des
Kombinationsfeldsund des Listenfelds
Die Unterschiede zwischen Listenfeld und Kombinationsfeld sind gering: DasListenfeld ist immer geöffnet, das Kombinationsfeld wird vom Benutzer geöff-net. Im Listenfeld können mehrere Einträge ausgewählt werden (wird in der Ei-genschaft MultiSelect festgelegt), im Kombinationsfeld nur einer.
Übung 1
Füllen Sie ein Listenfeld.
Übung 2
Eine Befehlsschaltfläche fügt neue Einträge in das Listenfeld hinzu.
Übung 3
Eine Befehlsschaltfläche löscht alle Einträge eines Listenfelds.
Kategorie Eigenschaft Beschreibung
Add fügt einen neuen Eintrag hinzu.
Clear löscht alle Einträge.
RemoveItem löscht einen Eintrag.
Kategorie Ereignis Kategorie Ereignis
Start Enter Änderungen BeforeUpdateAfterUpdateDropButtonClick
Mausereignisse DblClickMouseDownMouseUpMouseMove
BeforeDragOverBeforeDropAndPaste
Tastenereignisse KeyDownKeyPressKeyUpChange
Sonstiges Error
Ende Exit
10.14 Übungen
154
Tipps
Übung 4
Eine Befehlsschaltfläche löscht den ausgewählten Eintrag eines Listenfelds.
Übung 5
Eine Befehlsschaltfläche zeigt an, welcher und der wievielte Eintrag einesListenfelds ausgewählt wurde.
Übung 6
Eine Umschaltfläche wechselt zwischen Einzel- und Mehrfachauswahl.
Übung 7
Ändern Sie den Code aus Übung 4 und 5, da nun mehrere Einträge ausgewähltwerden können.
Übung 8
Füllen Sie ein Kombinationsfeld mit zwei Spalten und lassen Sie beim Start derUserform den ersten Eintrag angezeigt.
Tipp zu Übung 1
Das Listenfeld und das Kombinationsfeld müssen beim Laden des Formulars ge-füllt werden.
Tipp zu Übung 2
Es kann der gleiche Befehl AddItem wie in Aufgabe 1 verwendet werden.
Tipp zu Übung 4 und 5
Mit dem Befehl ListeIndex = -1 kann überprüft werden, ob nichts ausgewähltwurde.
Tipp zu Übung 7
Die Anzeige kann durch eine Schleife geändert werden, indem alle markiertenEinträge (Selected = True) »eingesammelt« werden. Dabei kann der »alte«Code verwendet werden.
Das Löschen ist weitaus schwieriger. Hier kann nicht in einer Schleife hochge-zählt werden, da »zwischenzeitlich« einige Einträge nicht mehr existieren.Wenn beispielsweise der Benutzer den ersten und den letzten (ListIndex – 1)
10.15 Tipps
155
10 Dialoge
Eintrag auswählt, die Schleife löscht den ersten Eintrag, dann ist der letzte Ein-trag auf Position ListIndex – 2 gerutscht. Eine Lösungsmöglichkeit besteht da-rin, den Zähler rückwärts laufen zu lassen.
Tipp zu Übung 8
Hier muss mit einem Array gearbeitet werden, der an die Eigenschaft List derListbox übergeben wird.
Lösung 1
Private Sub UserForm_Initialize()With Me.lstOrte .AddItem "Berlin" .AddItem "Frankfurt" .AddItem "Leipzig" .AddItem "Köln" .AddItem "Hamburg" .AddItem "München"End WithEnd Sub
Lösung 2
Private Sub cmdNeu_Click()Me.lstOrte.AddItem "Entenhausen " & Me.lstOrte.ListCount + 1End Sub
Lösung 3
Private Sub cmdAlleLöschen_Click()Me.lstOrte.ClearEnd Sub
Lösung 4
Private Sub cmdEinerWeg_Click()If Me.lstOrte.ListIndex >= 0 Then Me.lstOrte.RemoveItem Me.lstOrte.ListIndexEnd IfEnd Sub
Lösung 5
Private Sub cmdAuswahlZeigen_Click()If Me.lstOrte.ListIndex = -1 Then
10.16 Lösungen
156
Lösungen
MsgBox "Es wurde nichts ausgewählt!"Else MsgBox "Es wurde Nr. " & Me.lstOrte.ListIndex + 1 & _ " ausgewählt: " & Me.lstOrte.ValueEnd IfEnd Sub
Wie schon in Aufgabe 4, wird überprüft, ob nichts ausgewählt wurde (ListeIn-dex = -1). Falls etwas ausgewählt wurde, dann kann die Nummer mit ListIn-dex, der Eintrag mit ListValue ausgegeben werden. Beides setzt voraus, dass inden Eigenschaften der TopIndex nicht verändert wurde. Falls dies nicht sicherist, dann muss statt
If Me.lstOrte.ListIndex = -1 Then
geschrieben werden:
If Me.lstOrte.ListIndex = Me.lstOrte.TopIndex Then
Lösung 6
Private Sub togUmschalt_Click()If Me.togUmschalt.Value = True Then Me.lstOrte.MultiSelect = fmMultiSelectSingle Me.togUmschalt.Caption = "Einfach"Else Me.lstOrte.MultiSelect = fmMultiSelectMulti Me.togUmschalt.Caption = "Mehrfach"End IfEnd Sub
Lösung 7
Private Sub cmdAuswahlZeigen_Click()Dim i As IntegerDim strAusgabeIf Me.lstOrte.MultiSelect = fmMultiSelectSingle Then
If Me.lstOrte.ListIndex = -1 Then MsgBox "Es wurde nichts ausgewählt!" Else MsgBox "Es wurde Nr. " & Me.lstOrte.ListIndex + 1 & _ " ausgewählt: " & Me.lstOrte.Value End IfElse For i = 0 To Me.lstOrte.ListCount – 1 If Me.lstOrte.Selected(i) = True Then strAusgabe = strAusgabe & vbCr & "Nr. " & _ (i +1) & ": " & Me.lstOrte.List(i) End If
157
10 Dialoge
Next
If strAusgabe = "" Then MsgBox "Es wurde nichts ausgewählt!" Else MsgBox "Es wurde(n) ausgewählt:" & strAusgabe End IfEnd IfEnd Sub
Und das Löschen:
Private Sub cmdEinerWeg_Click()Dim i As IntegerIf Me.lstOrte.MultiSelect = fmMultiSelectSingle Then
If Me.lstOrte.ListIndex >= 0 Then Me.lstOrte.RemoveItem Me.lstOrte.ListIndex End IfElse For i = Me.lstOrte.ListCount – 1 To 0 Step -1 If Me.lstOrte.Selected(i) = True Then Me.lstOrte.RemoveItem i End If NextEnd IfEnd Sub
Lösung 8
Private Sub UserForm_Initialize()Dim strLänder(1 To 6, 1 To 6) As StringstrLänder(1, 1) = "Deutschland": strLänder(1, 2) = "Berlin"strLänder(2, 1) = "Schweiz": strLänder(2, 2) = "Bern"strLänder(3, 1) = "Österreich": strLänder(3, 2) = "Wien"strLänder(4, 1) = "Frankreich": strLänder(4, 2) = "Paris"strLänder(5, 1) = "Italien": strLänder(5, 2) = "Rom"strLänder(6, 1) = "Niederlande": strLänder(6, 2) = "Den Haag"
Me.cmbListe.ColumnCount = 2Me.cmbListe.List = strLänderMe.cmbListe.ListIndex = 0
End Sub
158
Bildlaufleiste und Drehfeld
10.17 Bildlaufleiste und Drehfeld
Zusammenfassung der Eigenschaften der Bildlaufleiste (Scrollbar) und desDrehfelds (Spinbutton)
Tab. 10.14: Zusammenfassung der Eigenschaften der Bildlaufleiste und des Drehfelds
Die Ereignisse und Methoden unterschieden sich nicht von den Ereignissen an-derer Steuerelemente.
Bildlaufleiste und Drehfeld verwenden folgende Ereignisse:
Tab. 10.15: Zusammenfassung der Ereignisse der Bildlaufleiste und des Drehfelds
Wichtig beim Drehfeld und bei der Bildlaufleiste ist der Value. In ihm wird eininterner Wert gespeichert, der einen aktuellen Zustand bestimmt.
Kategorie Eigenschaft Beschreibung
Bildlauf Delay beeinflusst die Zeitdauer zwischen aufeinander fol-genden SpinUp-, SpinDown- und Change-Ereignissen, die ausgelöst werden, wenn der Benutzer auf ein Drehfeld-Steuerelement oder auf ein Bildlaufleiste-Steuerelement klickt und die Maustaste gedrückt hält. Das erste Ereignis wird sofort ausgelöst. Die Verzöge-rung bis zum zweiten Auftreten des Ereignisses ist fünfmal so groß, wie der für Delay angegebene Wert.
Max Maximalwert
Min Minimalwert
SmallChange gibt an, um welche Zahl weiter gezählt wird, wenn der Benutzer auf einen der beiden Pfeile klickt.
LargeChange (nur bei Bild-lauf)
gibt an, um welche Zahl weiter gezählt wird, wenn der Benutzer in die Bildlaufleiste klickt.
Darstellung Orientation Ausrichtung
Kategorie Ereignis Kategorie Ereignis
Start Enter Änderungen BeforeUpdateAfterUpdate
Mausereignisse SpinDownSpinUp (bei Drehfeld)Scroll (bei Bildlauf-leiste)
BeforeDragOverBeforeDropAnd-Paste
Tastenereignisse KeyDownKeyPressKeyUpChange
Sonstiges Error
Ende Exit
159
10 Dialoge
Übung 1
Neben einem Textfeld befindet sich ein Drehfeld. Im Textfeld steht die Zahl 10.Wird nun im Drehfeld der Pfeil nach oben angeklickt, so erhöht sich der Wertum 1, wird der Pfeil nach unten angeklickt, so verringert sich die Zahl um 1. Dieuntere Grenze liegt bei 1.
Übung 2
Über ein Drehfeld wird die Schriftgröße eines Bezeichnungsfeldes vergrößertund verkleinert.
Übung 3
In einem Formular befindet sich ein Rahmen. Neben dem Rahmen sitzen dreiBildlaufleisten (rot, grün und blau) über die man die Farbe (Backcolor) des Rah-mens einstellen kann.
Übung 4
Mit einer Bildlaufleiste wird ein Buchstabe von »A« bis »Z« »hochgezählt«.
Übung 5
Beim Starten einer Userform werden in einem Array mehrere Werte gespei-chert. Der Inhalt des ersten Werts wird in einem Textfeld angezeigt. Mit einerBildlaufleiste kann nun zwischen den anderen Werten gescrollt werden. Ände-rungen in den Textfeldern werden im Array gespeichert.
Tipp zu Übung 1 und 2
Wählen Sie das Maximum des Drehfelds groß genug, aber nicht zu groß!
Tipp zu Übung 3 und 4
Diese beiden Übungen sind nur Varianten. In Übung 3 wird die Funktion RGBverwendet, in Übung 4 wird mit Asc und Chr, mit denen die Zahl des Ascii-Codes ermittelt, beziehungsweise eine Zahl in einen Buchstaben verwandeltwird, gearbeitet.
10.18 Übungen
10.19 Tipps
160
Lösungen
Tipp zu Übung 5
Auch in diesem Beispiel wird erneut die Initialisierung der Userform verwendet.Darin werden die beiden Arrays für Vor- und Zuname gefüllt und in die beidenTextfelder eingetragen. Ein Ändern der Bildlaufleiste bewirkt ein Ändern des In-halts in der Variablen. Sollen die Werte zurückgeschrieben werden, dann mussauf das Ändern in den Textfeldern reagiert werden:
Lösung 1
Folgende Werte können beim Aktivieren der Userform oder in den Eigenschaf-ten eingetragen werden:
Private Sub UserForm_Activate()txtWert.Value = 10With spnWert .Value = 10 .Min = 1 .Max = 1000 .SmallChange = 1End WithEnd Sub
Wählen Sie dabei das Maximum des Drehfelds groß genug, aber nicht zu groß.Eine Änderung auf das Drehfeld bewirkt nun Folgendes:
Private Sub spnWert_Change()txtWert.Value = spnWert.ValueEnd Sub
Lösung 2
Auch in diesem Beispiel muss nicht mit den beiden Ereignissen SpinUp undSpinDown gearbeitet werden. Es genügt das Ereignis Change. Wie in Lösung 1werden die Eigenschaften auch hier beim Initialisieren festgelegt:
Private Sub UserForm_Activate()With spnSchriftgröße .Value = 8 .Min = 4 .Max = 200 .SmallChange = 1End WithEnd Sub
Private Sub spnSchriftgröße_Change()
10.20 Lösungen
161
10 Dialoge
lblKommentar.Font.Size = _ Me.spnSchriftgröße.ValueEnd Sub
Lösung 3
Beim Aktivieren wird eine Startfarbe festgelegt. Den drei Bildlaufleisten sind dieWerte Min = 0, Max = 255, SmallChange = 1 und LargeChange = 5 zugewiesen.
Private Sub UserForm_Activate()Me.fraBunt.BackColor = RGB(0, 0, 0)End Sub
Private Sub scrBlau_Change()Me.fraBunt.BackColor = _ RGB(scrRot.Value, scrGrün.Value, scrBlau.Value)End Sub
Private Sub scrGrün_Change()Me.fraBunt.BackColor = _ RGB(scrRot.Value, scrGrün.Value, scrBlau.Value)End Sub
Private Sub scrRot_Change()Me.fraBunt.BackColor = _ RGB(scrRot.Value, scrGrün.Value, scrBlau.Value)End Sub
Abbildung 10.8:Bei diesem Office-Dialog wurde mitDrehfeldern gear-
beitet.
162
Lösungen
Lösung 4
Private Sub UserForm_Activate()Me.txtBuchstabe.Value = "A"Me.txtBuchstabe.Enabled = FalseWith scrAlphabeth .Min = Asc("A") .Max = Asc("Z") .Value = .Min .SmallChange = 1 .LargeChange = 3End WithEnd Sub
Private Sub scrAlphabeth_Change()Me.txtBuchstabe.Value = Chr(Me.scrAlphabeth.Value)End Sub
Lösung 5
Option ExplicitDim strVorname(1 To 5) As StringDim strZuname(1 To 5) As String
Private Sub UserForm_Activate()strVorname(1) = "Anna": strZuname(1) = "Weiß"strVorname(2) = "Bert": strZuname(2) = "Schwarz"strVorname(3) = "Claudia": strZuname(3) = "Blau"strVorname(4) = "Dieter": strZuname(4) = "Gelb"strVorname(5) = "Erna": strZuname(5) = "Farblos"
With Me.scrListe .Min = 1 .Max = 5 .Value = 1 .SmallChange = 1 .LargeChange = 2End With
Me.txtVorname.Value = strVorname(1)Me.txtZuname.Value = strZuname(1)End Sub
Private Sub scrListe_Change()txtVorname.Value = strVorname(scrListe.Value)txtZuname.Value = strZuname(scrListe.Value)End Sub
Private Sub txtVorname_Change()
163
10 Dialoge
strVorname(scrListe.Value) = txtVorname.ValueEnd Sub
Private Sub txtZuname_Change()strZuname(scrListe.Value) = txtZuname.ValueEnd Sub
10.21 Register und MultiseitenEin zentraler Unterschied beim Einrichten von Register und Multiseiten findetsich zu den bisher besprochenen Steuerelementen. Bei ihnen kann das ganzeSteuerelement oder eines der Registerblätter ausgewählt werden. Nun findensich im Kontextmenü die Befehle, um eine Seite zu löschen, zu verschiebenoder hinzuzufügen. Die Beschriftung der »Tabs« kann ebenfalls über die rechteMaustaste oder über die Eigenschaft Caption verändert werden. Das gesamteSteuerelement stellt folgende, weitere Eigenschaften zur Verfügung:
Die Eigenschaften der Register und Multiseiten:
Tab. 10.16:Die Eigenschaften
der Register undMultiseiten
Zusammenfassung der Eigenschaften (der Objekte) der Register (Tabstrips)und Multiseiten (Pages):
Tab. 10.17:Zusammenfassungder Eigenschaften(der Objekte) der
Register und Multi-seiten
Kategorie Eigenschaft Beschreibung
Darstellung TabOrientation bestimmt die Lage der Tabs (oben, unten, links oder rechts).
Tabulatoren MultiRow ordnet mehrere Tabs untereinander an.
TabFixedHeight die exakte Höhe. Bei 0 wird die Standardhöhe ver-wendet.
TabFixedWidth die exakte Breite. Bei 0 wird die Standardbreite ver-wendet.
Objekt Eigenschaft Beschreibung
SelectedItem das ausgewählte Blatt
.Accelerator Alle Eigenschaften werden bei den Befehls-schaltflächen beschreiben.
.Caption
.ControlTipText
.Enabled
.Index
.Name
.Tag
164
Übungen
Register und Multiseiten verwenden folgende Ereignisse:
Tab. 10.18: Zusammenfassung der Ereignisse der Register und Multi-seiten
Der zentrale Unterschied zwischen diesen beiden Steuerelementen liegt in deneinzelnen Blättern. Bei den Mulitseiten ist jede Seite von den übrigen getrennt.Beim Register jedoch werden Steuerelemente, die auf einer Seite erzeugt wer-den, durch alle Seiten »gepaust«, das heißt, sie sind auf allen Seiten gleich. Nunkann mit dem Ereignis Change abgefangen werden, auf welches Blatt der Be-nutzer klickt.
Übung 1
Auf einem Multiseiten-Objekt, das aus verschiedenen Registern besteht, wer-den verschiedene Informationen zu einem Benutzer eingetragen. Auf allen Sei-ten befindet sich das Textfeld txtName. Dessen Inhalt soll auf allen Seiten ange-zeigt werden.
Übung 2
Erstellen Sie einen Datei-Neu-Dialog, wie er aus Word, Excel oder Powerpointbekannt ist.
.Visible
TabIndex die Position des ausgewählten Blatts
Objekt Eigenschaft Beschreibung
Kategorie Ereignis Kategorie Ereignis
Start Enter Positionsänderung ClickDblClickBeforeDragOverBeforeDropAndPaste
Mausereignisse MouseDownMouseMoveMouseUp
Fehler Error
Tastenereignisse KeyDownKeyPressKeyUpChange
Sonstiges (nur Mul-tiseiten)
LayoutAddControlRemoveControl
Änderung (nur Multi-seiten)
ScrollZoom
Ende Exit
10.22 Übungen
165
10 Dialoge
Tipp zu Übung 1
Achtung: Am besten verwendet man hier das Ereignis Change der Textfelder.Das Ereignis Exit erweist sich nicht als sinnvoll, denn ein Klicken auf ein anderesRegisterblatt bedeutet für die Steuerelemente der Dialoge in VBA noch kein»Verlassen«.
Tipp zu Übung 2
Auf einer Userform wird ein Register (tabDateiNeu) erzeugt, das einen Register-henkel besitzt, der mit »Allgemein« beschriftet ist. Auf ihm befindet sich ein Lis-tenfeld mit dem Namen lstDateiKatalog. Beim Öffnen wird die Listenbox ge-füllt.
Danach werden weitere Registerblätter hinzugefügt. Klickt der Benutzer nunauf ein anderes Blatt, dann wird überprüft, auf welchem Blatt er sich befindetund die Liste erneut gefüllt.
Lösung 1
Bei drei Textfeldern könnte dies wie folgt aussehen:
10.23 Tipps
10.24 Lösungen
166
Lösungen
Private Sub txtName1_Change()txtName2.Value = txtName1.ValuetxtName3.Value = txtName1.ValueEnd Sub
Private Sub txtName2_Change()txtName1.Value = txtName2.ValuetxtName3.Value = txtName2.ValueEnd Sub
Private Sub txtName3_Change()txtName1.Value = txtName3.ValuetxtName2.Value = txtName3.ValueEnd Sub
Lösung 2
Private Sub UserForm_Initialize()Dim intDateienZähler As IntegerDim strDateiName As StringDim strVorlagenPfad As String
On Error Resume Next
strVorlagenPfad = _ Application.Options.DefaultFilePath(wdUserTemplatesPath) strDateiEndung = "*.dot"
With Application.FileSearch .NewSearch .FileName = strDateiEndung .LookIn = strVorlagenPfad .SearchSubFolders = False .Execute
For intDateienZähler = 1 To .FoundFiles.Count If InStr(.FoundFiles(intDateienZähler), "~") = 0 Then lstDateiKatalog.AddItem _ Left(Right(.FoundFiles(intDateienZähler), _ Len(.FoundFiles(intDateienZähler)) – _ Len(strVorlagenPfad) – 1), _ Len(Right(.FoundFiles(intDateienZähler), _ Len(.FoundFiles(intDateienZähler)) – _ Len(strVorlagenPfad) – 1)) – 4) End If NextEnd With
End Sub
167
10 Dialoge
Nun sollen noch weitere Registerblätter hinzugefügt werden:
[...]strDateiName = Dir(strVorlagenPfad & "\", vbDirectory)Do While strDateiName <> "" If strDateiName <> "." And strDateiName <> ".." Then If (GetAttr(strVorlagenPfad & "\" & strDateiName) _ And vbDirectory) = vbDirectory Then Me.TabDateiNeu.Tabs.Add bstrcaption:=strDateiName End If End If strDateiName = DirLoop[...]
Klickt der Benutzer nun auf ein anderes Registerblatt, dann wird überprüft, aufwelchem Blatt er sich befindet und die Liste erneut gefüllt:
Private Sub TabDateiNeu_Change()Dim intDateienZähler As IntegerDim strVorlagenPfad As String
On Error Resume Next
Me.lstDateiKatalog.Clear
strVorlagenPfad = _ Application.Options.DefaultFilePath(wdUserTemplatesPath)
If Me.TabDateiNeu.SelectedItem.Caption <> "Allgemein" Then strVorlagenPfad = strVorlagenPfad & "\" & _ Me.TabDateiNeu.SelectedItem.CaptionEnd If
With Application.FileSearch .NewSearch .FileName = strDateiEndung .LookIn = strVorlagenPfad .SearchSubFolders = False .Execute
For intDateienZähler = 1 To .FoundFiles.Count If InStr(.FoundFiles(intDateienZähler), "~") = 0 Then lstDateiKatalog.AddItem _ Left(Right(.FoundFiles(intDateienZähler), _ Len(.FoundFiles(intDateienZähler)) – _ Len(strVorlagenPfad) – 1), _ Len(Right(.FoundFiles(intDateienZähler), _ Len(.FoundFiles(intDateienZähler)) – _
168
Steuerelemente zur Laufzeit erzeugen
Len(strVorlagenPfad) – 1)) – 4) End If NextEnd With
End Sub
Hinter der Ok-Schaltfläche verbirgt sich folgender Text:
Private Sub cmdOk_Click()Dim strVorlagenPfad As String
On Error Resume Next
strVorlagenPfad = _ Application.Options.DefaultFilePath(wdUserTemplatesPath)
Documents.Add Template:= _ strVorlagenPfad & "\" & _ Me.lstDateiKatalog.Value & _ Right(strDateiEndung, 4)
Unload Me
End Sub
Und bei Abbrechen natürlich:
Unload Me
10.25 Steuerelemente zur Laufzeit erzeugenBislang wurde die Dynamik in Dialogboxen dadurch erzeugt, dass Eigenschaf-ten von vorhandenen Steuerelementen geändert wurden. Zum Beispiel ändertein Klick auf eine Befehlsschaltfläche die Eigenschaft Größe (Height) der Dialog-box. Das führt dazu, dass ein größerer Teil angezeigt wird. Im Folgenden wirderläutert, wie ein Ereignis (zum Beispiel ein Klick auf eine Befehlsschaltfläche)nicht die Eigenschaft eines vorhandenen Objekts ändert, sondern ein neuesSteuerelement erzeugt. Das folgende Dialogblatt besteht neben zwei Beschrif-tungen und einem Textfeld aus drei Befehlsschaltflächen. Eine der Befehls-schaltfläche wird zur Laufzeit beschriftet:
Private Sub UserForm_Initialize()Me.cmdAnzeige.Caption = "Erweitern"End Sub
Beim Vergrößern der Userform werden neue Steuerelemente erzeugt. Das neueSteuerelement muss deklariert werden. Da mehrere Ereignisse darauf zugreifen,wird es vor der ersten Prozedur deklariert:
169
10 Dialoge
Dim NeuesSteuerelement As Control
Die neuen Kontrollkästchen (Chk1 – CHK5) besitzen folgende Eigenschaften:
Private Sub cmdAnzeige_Click()If Me.Height = 165 Then Me.Height = 265 Me.cmdAnzeige.Caption = "Reduzieren"
Set NeuesSteuerelement = Controls.Add("forms.checkbox.1") With NeuesSteuerelement .Left = 10 .Top = 180 .Width = 140 .Height = 15 End WithElse Me.Height = 165 Me.cmdAnzeige.Caption = "Erweitern"End If
End Sub
Statt des Namens des Dialogblatts muss Forms stehen; das zugehörige Objekt(die Eigenschaft) ist eine Textbox, die Anzahl ist 1.
Natürlich sollte dem Kontrollkästchen eine Beschriftung zugewiesen werden:
[...] .Caption = "Groß/Kleinschreibung" .Accelerator = "ß"[...]
Besser wäre es, dem neuen Objekt einen selbstdefinierten Namen zu geben.Also:
Set NeuesSteuerelement = Controls.Add("forms.Checkbox.1", _ "Chk1")
Über einen global deklarierten Zähler intZähler können weitere Steuerele-mente hinzugefügt werden:
Name High Left Top Width
Chk1 15 10 180 140
Chk2 15 10 200 140
Chk3 15 10 220 140
Chk4 15 10 240 140
Chk5 15 10 260 140
170
Steuerelemente zur Laufzeit erzeugen
Dim NeuesSteuerelement As ControlDim intZähler As Integer
Private Sub cmdAnzeige_Click()If Me.Height = 165 Then Me.Height = 325 Me.cmdAnzeige.Caption = "Reduzieren"
For intZähler = 1 To 5 Set NeuesSteuerelement = _ Controls.Add("forms.checkbox.1", "Chk" & intZähler)
With NeuesSteuerelement .Left = 10 .Top = 160 + Zähler * 20 .Width = 140 .Height = 15 Select Case intZähler Case 1 .Caption = "Groß/Kleinschreibung" .Accelerator = "ß" Case 2 .Caption = "Nur ganzes Wort suchen" .Accelerator = "N" Case 3 .Caption = "Mit Mustervergleich" .Accelerator = "M" Case 4 .Caption = "Ähnliche Schreibweise" .Accelerator = "h" Case 5 .Caption = "Alle Wortformen" .Accelerator = "f" End Select
End With
Next intZählerElse[...]
Die Anzahl der Steuerelemente auf dem Dialogblatt beträgt:
Controls.Count
Das Alternativereignis der Befehlsschaltfläche soll nun diese wieder löschen:
Else For intZähler = 1 To 5 Me.Controls.Remove "Chk" & intZähler
171
10 Dialoge
Next intZähler
MsgBox "Alle weg", vbCritical
Me.Height = 165 Me.cmdAnzeige.Caption = "Erweitern"End If
Das Meldungsfenster dient zum Unterbrechen des Codes, um zu zeigen, dassdie Steuerelemente wirklich gelöscht wurden. Und schließlich kann über eineSchaltfläche abgefragt werden, welche Kontrollkästchen angekreuzt wurden:
Private Sub cmdWeitersuchen_Click()Dim i As Integer
ausgabetext = ""
For i = 0 To Controls.Count – 1 If Left(Controls(i).Name, 3) = "Chk" Then If Controls(i).Value = True And Controls(i).Visible = _ True Then ausgabetext = ausgabetext & vbCr & _ Controls(i).Caption End If End IfNextIf ausgabetext = "" Then MsgBox "Es wurde nichts angeklickt"Else MsgBox "Folgende Kontrollkästchen sind angeklickt:" _ & vbCr & ausgabetextEnd IfEnd Sub
Übung 1
Beim Initialisieren einer Userform werden ihr zwei Textfelder, zwei Bezeich-nungsfelder und zwei Befehlsschaltflächen hinzugefügt.
Übung 2
Ein Muliseiten-Blatt besteht aus zwei Seiten. Auf der ersten Seite befinden sicheinige Steuerelemente. Klickt der Benutzer auf das zweite Blatt, dann werdeneinige Optionsfelder hinzugefügt. Eine Schaltfläche fragt nun die einzelnen Op-tionen ab.
10.26 Übungen
172
Tipps
Tipp zu Übung 1 und 2
Damit man einem Steuerelement ein Ereignis zuweisen kann, muss dieses glo-bal mit WithEvents deklariert werden. Beispielsweise so:
Dim WithEvents ctlOk As CommandButton
Die Namen der Steuerelemente werden so definiert. Und so können ihnen nundie bekannten Ereignisse hinzugefügt werden. Dabei ist zu beachten, dass aufandere Steuerelemente, die zu Beginn noch nicht existieren, nicht mit
Me.txtName.Value
zugegriffen werden kann, sondern nur mit:
Me.Controls("txtName").Value
Lösung 1
Im Ereignis Initialize der Userform werden Textfelder und Bezeichnungsfelderhinzugefügt. Dabei sollten die wichtigsten Eigenschaften gesetzt werden:
Private Sub UserForm_Initialize()Dim ctl As ControlSet ctl = Controls.Add("forms.textbox.1", "txtName", True)With ctl .Left = 10 .Top = 5 .Width = 100 .Height = 20End With
Set ctl = Controls.Add("forms.label.1", "lblName", True)With ctl .Left = 10 .Top = 30 .Caption = "Name" .Accelerator = "N"End With[…]
Damit man einem Steuerelement ein Ereignis zuweisen kann, muss dieses glo-bal mit WithEvents deklariert werden:
10.27 Tipps
10.28 Lösungen
173
10 Dialoge
Option ExplicitDim WithEvents ctlAbbrechen As CommandButtonDim WithEvents ctlOk As CommandButtonDim WithEvents ctlAlter As TextBox
Private Sub UserForm_Initialize()[...]Set ctlAlter = Controls.Add("forms.textbox.1", "txtAlter", True)With ctlAlter .Left = 10 .Top = 60 .Width = 100 .Height = 20End With
Set ctl = Controls.Add("forms.label.1", "lblAlter", True)With ctl .Left = 10 .Top = 85 .Caption = "Alter" .Accelerator = "A"End With
Set ctlAbbrechen = Controls.Add("forms.commandbutton.1", _ "cmdAbbrechen", True)With ctlAbbrechen .Left = 100 .Top = 120 .Caption = "Abbrechen" .Accelerator = "A" .Width = 60 .Height = 20 .Cancel = TrueEnd With
Set ctlOk = Controls.Add("forms.commandbutton.1", _ "cmdOk", True)With ctlOk .Left = 170 .Top = 120 .Caption = "Ok" .Accelerator = "O" .Width = 60 .Height = 20 .Default = TrueEnd With
End Sub
174
Lösungen
Die Namen der Steuerelemente sind definiert. Und so können ihnen nun die be-kannten Ereignisse hinzugefügt werden. Dabei ist zu beachten, dass auf andereSteuerelemente, die zu Beginn noch nicht existieren, nicht mit
Me.txtName.Value
zugegriffen werden kann, sondern nur mit:
Me.Controls("txtName").Value
Im Folgenden drei Ereignisse von drei der Steuerelemente:
Private Sub ctlAbbrechen_Click() EndEnd Sub
Private Sub ctlOk_Click() MsgBox Me.Controls("txtName").Value & _ " ist " & _ Me.Controls("txtAlter").Value & _ " Jahre alt."End Sub
Private Sub ctlAlter_KeyPress _ (ByVal KeyAscii As MSForms.ReturnInteger) If KeyAscii < Asc("0") Or KeyAscii > Asc("9") Then KeyAscii = 0 End IfEnd Sub
Lösung 2
Das Multiseiten-Objekt trägt den Namen MultiPage1. Es besitzt zwei Seiten mitden Namen pagAllgemein und pagWeitere. Im ersten Teil der Bedingung wirdgezeigt, wie ein Rahmen mit vier Optionsfeldern zur Laufzeit hinzugefügt wer-den. Im zweiten Teil werden diese Steuerelemente wieder gelöscht, wenn derBenutzer auf das erste Blatt klickt. Klickt der Benutzer auf eine Befehlsschaltflä-che, dann wird das ausgewählte Optionsfeld des zweiten Blatts angezeigt. Ach-tung: die Nummerierung der Blätter beginnt bei 0!
Private Sub MultiPage1_Change()Dim ctl As ControlIf Me.MultiPage1.SelectedItem.Name = "pagWeitere" Then
Set ctl = MultiPage1.Pages(1).Controls. _ Add("forms.frame.1", "fraGruppe", True)With ctl .Left = 10 .Top = 5 .Width = 100
175
10 Dialoge
.Height = 100End With
Set ctl = MultiPage1.Pages(1).Controls("fraGruppe"). _ Add("forms.optionbutton.1", "optStandard", True)With ctl .Left = 15 .Top = 10 .Caption = "Standard" .Value = TrueEnd With
Set ctl = MultiPage1.Pages(1).Controls("fraGruppe"). _ Add("forms.optionbutton.1", "optDaten1", True)With ctl .Left = 15 .Top = 30 .Caption = "Daten1" .Accelerator = "1"End With
Set ctl = MultiPage1.Pages(1).Controls("fraGruppe"). _ Add("forms.optionbutton.1", "optDaten2", True)With ctl .Left = 15 .Top = 50 .Caption = "Daten2" .Accelerator = "2"End With
Set ctl = MultiPage1.Pages(1).Controls ("fraGruppe"). _ Add("forms.optionbutton.1", "optDaten3", True)With ctl .Left = 15 .Top = 70 .Caption = "Daten3" .Accelerator = "3"End With
MultiPage1.Pages(1).Controls("optStandard").SetFocus
ElseIf Me.MultiPage1.SelectedItem.Name = "pagAllgemein" Then MultiPage1.Pages(1).Controls.ClearEnd IfEnd Sub
Private Sub cmdOk_Click()
176
Weitere Steuerelemente
If Me.MultiPage1.SelectedItem.Name = "pagWeitere" Then MsgBox MultiPage1.Pages(1).Controls _ ("fraGruppe").ActiveControl.NameEnd IfEnd Sub
10.29 Weitere SteuerelementeIm Menü EXTRAS / ZUSÄTZLICHE STEUERELEMENTE und im Kontextmenü derWerkzeugsammlung finden sich noch weitere Steuerelemente. Es würde denRahmen den Buches sprengen alle aufzulisten, die Microsoft mit seinem Office-Paket zur Verfügung stellt. Daneben können noch weitere Steuerelemente da-zugekauft werden. Exemplarisch sollen einige wenige hier Erwähnung finden.
Tab. 10.19: Weitere Steuer-elemente
Bildlaufleisten sind von der Installation der Programme bekannt:
Steuerelement Bedeutung
ImageList Dieses Steuerelement wird nicht angezeigt. Damit kann eine Liste von Abbildungen und Symbole erstellt werden, die von anderen Ele-menten genutzt wird.
ListView Eine Auswahlliste, die nicht nur Text, sondern auch Symbole an-zeigt.
TreeView Hierarchische Listen, die eine Baumstruktur darstellen
ProgressBar Fortschrittsanzeige. Zeigt den Ablauf eines Vorgangs visuell an. Zur Steuerung werden die Eigenschaften Min, Max und Value verwen-det.
Slider Alternative zur Bildlaufleiste
StatusBar Bindet eine Statuszeile in eine Userform ein.
ToolBar Bindet eine Symbolleiste in die Userform ein.
Abbildung 10.9: Eine bekannte Bild-laufleiste
177
Einige Objekte des Application-Objekts können von allen Programmen benutztwerden: Neben den Befehlsleisten, den Scripts und den Dokumenteigenschaf-ten gehören das FileSearch-Objekt, der Office-Assistent und das Steuern vonSymbolleisten, Menüpunkten und Tastenkombinationen dazu. Auch hier ist vonEinschränkungen auszugehen: Das FileSearch-Objekt muss in Visio getrennthinzugeladen werden. In Word werden Symbole, Tastenkombinationen undMenüpunkte an Dateien, das heißt an Dokumente und Dokumentvorlagen ge-bunden, während man so etwas in Excel programmieren muss. In Visio wie-derum gibt es eigene Befehle zur Steuerung von Menü- und Tastenkombinatio-nen.
11.1 Das FileSearch-Objekt
Angenommen, Sie möchten einen Dateimanager erstellen. Natürlich machtdies wenig Sinn, so etwas nachzubauen; aber an diesem Beispiel kann gut ge-zeigt werden, wie der Zugriff auf die Dateien funktioniert. Der Dialog hat fol-gende Gestalt:
11 Gemeinsam benutzte Elemente
Abbildung 11.1: Der bekannte Dia-log aus dem Menü DATEI / NEU
179
11 Gemeinsam benutzte Elemente
Aufgrund der großen Anzahl der gefunden Dateien empfiehlt sich ein Listen-feld. Die Endungen sollen dagegen in einer Combobox aufgelistet werden, dadiese vom Benutzer geändert werden kann, wenn er nach einem anderen Da-teityp sucht. Beim Starten des Dialogs wird die Combobox mit einigen Datei-endungen gefüllt, in das Textfeld wird der aktuelle Ordner hineingeschriebenund das Formular beschriftet:
Private Sub UserForm_Initialize() With Me.cmbTyp .AddItem "*.doc" .AddItem "*.xls" .AddItem "*.ppt" .AddItem "*.mdb" .AddItem "*.txt" .AddItem "*.htm" .AddItem "*.*" .ListIndex = 0 End With Me.txtSuche = CurDir Me.Caption = "Dateiensuche"End Sub
Wenn der Benutzer nun auf »Start« klickt, dann wird überprüft, ob das Feld, indem der Pfad steht, gefüllt ist:
If Len(Me.txtSuche.Value) = 0 Then MsgBox "Bitte geben Sie das Verzeichnis ein, in " & _ "dem gesucht werden soll." Me.txtSuche.SetFocus Exit SubEnd If
Der eingegebene Ordner wird überprüft:
If Right(Me.txtSuche.Value, 1) <> "\" Then txtSuche.Value = txtSuche.Value & "\" End If If Dir(txtSuche.Value) = "" Then MsgBox "Der angegebene Ordnername ist " & _ "nicht korrekt." Me.txtText.Text = CurDir Err.Clear Exit Sub End If
Dann wird überprüft, welcher der Optionsbuttons angeklickt wurde. Dabei wirddie Variable fUnterverzeichnis auf »True« oder »False« gesetzt, iSuchKrite-rium wird mit einem Wert gefüllt (1 bis 4), der hinter den Systemkonstantensteckt.
180
Das FileSearch-Objekt
If Me.optJa = True Then fUnterverzeichnis = True Else fUnterverzeichnis = False End If
If Me.optDatum = True Then iSuchkriterium = msoSortByLastModified ElseIf Me.optGröße = True Then iSuchkriterium = msoSortBySize ElseIf Me.optName = True Then iSuchkriterium = msoSortByFileName ElseIf Me.optTyp = True Then iSuchkriterium = msoSortByFileType End If
Schließlich kann die Dateisuche beginnen. Das Objekt Application verwendetdie Eigenschaft FileSearch. Sie enthält eine Reihe von Parametern:
.NewSearch startet die Suche von Neuem und verwendet nicht die älteren nochvorhandenen Eingaben.
.Filename trifft die Auswahl der Endungen. Dies wird über die Combobox über-geben.
.LookIn bezieht sich auf den Ordner, in dem gesucht wird. Dies wird aus demTextfeld ausgelesen.
Wird der Parameter .SearchSubFolders auf »True« gesetzt, dann werden dieUnterordner durchsucht. Die Dateien können auf Inhalt überprüft werden. Diesentspricht der Eigenschaft .TextOrProperty.
Mit der Methode Execute beginnt die Suche. Dabei können als Parameter ange-geben werden, ob nach Text, Datum, Größe oder Typ sortiert wird. Da nur dieDateinamen aufgelistet werden sollen, werden zwei als Array deklarierte Vari-able mit den Dateinamen gefüllt. Bei beiden muss die Größe redimensioniertwerden, da erst mit dem Befehl Execute bekannt ist, wie viele Dateien sich indem Ordner befinden (FoundFiles.Count), in dem gesucht wird. Die erste Vari-able wird zur Anzeige verwendet: Dort wird der Pfadname abgeschnitten. Diezweite Variable »merkt« sich den ganzen Pfad. Werden eine oder mehrere Da-teien gefunden, so werden sie angezeigt:
With Application.FileSearch .NewSearch .Filename = Me.cmbTyp .LookIn = Me.txtSuche .SearchSubFolders = fUnterverzeichnis If Me.txtText <> "" Then .TextOrProperty = Me.txtText End If
181
11 Gemeinsam benutzte Elemente
If .Execute(SortBy:=iSuchkriterium, _ sortorder:=msoSortOrderAscending, _ AlwaysAccurate:=True) > 0 Then ReDim strZugehOrdner(.FoundFiles.Count) ReDim strDateien(.FoundFiles.Count)
For i = 1 To .FoundFiles.Count strDateien(i) = .FoundFiles(i) strZugehOrdner(i) = .FoundFiles(i)
Do strDateien(i) = Right(strDateien(i), _ (Len(strDateien(i)) – InStr(strDateien(i), _ "\"))) Loop While InStr(strDateien(i), "\") > 0
Me.lstDateien.AddItem strDateien(i) Next i
Else Me.lstDateien.AddItem _ "Keine Entsprechungen gefunden!" End If
End With
Abbildung 11.2:Der eigene Datei-
manager
182
Übung
Um nun auf den vollständigen Dateinamen zuzugreifen, wird die VariablestrZugehOrdner verwendet. Dies soll gezeigt werden am Beispiel eines Klicksauf einen Dateinamen: Dann wird der ganze Dateiname in der Titelzeile ange-zeigt:
Private Sub lstDateien_Click()Me.Caption = strZugehOrdner(Me.lstDateien.ListIndex + 1)End Sub
Übung
Zählen Sie die vorhanden Dateien im Ordner C:\Rechnungen und generieren Siedaraus eine neue Rechnungsnummer.
Lösung
Sub NeueRechnungsnummer()With Application.FileSearch .NewSearch .Filename = "*.*" .LookIn = "C:\Rechnungen" .SearchSubFolders = False .ExecuteMsgBox "Neue Nummer: " & Year(Date) * 100 + .FoundFiles.CountEnd WithEnd Sub
11.4 Der Assistent und das Balloon-ObjektDiese beiden Funktionen stehen sicherlich nicht im Zentrum der Office-Pro-grammierung. Viele Benutzer schalten sie genervt aus, viele Firmen löschen dieentsprechenden »*.act«-Dateien von den Rechnern der Anwender. Deshalb sollihnen lediglich ein Beispiel gewidmet werden. Wer sich für die Assistenten inte-ressiert, der möge in weiterführender Literatur oder in der Hilfe mehr darübernachlesen.
11.2 Übung
11.3 Lösung
183
11 Gemeinsam benutzte Elemente
An ein Ereignis wird der Assistent gebunden. Die verschiedenen Typen liegenauf der Festplatte und können über die Endung »*.act« gesucht werden. KarlKlammer trägt den Namen Clippit.act. Der Dateiname wird an die Eigen-schaft Filename des Assistant-Objekts gebunden. Ebenso muss Visible auf»True« gesetzt werden.
Dem Assistenten kann eine Sprechblase zugewiesen werden. Jede dieserSprechblasen hat verschiedene Animationen. Zusätzlich kann in der linken obe-ren Ecke ein Icon eingefügt werden. Im folgenden Beispiel stellt msoIconTipeine Glühlampe dar. In der Titelzeile (Heading) kann ein Text und – optional –eine Grafik stehen. Der Name der Grafikdatei steht in geschweiften Klammern,wobei am Anfang der Typ (»wmf«) angegeben wird. Nun folgt Text. In einerAufzählung darunter, die bis zu fünf Punkten beinhalten kann, werden Dingeerläutert. Für die Gestaltung stehen die Eigenschaften msoBalloonTypeButtons,msoBalloonTypeBullets und msoBalloonTypeNumbers zur Verfügung. Undschließlich können (analog zum Meldungsfenster) verschiedene Auswahlmög-lichkeiten zur Verfügung gestellt werden (msoButtonSetOk, msoButtonSetCan-cel, msoButtonSetYesNo, msoButtonSetAbortRetryIgnore, ...) diese können ab-gefangen werden. Und hier der Code des Assistenten:
Sub Assistent()Dim balSprechblase As Balloon
Assistant.Filename = "D:\office2000\Office\Clippit.act"Assistant.Visible = True
Set balSprechblase = Assistant.NewBalloonWith balSprechblase .Animation = msoAnimationListensToComputer .Icon = msoIconTip .Heading = "Lehrer Lämpel"
.Text = """Ach"" – spricht er – ""Die größte Freud" & _ vbCr & "Ist doch die Zufriedenheit.""" .BalloonType = msoBalloonTypeButtons .Labels(1).Text = "Rums!! Da geht die Pfeife los" .Labels(2).Text = "Mit Getöse, schrecklich groß." .Labels(3).Text = "Kaffeetopf und Wasserglas," .Labels(4).Text = "Tobakdose, Tintenfass," .Labels(5).Text = "Alles fliegt im Pulverblitz." .Button = msoButtonSetYesNo
.ShowEnd With
End Sub
184
Symbolleisten, Menüleisten und Tastenkombinationen
11.5 Symbolleisten, Menüleisten und Tastenkombinationen
Das Objekt, mit dem auf alle Symbolleisten zugegriffen werden kann, heißtCommandbars. Es handelt sich dabei um eine Sammlung. Folgendes Makrodurchläuft alle Symbolleisten und listet sie namentlich auf:
Sub AlleSymbolLeisten()Dim i As IntegerDim strSymbLeiste As StringFor i = 1 To Application.CommandBars.Count strSymbLeiste = strSymbLeiste & ", " & CommandBars(i).NameNextMsgBox strSymbLeisteEnd Sub
Jede einzelne Symbolleiste hat eine Reihe Eigenschaften. Mit Visible kannüberprüft werden, ob die Symbolleiste sichtbar ist:
Sub AlleSichtbarenSymbolLeisten()Dim i As IntegerDim strSymbLeiste As StringFor i = 1 To Application.CommandBars.Count If CommandBars(i).Visible = True Then
Abbildung 11.3: Ein Beispiel für den Assistenten
185
11 Gemeinsam benutzte Elemente
strSymbLeiste = strSymbLeiste & ", " & _ CommandBars(i).Name End IfNextMsgBox strSymbLeisteEnd Sub
Daraus wird erkennbar, dass auch die Menüleiste eine Sonderform der Symbol-leiste ist. Sie trägt in Word den Namen »MenuBar«, in Excel heißt sie »Work-sheet Menu Bar«. Mit VBA können Sie auf die Symbolleisten über deren engli-sche Bezeichnungen zugreifen. Jede Symbolleiste hat einen Type: DieMenüleiste ist vom Typ msoBarTypeMenuBar, die übrigen besitzen die EigenschaftmsoBarTypeNormal. Daneben steht noch der Typ msoBarTypePopUp zur Verfü-gung.
Jede Symbolleiste hat Symbole (Controls). Auch sie können durchlaufen wer-den:
Sub AlleSymbole()Dim intZähler As IntegerDim strSymbole As StringWith Application.CommandBars("Formatting") For intZähler = 1 To .Controls.Count strSymbole = strSymbole & vbCr & _ .Controls(intZähler).Caption NextEnd WithMsgBox strSymboleEnd Sub
Analog kann die Menüleiste durchlaufen und alle Menüeinträge angezeigt wer-den:
With Application.CommandBars("Menu Bar")[...]
Auch die Symbole haben verschiedene Präfigurationen. Sie können über die Ei-genschaft »Type« abgefragt werden:
strSymbole = strSymbole & vbCr & .Controls(intZähler).Type _ & vbTab & .Controls(intZähler).Caption
Folgende Symbolarten stehen Ihnen zur Verfügung:
Tab. 11.1:Die verschiedenen
Symbolarten derSymbolleiste
Typ Wert
msoControlActiveX 22
msoControlButton 1
msoControlButtonDropDown 5
msoControlButtonPopup 12
186
Symbolleisten, Menüleisten und Tastenkombinationen
Und ebenso können auch alle Menüeinträge durchlaufen werden:
Sub AlleMenüPunkte()Dim intZähler As IntegerDim strMenüs As StringWith Application.CommandBars("Menu Bar").Controls("E&xtras") For intZähler = 1 To .Controls.Count strMenüs = strMenüs & vbCr & _ .Controls(intZähler).Caption NextEnd WithMsgBox strMenüsEnd Sub
Da manche Menüs weitere Untereinträge besitzen, können auch diese mittelseiner Schleife durchlaufen werden. Das folgende Beispiel zeigt alle Menüein-träge im (Word-)Menü EXTRAS / SPRACHE an:
Sub MenüExtrasSprache()Dim intZähler As IntegerDim strMenüs As String
msoControlComboBox 4
msoControlCustom 0
msoControlDropdown 3
msoControlEdit 2
msoControlExpandingGrid 16
msoControlGauge 19
msoControlGenericDropdown 8
msoControlGraphicCombo 20
msoControlGraphicDropdown 9
msoControlGraphicPopup 11
msoControlGrid 18
msoControlLabel 15
msoControlOCXDropdown 7
msoControlPane 21
msoControlPopup 10
msoControlSplitButtonMRUPopup 14
msoControlSplitButtonPopup 13
msoControlSplitDropdown 6
msoControlSplitExpandingGrid 17
Typ Wert
187
11 Gemeinsam benutzte Elemente
With Application.CommandBars _ ("Menu Bar").Controls("E&xtras").Controls("&Sprache") For intZähler = 1 To .Controls.Count strMenüs = strMenüs & vbCr & _ .Controls(intZähler).Caption NextEnd WithMsgBox strMenüs
End Sub
Im folgenden Beispiel wird eine vorhandene Symbolleiste am unteren Rand derAnwendung angezeigt:
With CommandBars("Drawing")
.Visible = True
.Position = msoBarBottom
End With
Oder sie wird ein- oder ausgeschaltet:
With CommandBars("Drawing") .Visible = Not (.Visible) .Position = msoBarBottomEnd With
Wichtiger als das Durchlaufen vorhandener Menüeinträge und Symbole ist dasErzeugen und das Löschen von neuen Menüs und Symbolen. Das folgende Bei-spiel erzeugt einen neuen Menüpunkt und fügt zwei Menüeinträge hinzu.
Sub NeuesMenü()Dim mnuMenü As CommandBarDim mnuMenüeintrag As CommandBarControlDim mnuMenüPunkt As CommandBarControl
Set mnuMenü = Application.CommandBars.ActiveMenuBarSet mnuMenüeintrag = mnuMenü.Controls.Add _ (Type:=10, temporary:=True)With mnuMenüeintrag .Caption = "&Datenbank" .Enabled = True .Visible = True .DescriptionText = "Datenbank"End WithSet mnuMenüPunkt = mnuMenüeintrag.Controls.Add(Type:=1)With mnuMenüPunkt .Caption = "&Datenbankexport" .Enabled = True
188
Symbolleisten, Menüleisten und Tastenkombinationen
.Visible = True .OnAction = "Datenbankexport"End With
Set mnuMenüPunkt = mnuMenüeintrag.Controls.Add(Type:=1)With mnuMenüPunkt .Caption = "&Datenbank&import" .Enabled = True .Visible = True .OnAction = "Datenbankimport"End With
End Sub
Und schließlich kann der Menüpunkt wieder gelöscht werden:
Sub MenüDatenbankLöschen()Application.CommandBars.ActiveMenuBar.Controls _ ("&Datenbank").DeleteEnd Sub
Das folgende Beispiel erzeugt eine neue Symbolleiste und fügt ihr drei Symbolehinzu:
Sub MeineNeuenSymbis()Dim mnuSymbLeiste As CommandBarDim mnuSymbol As CommandBarControl
Set mnuSymbLeiste = Application.CommandBars.AddWith mnuSymbLeiste .Name = "Meine Symbole" .Position = msoBarFloating .Visible = TrueEnd With
Set mnuSymbol = mnuSymbLeiste.Controls.Add(Type:=1, ID:=26, _ temporary:=True)With mnuSymbol .Caption = "Icon1" .DescriptionText = "Mein erstes Icon" .TooltipText = "Mein erstes Icon" .OnAction = "MeinMakro" .Visible = True .Enabled = TrueEnd With
Set mnuSymbol = mnuSymbLeiste.Controls.Add(Type:=1, ID:=30, _ temporary:=True)
189
11 Gemeinsam benutzte Elemente
With mnuSymbol .Caption = "Icon2" .DescriptionText = "Mein zweites Icon" .TooltipText = "Mein zweites Icon" .OnAction = "MeinMakro2" .Visible = True .Enabled = True .BeginGroup = TrueEnd With
Set mnuSymbol = mnuSymbLeiste.Controls.Add(Type:=1, ID:=24, _ temporary:=True)With mnuSymbol .Caption = "Icon3" .DescriptionText = "Mein drittes Icon" .TooltipText = "Mein drittes Icon" .OnAction = "MeinMakro3" .Visible = True .Enabled = TrueEnd With
End Sub
Dieses Beispiel wurde deshalb so ausführlich ausgeschrieben, um einige der Ei-genschaften (Visible, Enabled, BeginGroup und OnAction) zu zeigen. Die Eigen-schaft OnAction ist besonders wichtig, da mit ihr dem Symbol ein Makro zuge-wiesen wird.
Das folgende Makro löscht alle Symbole von der (oben erzeugten) Symbolleisteund schließlich die Symbolleiste selbst:
Sub MeineNeuenSymbisWerdenGelöscht()Dim mnuSymbLeiste As CommandBarDim i As IntegerSet mnuSymbLeiste = Application.CommandBars("Meine Symbole")For i = mnuSymbLeiste.Controls.Count To 1 Step -1 mnuSymbLeiste.Controls(i).DeleteNext
mnuSymbLeiste.Delete
End Sub
Oder, etwas eleganter, auf folgende Weise:
Sub MeineNeuenSymbisWerdenGelöscht()Dim mnuSymbLeiste As CommandBarDim ctlSymbol As CommandBarControlSet mnuSymbLeiste = Application.CommandBars("Meine Symbole")
190
Übungen
For Each ctlSymbol In mnuSymbLeiste.Controls ctlSymbol.DeleteNext
mnuSymbLeiste.Delete
Das Löschen der einzelnen Symbole ist selbstverständlich überflüssig. An dieserStelle sollte lediglich die Methode gezeigt werden.
Übung 1
Jedem vorhandenen Symbol ist eine ID zugeordnet. Aber nicht hinter jeder Zahlsteckt ein Symbol. Lassen Sie sich per Programmierung eine neue Symbolleistegenerieren, die für die Werte zwischen 1 und 200 neue Symbole erzeugt. Las-sen Sie die Werte im »ToolTip-Text« anzeigen.
Übung 2, 3 und 4
In Excel werden für Symbole drei (vier) Makros benötigt. Das erste Makro über-prüft, ob ein Symbol mit dem Namen »Abrechnung« vorhanden ist. Falls ja, sowird es sichtbar gemacht, falls nein, so wird es erzeugt.
Wechselt der Benutzer nun in eine andere Datei, dann wird dieses Symbol un-sichtbar geschaltet.
Wechselt der Benutzer zurück in seine Datei, so wird wie beim Start überprüft,ob das Symbol existiert. Entweder wird es sichtbar gemacht oder erzeugt.
Beendet der Benutzer seine Datei, dann wird das Symbol gelöscht.
Übung 5, 6, 7 und 8
Beim Öffnen einer Datei wird am Ende des Menüs EXTRAS der Menüpunkt»Shape« eingefügt, falls er noch nicht vorhanden ist. Falls ein Zeichnungsobjektinnerhalb der Applikation markiert ist, dann wird ein Makro aufgerufen, wel-ches diesen Menüpunkt aktiviert. Falls die Markierung aufgelöst wird, dannwird der Menüpunkt deaktiviert. Wird die Datei geschlossen, dann wird derMenüpunkt gelöscht. Schreiben Sie diese vier Makros.
11.6 Übungen
191
11 Gemeinsam benutzte Elemente
Tipp zu Übung 2 bis 4
Die drei Makros sind sehr ähnlich aufgebaut. Alle drei überprüfen eine be-stimmte Symbolleiste, ob das spezielle Symbol schon (noch) vorhanden ist. Fallsdies der Fall ist, wird es sichtbar oder unsichtbar gemacht oder ganz gelöscht.Im ersten Makro SymbAbrechnungSymbolErzeugen wird es bei Nichtexistenz er-zeugt. Der Zähler (intZähler) läuft dabei von der letzten bis zur ersten Zahl. DerGrund: Das Symbol wird am rechten Rand der Symbolleiste Standard erzeugt.Also werden die Symbole von rechts nach links überprüft, damit die Schleifenicht unnötig viele Durchläufe haben muss.
Lösung 1
Sub VieleSymbole()Dim mnuSymbLeiste As CommandBarDim mnuSymbol As CommandBarButtonOn Error Resume NextSet mnuSymbLeiste = Application.CommandBars.AddWith mnuSymbLeiste .Name = "Neue Symbole" .Position = msoBarFloating .Visible = TrueEnd WithFor intZähler = 1 To 200 Set mnuSymbol = mnuSymbLeiste.Controls.Add(ID:=intZähler) If Err.Number = 0 Then mnuSymbol.TooltipText = intZähler End If Err.ClearNextEnd Sub
Würde man auf die Verzweigung verzichten, bei der die Err.Number überprüftwird, dann würde dem jeweils letzten Symbol die jeweils höchste mögliche Zahlvor dem nächsten Symbol zugewiesen werden, was falsch ist. Beispiel: Wenndie Symbole mit der Nummer 51, 52 und 59 existieren, dann wird dem erstenSymbol die Nummer 51 zugewiesen. Dem zweiten Symbol nacheinander dieNummern 52, 53, 54, ... und schließlich 58. Dann wird für 59 ein neues Symbolgeneriert.
11.7 Tipps
11.8 Lösungen
192
Lösungen
Lösung 2
Sub SymbAbrechnungSymbolErzeugen()Dim mnuSymbLeiste As CommandBarDim mnuSymbol As CommandBarButtonDim intZähler As IntegerDim intSymbAnzahl As Integer
Set mnuSymbLeiste = Application.CommandBars("Standard")intSymbAnzahl = mnuSymbLeiste.Controls.CountFor intZähler = intSymbAnzahl To 1 If mnuSymbLeiste.Controls(intZähler).Caption = _ "Abrechnung" Then mnuSymbLeiste.Controls(intZähler).Visible = True Exit Sub End IfNext
Set mnuSymbol = mnuSymbLeiste.Controls.Add(ID:=127, _ Before:=intZähler, temporary:=True)mnuSymbol.DescriptionText = "Abrechnung"mnuSymbol.Caption = "Abrechnung"mnuSymbol.TooltipText = "Abrechnung"
End Sub
Lösung 3
Sub SymbAbrechnungSymbolUnsichtbar()Dim mnuSymbLeiste As CommandBarDim mnuSymbol As CommandBarButtonDim intZähler As IntegerDim intSymbAnzahl As Integer
Set mnuSymbLeiste = Application.CommandBars("Standard")intSymbAnzahl = mnuSymbLeiste.Controls.CountFor intZähler = intSymbAnzahl To 1 Step -1 If mnuSymbLeiste.Controls(intZähler).Caption = _ "Abrechnung" Then mnuSymbLeiste.Controls(intZähler).Visible = False Exit Sub End IfNext
End Sub
193
11 Gemeinsam benutzte Elemente
Lösung 4
Sub SymbAbrechnungSymbolLöschen()Dim mnuSymbLeiste As CommandBarDim mnuSymbol As CommandBarButtonDim intZähler As IntegerDim intSymbAnzahl As Integer
Set mnuSymbLeiste = Application.CommandBars("Standard")intSymbAnzahl = mnuSymbLeiste.Controls.CountFor intZähler = intSymbAnzahl To 1 Step -1 If mnuSymbLeiste.Controls(intZähler).Caption = _ "Abrechnung" Then mnuSymbLeiste.Controls(intZähler).Delete Exit Sub End IfNext
End Sub
Lösung 5
Sub ShapeInMenüEinbauen()Dim mnuMenü As CommandBarDim mnuMenüEintrag As CommandBarControlDim mnuMenüShape As CommandBarControlDim mnuMenüExtras As CommandBarControl
Set mnuMenü = Application.CommandBars.ActiveMenuBarSet mnuMenüExtras = mnuMenü.Controls("E&xtras")For Each mnuMenüEintrag In mnuMenüExtras.Controls If mnuMenüEintrag.Caption = "Sha&pe" Then mnuMenüEintrag.Visible = True Exit Sub End IfNext
Set mnuMenüShape = mnuMenüExtras.Controls.AddWith mnuMenüShape .Caption = "Sha&pe"
.OnAction = "ShapeFormat"End With
End Sub
194
Lösungen
Lösung 6
Sub MenüShapesLöschen()Dim mnuMenü As CommandBarDim mnuMenüEintrag As CommandBarControlDim mnuMenüShape As CommandBarControlDim mnuMenüExtras As CommandBarControl
Set mnuMenü = Application.CommandBars.ActiveMenuBarSet mnuMenüExtras = mnuMenü.Controls("E&xtras")For Each mnuMenüEintrag In mnuMenüExtras.Controls If mnuMenüEintrag.Caption = "Sha&pe" Then mnuMenüEintrag.Delete Exit Sub End IfNext
End Sub
Lösung 7 und 8
Die beiden entscheidenden Zeilen lauten:
mnuMenüEintrag.Enabled = False mnuMenüEintrag.Enabled = True
Sie werden eingebunden in zwei Makros, die auf das Ereignis »MarkiereShape« reagieren. Dazu wird in einer AutoStart-Routine auf eine Klasse zugrif-fen:
Dim K As New clsEreignissePrivate Sub Document_Open()Set K.wdapp = Word.ApplicationEnd Sub
In dieser Klasse kann nun ein Ereignis definiert werden, das gestartet wird,wenn eine Autoform markiert wird:
Public WithEvents wdapp As ApplicationPrivate Sub wdapp_WindowSelectionChange _ (ByVal Sel As Selection)If Sel.Type = wdSelectionShape Then Call MenüAktivElse Call MenüInaktivEnd IfEnd Sub
In Visio wird das Ereignis »Shape markieren« leichter abgefangen – allerdingslauten dort die Befehle zum Deaktivieren eines Menüpunkts völlig anders. Hiernun zwei Makros, die diese Funktion erfüllen:
195
11 Gemeinsam benutzte Elemente
Sub MenüInaktiv()Dim mnuMenü As CommandBarDim mnuMenüEintrag As CommandBarControlDim mnuMenüShape As CommandBarControlDim mnuMenüExtras As CommandBarControl
Set mnuMenü = Application.CommandBars.ActiveMenuBarSet mnuMenüExtras = mnuMenü.Controls("E&xtras")For Each mnuMenüEintrag In mnuMenüExtras.Controls If mnuMenüEintrag.Caption = "Sha&pe" Then mnuMenüEintrag.Enabled = False Exit Sub End IfNext
End Sub
Sub MenüAktiv()Dim mnuMenü As CommandBarDim mnuMenüEintrag As CommandBarControlDim mnuMenüShape As CommandBarControlDim mnuMenüExtras As CommandBarControl
Set mnuMenü = Application.CommandBars.ActiveMenuBarSet mnuMenüExtras = mnuMenü.Controls("E&xtras")For Each mnuMenüEintrag In mnuMenüExtras.Controls If mnuMenüEintrag.Caption = "Sha&pe" Then mnuMenüEintrag.Enabled = True Exit Sub End IfNext
End Sub
196
Ein wichtiges Element, mmit dem man den Code ermitteln kann, mit dem aufWord zugegriffen wird, ist der Makrorekorder. Mit seiner Hilfe können die meis-ten Word-Befehle aufgezeichnet werden.
12.1 DateizugriffOberstes Objekt, das heißt Word selbst, heißt Application. Die Schreibung istoptional. Es ist also gleichgültig, ob Sie
Application.ActiveWindow.View.ShowAll = True
oder
ActiveWindow.View.ShowAll = True
schreiben, um sich in Word die Formatierungszeichen anzeigen zu lassen.
Eine neue Vorlage wird mit dem Befehl
Documents.Add(Template, NewTemplate, DocumentType, Visible)
oder mit:
12 Word VBA
Abbildung 12.1: Der Makrorekorder
197
12 Word VBA
Application.Documents.Add _ (Template, NewTemplate, DocumentType, Visible)
hergeholt. Eine vorhandene Datei wird folgendermaßen geöffnet:
Documents.Open(FileName, ConfirmConversions, ReadOnly, _AddToRecentFiles, PasswordDocument, PasswordTemplate, _Revert, WritePasswordDocument, WritePasswordTemplate, _Format, Encoding, Visible)
Dabei bedeuten:
Tab. 12.1:Die Parameter vonDocuments.Open
Alle geöffneten Dokumente können mit der Sammlung Documents durchlaufenwerden. Dabei gibt die Eigenschaft Count die Anzahl der offenen Dateien an.Das Objekt Window und Document sind dabei identisch, so lange eine Datei nureinem einzigen Fenster geöffnet wurde. Ist dies nicht der Fall, dann muss dieSammlung Windows durchlaufen werden.
Parameter Bedeutung
FileName Der Dateiname (unbedingt erforderlich – er sollte mit dem Pfad angegeben werden)
ConfirmConversions »True« bedeutet, dass die Datei nicht im WinWord-Format vorliegt und deshalb konvertiert werden muss.
ReadOnly »True« bedeutet, dass die Datei schreibgeschützt geöffnet wird.
AddToRecentFiles »False« bedeutet, dass die Datei nicht zur Liste der zuletzt geöffneten Dateien hinzugefügt wird.
PasswordDocument Hier wird das Kennwort des Dokuments festgelegt.
PasswordTemplate Hier wird das Kennwort der Dokumentenvorlage festge-legt.
Revert Sollte das Dokument schon geöffnet sein, so bedeutet »True«, dass das alte Dokument ohne Änderungen ge-schlossen und neu geöffnet wird. »False« dagegen heißt, dass das alte Dokument aktiviert wird.
WritePasswordDocu-ment
Kennwort zum Speichern von Änderungen
WritePasswordTemplate Kennwort zum Speichern von Änderungen der Vorlage
Format legt das Konvertierungsprogramm für Dateien fest.
Encoding gibt die Dokumentcodierung (Codepage oder Zeichensatz) zurück, die beim Betrachten eines gespeicherten Doku-ments vom Webbrowser verwendet werden soll, oder legt diese fest.
Visible könnte das Dokument für den Benutzer unsichtbar öffnen. Diese Funktion dient dazu, per Programmierung Teile eines Dokuments auszulesen, ohne dass es der Benutzer sieht.
198
Dateizugriff
VBA stellt für Word (neben ActivePrinter) zwei »aktive Objekte« zur Verfü-gung: ActiveDocument und ActiveWindow. Sie stellen das »obenliegende« Doku-ment dar, in dem sich der Benutzer gerade befindet. Dieses kann mit folgendenbeiden Methoden gespeichert werden:
ActiveDocument.SaveActiveDocument.SaveAs(FileName, FileFormat, LockComments, _Password, AddToRecentFiles, WritePassword, _ReadOnlyRecommended, EmbedTrueTypeFonts, _SaveNativePictureFormat, SaveFormsData, SaveAsAOCELetter)
Dabei bedeuten:
Tab. 12.2: Die Parameter von ActiveDocument. Save
Es wird geschlossen:
ActiveDocument.Close(SaveChanges, _ OriginalFormat, RouteDocument)
Tab. 12.3: Die Parameter von ActiveDocument. Close
Parameter Bedeutung
FileName Dateiname
FileFormat Das Dokumentenformat, beispielsweise wdFormatDOSText oder wdFormatText
LockComments »True« bedeutet, dass die Kommentare im Text gespeichert werden.
Password Hier wird das Passwort festgelegt.
AddToRecentFiles »True« bedeutet, dass das Dokument zur Liste der zuletzt ver-wendeten Dateien hinzugefügt wird.
WritePassword Passwort zum Speichern von Änderungen des Dokuments
ReadOnlyRecom-mended
»True« bedeutet, dass Word beim Öffnen den Schreibschutz vorschlägt.
EmbedTrueType-Fonts
»True« bedeutet, dass die TrueType-Schriften eingebettet wer-den.
SaveNativePicture-Format
»True« bedeutet, dass von importierten Grafiken nur die Win-dows-Versionen gespeichert werden.
SaveFormsData »True« speichert nur die Daten, die der Benutzer in ein Formular eingegeben hat.
SaveAsAOCELetter »True« speichert das Adressfeld mit dem Dokument.
Parameter Bedeutung
SaveChanges Hier wird festgelegt, ob der Benutzer Änderungen speichern will (wdSaveChanges), ob der Benutzer entscheiden darf, dass sie gespeichert werden (wdPromptToSaveChanges), oder ob das Dokument ohne Änderungen verworfen wird (wdDoNot-SaveChanges).
199
12 Word VBA
Und Drucken? So wird gedruckt:
ActiveDocument.PrintOut(Background, Append, Range, _OutputFileName, From, To, Item, Copies, Pages, PageType, _PrintToFile, Collate, FileName, ActivePrinterMacGX, _ManualDuplexPrint, PrintZoomColumn, PrintZoomRow, _PrintZoomPaperWidth, PrintZoomPaperHeight)
Übung 1
Es wird überprüft, ob die Datei Mahnung.doc geöffnet ist. Falls ja, so wird sie inden Vordergrund geholt, falls nein, so wird sie geöffnet.
Übung 2
Der Benutzer wird gefragt, wie oft ein Dokument ausgedruckt werden soll.Dann wird es so oft ausgedruckt, wie der Benutzer es vorgegeben hat, und au-tomatisch geschlossen.
Übung 3
Ein Makro holt die Dokumentvorlage Rechnungsvorlage.dot her und speichertsie unter »Re”+Tagesdatum.
Lösung 1
Sub Mahnung()Dim wdDoc As DocumentFor Each wdDoc In Documents If wdDoc.Name = "Mahnung.doc" Then wdDoc.Activate Exit Sub End If
OriginalFormat Hier wird entschieden, ob das Dokument als WordDokument oder in einem anderen Format gespeichert wird.
RouteDocument Hier kann festgelegt werden, ob das Dokument an den nächsten Empfänger weitergeleitet wird.
12.2 Übungen
Parameter Bedeutung
12.3 Lösungen
200
Bewegen, Markieren, Position bestimmen
NextDocuments.Open ("c:\Eigene Dateien\Mahnung.doc")End Sub
Lösung 2
Sub DruckMakro()Dim intAnzahl As IntegerintAnzahl = InputBox("Wie oft soll die Datei " & _ "ausgedruckt werden?")ActiveDocument.PrintOut copies:=intAnzahlActiveDocument.Close wdSaveChangesEnd Sub
Lösung 3
Sub NeueRechnung()Documents.Add "Rechnungsformular.dot", FalseActiveDocument.SaveAs "Re" & Format(Date, "ddmmyyyy")End Sub
12.4 Bewegen, Markieren, Position bestimmen
Neuer Text wird in ein Dokument mit folgendem Befehl eingefügt:
Selection.TypeText
Mit folgender Methode wird ein (¢) eingefügt:
Selection.TypeParagraph
Folgende Tabelle listet die wichtigsten Selection-Methoden auf:
Tab. 12.4: Die wichtigsten Selection-Metho-den
Methode/Eigen-schaft von Selection Beschreibung
Tastenkombina-tion und Menü-punkte in Word Beispiel
Text einfügen
.TypeText Text:="..." fügt Text ein Selection.TypeText Text:= "Lehrer"
.Text = "..." fügt Text ein Selection.Text = "Lehrer"
.TypeParagraph fügt einen Ab-satz ein
(¢) Selection.TypePara-graph
Löschen
201
12 Word VBA
.TypeBackspace löscht ein Zei-chen links des Cursors
(æ_) Selection.TypeBack-space
.Delete(Unit, Count)Unit kann ein Zeichen sein (wdCharacter) oder ein Wort (wd-Word).Count ist eine ganze Zahl.
löscht ein oder mehrere Zei-chen rechts des Cursors
(Entf)BEARBEITEN – MARKIERUNG LÖ-SCHEN
Selection.Deletelöscht das nächste Zeichen oder die MarkierungSelection.Delete Count:=3löscht die nächsten drei ZeichenSelection.Delete unit:=wdWord, Count:=3löscht die nächsten drei Wörter.
.InsertBreak(Type)Type kann sein: wdPa-geBreak, wdColumn-Break, wdSectionBre-akNextPage, wdSec-tionBreakContinuous, wdSectionBreakEven-Page, wdSectionBrea-kOddPage oder wd-LineBreak
(Strg)+(¢)EINFÜGEN – MA-NUELLER WECHSEL
Selection.Insert-Breakfügt einen Seiten-umbruch ein.Selection.Insert-Break (wdPage-Break)fügt einen Seiten-umbruch ein.
.InsertSymbol(Charac-terNumber, Font, Uni-code)CharacterNumber ist die Zeichennummer für das angegebene Sonderzeichen. Font Variant optional. Der Name der Schriftart, die das Sonderzeichen enthält
Unicode ist False bei einem ANSI-Zeichen, True, wenn das Uni-code-Zeichen einge-fügt werden soll, das durch CharacterNum-ber spezifiziert wurde.
fügt an Stelle des angegebe-nen Bereichs oder der Mar-kierung ein Son-derzeichen ein
EINFÜGEN – SON-DERZEICHEN
Selection.InsertSym-bol Font:="Wing-dings", Character-Number:=-4022, Unicode :=Truefügt einen Smilie ein: JSelection.InsertSym-bol Font:="Wing-dings", Character-Number:=74(74 = 31 + 43)fügt einen Smilie ein: J
Methode/Eigen-schaft von Selection Beschreibung
Tastenkombina-tion und Menü-punkte in Word Beispiel
202
Bewegen, Markieren, Position bestimmen
Text kann auch einge-fügt werden mit .In-sertAfter, .InsertBe-fore
Bewegen im Text
.Move(Unit, Count)Unit kann sein:wdCharacter, wd-Word, wdSentence, wdParagraph, wdSec-tion, wdStory (der ge-samte Text), wdCell, wdColumn, wdRow oder wdTable.
bewegt den Cursor.
(Æ), (æ), (½), (¼), (Strg)+(Æ), (Strg)+(æ), (Strg)+(½), (Strg)+(¼)
Selection.Move Count:=3bewegt den Cursor drei Zeichen nach rechts.Selection.Move Count:=-3bewegt den Cursor drei Zeichen nach links.Selection.Move unit:=wdSentence, Count:=3bewegt den Cursor drei Sätze nach rechts.
.Movedown und .Mo-veup (Unit, Count, Ex-tent)Unit kann sein:wdLine, wdPara-graph, wdWindow oder wdScreen (eine Bildschirmseite)
bewegt den Cursor über den Text
(¼), (½), (Bild¼), (Bild½), (Strg)+(¼), (Strg)+(½)
Selection.Mo-veDown Unit:=wd-Line, Count:=3bewegt den Cursor drei Zeilen nach un-tenSelection.Mo-veDown Unit:=wd-Screen, Count:=3bewegt den Cursor drei Bildschirmsei-ten nach unten (ent-spricht (Bild¼), (Bild¼), (Bild¼))
MoveLeft, MoveRight (Unit, Count, Extent)Unit kann sein:wdCell, wdCharacter, wdWord oder wdSen-tence.
bewegt den Cursor über den Text.
Selection.Move-Right Unit:=wd-Word, Count:=3bewegt den Cursor drei Wörter nach rechts.
Methode/Eigen-schaft von Selection Beschreibung
Tastenkombina-tion und Menü-punkte in Word Beispiel
203
12 Word VBA
.EndKey (Unit, Extend)Unit kann sein:wdStory, wdColumn, wdLine oder wdRow.
bewegt den Cursor über den Text nach un-ten.
(Strg)+(Ende) Selection.EndKey Unit:=wdStorybewegt den Cursor ans Ende des Doku-ments.
.HomeKey (Unit, Ex-tend)Unit kann sein:wdStory, wdColumn, wdLine oder wdRow
bewegt den Cursor über den Text nach oben.
(Strg)+(Pos1) Selection.HomeKey Unit:=wdStorybewegt den Cursor an den Anfang des Dokuments.
Zum Bewegen dient auch: .EndOf, .Mo-veEndUntil, .Mo-veEndWhile, .Move-StartUntil, .MoveStrt-While, MoveUntil, .MoveWhile
Markieren von Text:
.MoveDown, .Mo-veUp, .MoveLeft, .MoveRight, .EndKey, .HomeKey
markiert. (ª)+(æ), (ª)+(½), (ª)+(Æ), (ª)+(½), (ª)+(Bild¼), (ª)+(Bild½), (ª)+(Strg)+(¼), (ª)+(Strg)+(½)
Selection.Move-Right unit:=wdCha-racter, Count:=3, Ex-tend:=wdExtendmarkiert drei Zei-chen rechts vom Cursor.Selection.MoveUp unit:=wdParagraph, Count:=3, Ex-tend:=wdExtendmarkiert drei Ab-sätze über dem Cur-sor.
.WholeStory markiert den gesamten Text.
(Strg)+(A)Bearbeiten – Alles Markieren
Selection.Whole-Storymarkiert den ganzen Text.
zum Markieren dient auch .Expand, .EndOf, .Extend, .Select, .Star-tOf
.Collapse(Direction)Direction kann sein: wdCollapseEnd oder wdCollapseStart
löst Markierung auf.
(æ) Selection.Collapsesetzt den Cursor vor den markierten Text.
Methode/Eigen-schaft von Selection Beschreibung
Tastenkombina-tion und Menü-punkte in Word Beispiel
204
Bewegen, Markieren, Position bestimmen
Umgekehrt kann nicht nur eine bestimmte Stelle innerhalb eines Dokumentsangesprungen, sondern auch ein Teil eines markierten Texts ausgelesen wer-den.
Tab. 12.5: Die wichtigsten Selection-Metho-den zum Auslesen von Text
Schwierig wird es, wenn überprüft werden soll, ob ein Text markiert ist. Dennleider liefert die Eigenschaft:
Selection.Characters.Count
die Zahl 1, also die gleiche Zahl, wie wenn ein Zeichen markiert wäre. Dafürsteht eine andere Eigenschaft zur Verfügung.
Trotz der vielen Möglichkeiten, sich über den Text zu bewegen, bleibt als besteund sicherste Methode das Anspringen von Textmarken. Sie können über EX-TRAS – OPTIONEN – ANSICHT sichtbar gemacht werden, sollten in Dokumen-ten, oder noch besser in Dokumentvorlagen, vorhanden sein, damit sie ange-sprungen werden können, damit der Text exakt an einer vorgesehenen Positionzu stehen kommt.
Der Befehl Selection.GoTo besitzt eine Reihe Sprungmöglichkeiten. Die allge-meine Syntax lautet:
Selection.GoTo(What, Which, Count, Name)
What kann folgende Konstanten annehmen:
Tab. 12.6: Die Konstanten des Parameters What
Auslesen von markiertem Text
.Text gibt den Text zurück, der markiert wurde.
MsgBox Selection.Text
.Characters gibt ein Zeichen zu-rück.
MsgBox Selection.Characters(2)
.Words gibt ein Wort zurück. MsgBox Selection.Words(2)
.Sentences gibt einen Satz zurück. MsgBox Selection.Sentences(2)
.EscapeKey bricht einen Modus ab, beispielsweise den Er-weiterungsmodus.
(Esc) Selection.EscapeKey
What Bedeutung
wdGoToAbsolute Bildschirm
wdGoToBookmark Textmarke
wdGoToComment Kommentar
wdGoToEndnote Endnote
wdGoToEquation Formel
wdGoToField Feldfunktion
wdGoToFootnote Fußnote
205
12 Word VBA
Mit Which ist das Element gemeint, auf das der Cursor gesetzt werden soll. Da-für sind folgende Konstanten erlaubt:
wdGoToAbsolute, wdGoToFirst, wdGoToLast, wdGoToNext, wdGoToPrevious oder wdGoToRelative
Mit Count ist die Anzahl gemeint. Folgende Befehlszeilen springen auf die ersteÜberschrift im Text:
Selection.GoTo What:=wdGoToHeading, Which:=wdGoToFirstSelection.GoTo What:=wdGoToHeading, Which:=wdGoToAbsolute, _ Count:=1
Bei den Konstanten
wdGoToBookmark, wdGoToComment, wdGoToField und wdGoToObject ist zwingendein Name nötig. Aufgrund der Eindeutigkeit des Namens sind die Richtung(Which) und die Anzahl (Count) überflüssig.
Mit der Eigenschaft
Selection.Range
kann auf einen markierten Bereich zugegriffen werden. Ist dieser leer, dann gibt
Selection.Range.Text
nichts zurück. Darüber hinaus kann eine ganze Reihe weiterer Informationenabgefragt werden. Dazu dient
Selection.Information(Type)
wdGoToGrammaticalError Grammatikfehler
wdGoToGraphic Grafik
wdGoToHeading Überschrift
wdGoToLine Zeile
wdGoToObject OLE-Objekt
wdGoToPage Seite
wdGoToPercent Prozentualer Teil des Dokuments
wdGoToProofreadingError Änderung
wdGoToSection Abschnitt
wdGoToSpellingError Rechtschreibfehler
wdGoToTable Tabelle
What Bedeutung
206
Bewegen, Markieren, Position bestimmen
Tab. 12.7: Die Konstanten bei Type von Selection. Information(Type)
Konstante (Type) Bedeutung
wdActiveEndAdjustedPageNumber Die Seitennummer mit dem aktiven Ende der an-gegebenen Auswahl oder des Bereichs
wdActiveEndPageNumber Die Seitennummer mit dem aktiven Ende der an-gegebenen Auswahl oder des Bereichs gezählt, von Beginn des Dokuments
wdActiveEndSectionNumber Die Nummer des Abschnitts
wdFirstCharacterLineNumber Die Zeilennummer des ersten Zeichens in der Auswahl
wdWithInTable »True«, wenn sich die Auswahl in einer Tabelle befindet.
wdAtEndOfRowMarker »True«, wenn sich der Cursor an der Zeilenend-marke in einer Tabelle befindet.
wdFrameIsSelected »True«, wenn es sich bei der Auswahl oder beim Bereich um einen gesamten Rahmen oder Text-feld handelt.
wdInCommentPane »True«, wenn sich der Cursor in einem Kom-mentarausschnitt befindet.
wdInEndnote »True«, wenn sich der Cursor in einem Endno-tenbereich befindet.
wdInFootnote »True«, wenn sich der Cursor in einem Fußno-tenbereich befindet.
wdInMasterDocument »True«, wenn sich der Cursor in einem Zentral-dokument befindet.
wdEndOfRangeColumnNumber Die Tabellenspaltennummer
wdEndOfRangeRowNumber Die Tabellenzeilennummer
wdStartOfRangeColumnNumber Die Nummer der Tabellenspalte in einem neuen Abschnitt
wdStartOfRangeRowNumber Die Nummer der Tabellenzeile in einem neuen Abschnitt
wdCapsLock »True«, wenn die FESTSTELLTASTE aktiviert ist.
wdNumLock »True«, wenn »Num« aktiv ist.
wdOverType »True«, wenn der Überschreibmodus aktiv ist. Mit der Overtype-Eigenschaft ändern Sie den Zu-stand des Überschreibmodus.
wdSelectionMode Auswahlmodus:0 Normale Auswahl1 Erweiterte Auswahl (in der Statusleiste er-scheint »ERW«) Dies entspricht der Tastenkom-bination (ª)+(Strg)+(F8).2 Spaltenauswahl (in der Statusleiste erscheint »SP«). Dies entspricht der Tastenkombination (ª)+(Strg)+(F8).
wdRevisionMarking »True«, wenn die Änderungsverfolgung aktiv ist.
207
12 Word VBA
Übung 1
Ein Makro liest das erste Zeichen, das erste Wort, den ersten Satz und den ers-ten Absatz einer Markierung aus, wenn etwas markiert wurde.
Übung 2
Ein Makro springt ans Ende des Dokuments, erzeugt dort zwei leere Absätzeund schreibt dann »Mit freundlichen Grüßen«.
Übung 3
Ein Makro merkt sich den Zustand der Ansicht (Normal, Weblayout oder Seiten-layout). Danach stellt es die Seitenansicht auf »Seitenlayout« ein und setzt dannden Cursor in die Fußzeile. Dort wird der Name der aktuellen Dokumentvorlagehineingeschrieben. Der Cursor wird in das Dokument zurückgesetzt. Die ur-sprüngliche Ansicht wird wieder hergestellt.
wdHeaderFooterType Art der Kopf- oder Fußzeile:Wert Art der Kopf- oder Fußzeile-1 Keine (die Auswahl oder der Bereich befindet sich nicht in einer Kopf- oder Fußzeile)0 Gerade Kopfzeile1 Ungerade Kopfzeile oder die einzige Kopfzeile2 Gerade Fußzeile3 Ungerade Fußzeile oder die einzige Fußzeile4 Erste Kopfzeile5 Erste Fußzeile
wdHorizontalPositionRelativeTo-Page
Die horizontale Position zum Seitenrand
wdHorizontalPositionRelativeTo-TextBoundary
Die horizontale Position zur Textumgrenzung
wdVerticalPositionRelativeToPage Die vertikale Position zum Seitenrand
wdVerticalPositionRelativeToText-Boundary
Die vertikale Position zur Textumgrenzung
wdNumberOfPagesInDocument Die Anzahl der Seiten im Dokument, das mit der Auswahl oder dem Bereich verbunden ist.
wdZoomPercentage Gibt den aktuellen Wert zurück, der mit der Percentage-Eigenschaft festgelegt wurde, für die Vergrößerung in Prozent.
12.5 Übungen
Konstante (Type) Bedeutung
208
Tipps
Tipp zu Übung 1
Beachten Sie bitte, dass Absatz-Objekte etwas anders behandelt werden, alsZeichen, Wörter oder Sätze.
Tipp zu Übung 2 und 3
Die Lösung erhält man zum größten Teil, wenn man den Befahl mit dem Makro-rekorder aufzeichnet.
Lösung 1
Sub Auslesen()Dim strZeichen As StringDim strWort As StringDim strSatz As StringDim strAbsatz As StringDim strText As String
With Selection strZeichen = .Characters(1).Text strWort = .Words(1).Text strSatz = .Sentences(1).Text strAbsatz = .Paragraphs(1).Range.Text strText = .TextEnd With
MsgBox "Der markierte Text lautet:" & vbCr & _ strText & vbCr & vbCr & _ "Das erste Zeichen:" & vbTab & strZeichen _ & vbCr & "Das erste Wort:" & vbTab & strWort _ & vbCr & "Der erste Satz:" & vbTab & strSatz _ & vbCr & "Der erste Absatz:" & vbTab & strAbsatz
End Sub
Lösung 2
Sub mfg()With Selection .EndKey unit:=wdStory .TypeParagraph
12.6 Tipps
12.7 Lösungen
209
12 Word VBA
.TypeParagraph .TypeText Text:="Mit freundlichen Grüßen"End WithEnd Sub
Lösung 3
Sub DokVorlagenNameInFußzeile()Dim bytFensterZustand As Byte
With ActiveWindow.ActivePane.View bytFensterZustand = .Type .Type = wdPrintView .SeekView = wdSeekCurrentPageFooter Selection.TypeText Text:=ActiveDocument.AttachedTemplate .SeekView = wdSeekMainDocument .Type = bytFensterZustandEnd WithEnd Sub
Diese Aufgabe funktioniert auch ohne »Springen«. Dazu wird die Nummer desaktuellen Abschnitts abgefragt und dort in die Fußzeile der Text geschrieben:
Sub DokVorlagenNameInFußzeile2()Dim intAbschnittNr As Integer
intAbschnittNr = _ Selection.Information(wdActiveEndSectionNumber)ActiveDocument.Sections(intAbschnittNr). _ Footers(wdHeaderFooterPrimary).Range.Text = _ ActiveDocument.AttachedTemplate
End Sub
12.8 TabellenEine Tabelle wird mit folgender Anweisung erzeugt:
ActiveDocument.Tables.Add (Range, NumRows, NumColumns)
Jede Zeile und jede Spalte hat eine Nummer (dies ist für das Rechnen wichtig).Diese kann erfragt werden mit wdStartOfRangeColumnNumber und mit wdStart-OfRangeRowNumber (beides Eigenschaften von Selection).
Eine bestimmte Tabelle, beispielsweise Tables(1) besitzt als Objekte die Samm-lung der Zeilen (Rows) und der Spalten (Columns). Diese wiederum besitzen dieSammlung der Zellen (Cells), die jeweils von 1 bis zur letzten nummeriert wer-den. Jede Zelle hat wiederum eine Reihe von Formatierungseigenschaften, wie
210
Übungen
Width, Height, Shading, Borders, LeftPadding, TopPadding (Abstand des Texteszum Zellrand), ... Sie sollen an dieser Stelle nicht besprochen werden, da sie perMakrorekorder bestimmt werden können.
Übung 1
Es wird überprüft, ob sich der Cursor in einer Tabelle befindet oder nicht. Sitzter in der Tabelle, wird dies dem Benutzer mitgeteilt. Sonst wird eine Tabelle mitdrei Zeilen und fünf Spalten erzeugt.
Übung 2
Erzeugen Sie eine Tabelle, die drei Zeilen und zwei Spalten hat, und deren ersteZeile eine graue Schattierung von 25% besitzt.
Übung 3
Schreiben Sie ein Makro, das ein neues Dokument erzeugt und dort eine Tabellefür den ANSI-Code einfügt.
Tipp1 bis 3
Viel Tipp- und Sucharbeit kann man sich durch den Makrorekorder ersparen!
Lösung 1
Sub InTabelleOderNicht()If Selection.Information(wdWithInTable) = True Then MsgBox "Der Cursor befindet sich in der Tabelle!"Else ActiveDocument.Tables.Add Range:=Selection.Range, _ NumRows:=3, NumColumns:=5End IfEnd Sub
12.9 Übungen
12.10 Tipps
12.11 Lösungen
211
12 Word VBA
Lösung 2
Sub TabelleGrauerKopf()Dim wdTabelle As TableSet wdTabelle = ActiveDocument.Tables.Add( _ Range:=Selection.Range, NumRows:=3, NumColumns:=2)With wdTabelle
.Rows(1).Shading.Texture = wdTexture25Percent
With .Borders .InsideLineStyle = wdLineStyleSingle .OutsideLineStyle = wdLineStyleSingle End WithEnd WithEnd Sub
Lösung 3
Sub ANSICode()Dim intZähler1 As IntegerDim intZähler2 As IntegerDim wdDokument As DocumentDim wdTabelle As Table
Set wdDokument = Documents.AddSet wdTabelle = wdDokument.Tables.Add( _ Range:=Selection.Range, NumRows:=24, _ NumColumns:=11)
For intZähler1 = 0 To 9 wdTabelle.Rows(1).Cells(intZähler1 + 2).Range.Text = _ intZähler1Next intZähler1
For intZähler2 = 3 To 24 wdTabelle.Columns(1).Cells(intZähler2 – 1).Range.Text = _ intZähler2 * 10
For intZähler1 = 0 To 9 wdTabelle.Columns(intZähler1 + 2). _ Cells(intZähler2 – 1).Range.Text = _ Chr$(intZähler2 * 10 + intZähler1) Next intZähler1Next intZähler2
wdTabelle.Columns(1).Cells(24).Range.Text = 250
212
Formularfelder
For intZähler1 = 0 To 5 wdTabelle.Columns(intZähler1 + 2). _ Cells(24).Range.Text = _ Chr$(250 + intZähler1) Next intZähler1
wdTabelle.Rows(1).Shading.Texture = wdTexture15PercentFor intZähler2 = 2 To 24 wdTabelle.Columns(1).Cells(intZähler2). _ Shading.Texture = wdTexture15PercentNext intZähler2
End Sub
12.12 FormularfelderIn einer Dokumentvorlage können Formularfelder enthalten sein. Diese befin-den sich in der Regel in einem geschützten Abschnitt. Sie werden über die Sym-bolleiste »Formular« eingefügt. Und an diese können Makros gebunden wer-den, die beim Verlassen oder beim Betreten aktiviert werden. Formularfelderhaben einen Namen (der in den Eigenschaften eingestellt wird). Über diesenwerden sie gesteuert. Drei Arten von Formularfeldern stehen zur Verfügung:Textfelder, Kontrollkästchen und Dropdownfelder. Im Folgenden finden Sie dieListe der wichtigsten Eigenschaften der Formularfelder:
Abbildung 12.2: Die fertige ANSI-Tabelle
213
12 Word VBA
Übung 1
In einem Dropdownfeld stehen eine Reihe Namen, in einem zweiten die zuge-hörigen Telefondurchwahlen. Ändert der Benutzer einen Namen, dann wirdauch die Telefonnummer verändert und umgekehrt.
Übung 2
Der in Übung 1 aus dem Dropdownfeld ausgewählte Name soll zugleich in einTextfeld geschrieben werden, wo es überschrieben werden kann.
Übung 3
Wird auf dem Formular in Frage 11 »verheiratet« angekreuzt, dann »springt«der Cursor nach der Tabulatoreingabe auf Frage 12 (Angaben zum Partner).Falls nicht, so »geht« es mit Frage 17 weiter.
Tipp zu Übung 1
Es sind zwei Makros nötig, die die Namen der entsprechenden Dropdown-For-mularfelder (drpTelDurchwahl und drpNamen) und die Eigenschaft Value verwen-den.
Befehl Bedeutung
ActiveDocument.Form-Fields(Name).CheckBox.Value
liefert 1 (»True«), wenn das Kontrollkästchen angekreuzt ist. Sonst 0 (»False«).
ActiveDocument.Form-Fields(Name).DropDown.Value
liefert die Nummer des ausgewählten Ein-trags.
ActiveDocument.Form-Fields(Name).DropDown.ListEntries
greift auf alle Listeneinträge zurück.
ActiveDocument.Form-Fields(Name).Result
liefert den ausgewählten Text eines Drop-downfelds oder den eingegebenen Text eines Textfelds.
ActiveDocument.Form-Fields(Name).Enabled
sperrt Feld gegen Änderungen oder lässt Änderungen zu.
ActiveDocument.Form-Fields(Name).TextInput.Default
ändert den Standardeintrag eines Textfeldes.
12.13 Übungen
12.14 Tipps
214
Lösungen
Lösung 1
Sub DropdownSynchronNameNachTel()ActiveDocument.FormFields("drpTelDurchwahl"). _ DropDown.Value = _ ActiveDocument.FormFields("drpNamen"). _ DropDown.ValueEnd Sub
Sub DropdownSynchronTelNachNamen()ActiveDocument.FormFields("drpNamen"). _ DropDown.Value = _ ActiveDocument.FormFields("drpTelDurchwahl"). _ DropDown.ValueEnd Sub
Vergessen Sie nicht, diese Makros an die Formularfelder, das heißt, an das Ereig-nis »Beim Beenden« zu binden!
Lösung 2
Das erste Makro muss erweitert werden um folgende Befehlszeile:
Sub DropdownSynchronNameNachTel()[...]ActiveDocument.FormFields("txtNamen").Result = _ActiveDocument.FormFields("drpNamen").ResultEnd Sub
Lösung 3
Sub SprungBeiNichtVerheiratet()If ActiveDocument.FormFields("chk11"). _ CheckBox.Value = True Then Selection.GoTo What:=wdGoToBookmark, Name:="chk17"Else Selection.GoTo What:=wdGoToBookmark, Name:="chk12"End IfEnd Sub
12.16 Ereignisse in WordNeben Ereignissen, die in Word 2000 noch aus Zeiten von WordBasic verwaltetwerden, stehen Ihnen in den »Microsoft Word Objekten« in »ThisDocument«folgende Ereignisse zur Verfügung:
12.15 Lösungen
215
12 Word VBA
Document_Close(), Document_New() und Document_Open().
Dabei bezieht sich New auf das Öffnen einer Dokumentvorlage über den Menü-punkt DATEI / NEU. Wird dagegen eine Word-Datei (*.doc oder *.dot) über DA-TEI / ÖFFNEN aufgemacht, so wird das Ereignis Open aktiviert.
Ein weiteres Ereignis finden Sie unter dem Befehl
Application.OnTime
Dort kann ein Zeitpunkt festgelegt werden, an dem ein Makro gestartet wird.
Wird in einem Klassenmodul der Befehl
Public WithEvents wdapp As
eingefügt, so stehen Ihnen die beiden Objekte
Word.Application und Word.Document zur Verfügung. Während letzteres keineweiteren Ereignisse liefert (neben den oben genannten), so stellt Word.Applica-tion folgende Ereignisse zur Verfügung:
wdapp_DocumentBeforeClose(ByVal Doc As Document, Cancel As Boolean), wdapp_DocumentBeforePrint(ByVal Doc As Document, Cancel As Boolean), wdapp_DocumentBeforeSave(ByVal Doc As Document, SaveAsUI As Boolean, Cancel As Boolean), wdapp_DocumentChange(), wdapp_DocumentOpen(ByVal Doc As Document), wdapp_NewDocument(ByVal Doc As Document), wdapp_Quit(), wdapp_WindowActivate(ByVal Doc As Document, ByVal Wn As Window), wdapp_WindowBeforeDoubleClick(ByVal Sel As Selection, Cancel As Boolean), wdapp_WindowBeforeRightClick(ByVal Sel As Selection, Cancel As Boolean), wdapp_WindowDeactivate(ByVal Doc As Document, ByVal Wn As Window), wdapp_WindowSelectionChange(ByVal Sel As Selection)
Übung 1
Beim Öffnen eines Formulars (über DATEI / NEU) wird eine Userform geöffnet.
Übung 2
Beim Öffnen eines bestimmten Dokuments wird die Textstelle angesprungen,wo zuletzt gearbeitet wurde.
Übung 3
Beim Starten von Word soll das Lineal eingeschaltet sein, die Ansicht auf »Nor-mal« und 100% gestellt werden.
12.17 Übungen
216
Tipps
Übung 4
Beim Öffnen einer bestimmten Datei wird eine Sicherheitskopie auf dem Serverabgelegt, wobei zum Dateinamen das aktuelle Datum gespeichert wird.
Übung 5
Beim Start von Word wird die zuletzt verwendete Datei geöffnet.
Übung 6
Wird ein Dokument geschlossen, dann wird überprüft, ob das Dokument ge-speichert wurde. Wurde es schon gespeichert, so wird erneut automatisch, dasheißt ohne nachzufragen, gespeichert. Hat das Dokument allerdings noch kei-nen Namen, das heißt, der Dateiname beginnt mit »Dokument«, so wird derBenutzer gebeten, das Dokument abzuspeichern. Und zwar penetrant, weilihm keine Möglichkeit des Abbrechens gegeben werden soll! Erst wenn er esgespeichert hat, wird ein neues Dokument geöffnet.
Übung 7
Zehn Sekunden nach Öffnen einer bestimmten Datei wird der Benutzer gelobt.
Übung 8
Bevor der Benutzer eine Datei ausdruckt, wird er darauf hingewiesen, dass dasPapier sehr teuer ist.
Tipp zu Übung 2
Die Tastenkombination (ª)+(F5), die auf zuletzt benutzte Textstelle springtkann aufgezeichnet werden. Dieser Befehl (GoBack) kann nun in das Öffnen-Er-eignis eingebunden werden.
Tipp zu Übung 3
Die benötigten Befehlszeilen können über den Makrorekorder ermittelt werdenund in das New-Ereignis eingefügt werden.
Tipp zu Übung 6
Zur Lösung dieses Problems wird ein Trick verwendet: Da das Ereignis Close ver-wendet wird, muss das Makro schon beim Start zur Verfügung stehen. Um dieszu ermöglichen, ruft das Ereignis Document_New das Makro AutoClose auf, dasdann aktiviert wird, wenn ein beliebiges Dokument geschlossen wird.
12.18 Tipps
217
12 Word VBA
Tipp zu Übung 7
Auch diese Lösung benötigt zwei Makros. Das eine (Lob) enthält das eigentlicheMakro. Das andere Document_Open ruft das erstere auf, wenn vom jetzigen Zeit-punkt zehn Sekunden vergangen sind.
Lösung 1
Private Sub Document_New()frmHaupt.ShowEnd Sub
Lösung 2
Private Sub Document_New()Application.GoBackEnd Sub
Lösung 3
Private Sub Document_New()With Application.ActiveWindow.ActivePane .DisplayRulers = True .View.Zoom.Percentage = 100 If Application.ActiveWindow.View.SplitSpecial = _ wdPaneNone Then .View.Type = wdNormalView Else Application.ActiveWindow.View.Type = wdNormalView End IfEnd WithEnd Sub
Erstaunlicherweise muss bei diesen Befehlszeilen, wenn sie mit dem Makrore-korder ermittelt wurden, das oberste Objekt Application hinzugefügt werden!
Lösung 4
Private Sub Document_Open()Dim strGanzerDateiName As StringDim strDateiName As StringstrDateiName = ActiveDocument.NamestrGanzerDateiName = ActiveDocument.FullName
ActiveDocument.SaveAs "C:\Eigene Dateien\Sonstiges\" & _ Format(Date, "ddmmyy") & strDateiName
12.19 Lösungen
218
Lösungen
ActiveDocument.SaveAs strGanzerDateiNameEnd Sub
Lösung 5
In die Datei Normal.dot muss folgendes Makro kopiert werden:
Private Sub Document_New()Application.RecentFiles(1).OpenEnd Sub
Lösung 6
Private Sub Document_New() ActiveDocument.RunAutoMacro Which:=wdAutoCloseEnd Sub
Sub AutoClose()Dim intAbbrechen As IntegerIf Left(ActiveDocument.Name, 8) = "Dokument" Then intAbbrechen = 0 While intAbbrechen = 0 intAbbrechen = Dialogs(wdDialogFileSaveAs).Show WendElse ActiveDocument.SaveEnd IfEnd Sub
Die Erläuterungen zu den Dialogen (Dialogs) finden Sie am Ende des Word-Ka-pitels im Abschnitt »Einige nützliche, erstaunliche und lustige Befehle«.
Lösung 7
Sub Lob() MsgBox "Guten Morgen, junger, schöner Mann!"End Sub
Private Sub Document_Open()Application.OnTime When:=Now + TimeValue("00:00:10"), _ Name:="Lob"End Sub
Lösung 8
In einem Klassenmodul befinden sich folgende Zeilen:
Option ExplicitPublic WithEvents wdapp As Application
219
12 Word VBA
Private Sub wdapp_DocumentBeforePrint _ (ByVal Doc As Document, Cancel As Boolean)MsgBox "Das Papier ist sehr teuer! " & _ & vbCr & "Bitte gehen Sie sparsam damit um!"End Sub
Es wird ein Objekt wdapp vom Typ (Word-)Application deklariert. Nun kann in ei-ner Ereignisprozedur dieses Objekts das Ereignis BeforePrint gestartet werden.Damit dieses Ereignis dieser Eigenschaft des Objekts gestartet werden kann,wird ein Makro benötigt. Beispielsweise:
Dim x As New Klasse1
Sub DruckStart()Set x.wdapp = Word.ApplicationEnd Sub
Dieses Makro wird gestartet. Wird nun irgendwann irgendein Dokument ge-druckt, dann startet das BeforePrint-Ereignis. Sinnvollerweise wird nicht dasMakro gestartet, sondern diese Routine in ein weiteres Ereignis gestellt. Bei-spielsweise in Document_New der Datei Normal.dot. Oder Ähnliches.
12.20 Einige nützliche, erstaunliche und lustige Befehle
Application.Caption
Jedes der Anwendungsprogramme hat eine Caption. Damit ist der Text in derTitelzeile gemeint. Wird in Word die Application.Caption abgefragt, so zeigtdas Meldungsfenster »Microsoft Word«. Erstaunlicherweise kann diese Eigen-schaft nicht nur abgefragt, sondern auch gesetzt werden:
Application.Caption = "StarOffice"
zeigt einen veränderten Text in der Titelzeile an. Dies kann beim Initialisierenvon Word eingebunden werden. Wird dieser Befehl an ein Makro gebunden,dann verschwindet der Text wieder, sobald Word neu gestartet wird. Explizitausschalten kann man diesen albernen Scherz entweder über:
Application.Caption = "Microsoft Word"
oder auch mit:
Application.Caption = ""
Application.ListCommands
Die Methode ListCommands des Objekts Application verlangt einen boolschenWert: »True« oder »False«. Wird »True« angegeben und der Befehl
Application.ListCommands True
220
Einige nützliche, erstaunliche und lustige Befehle
gestartet, dann wird ein neues Dokument erzeugt, in das alle Word-Befehle,alle Tastenkombinationen und alle Menüpunkte aufgelistet werden. Bei »False«sind es »nur« die Befehle, die einen Menüeintrag und/oder eine Tastenkombi-nation besitzen.
Application.System
Mit der Eigenschaft System der Application-Objekts können interessante Infor-mationen ausgelesen werden. Sie wurden bereits erwähnt beim Zugriff auf ini-Dateien und auf die Registry (siehe Kapitel 6). Daneben finden sich folgendeEigenschaften:
ComputerType, MathCoprocessorInstalled, FreeDiskSpace und ProcessorType
Country und LanguageDesignation
Cursor, HorizontalResolution und VerticalResolution
OperatingSystem und Version
Der Befehl
Application.System.MSInfo
startet das »Microsoft Systeminfo«.
Application.Tasks
Nur in Word kann man auf die laufenden Prozesse zugreifen. Hierzu steht dieSammlung Tasks zur Verfügung. Das folgende Beispiel listet alle Tasks auf:
Sub Programme()Dim t As TaskDim strN As String
For Each t In Application.Tasks strN = strN & vbCr & t.NameNext
MsgBox strN
End Sub
Für einen Task stehen die Methoden Activate, Close, Resize und SendWindow-Message zur Verfügung.
EXTRAS – OPTIONEN
Alle Word-Optionen, die über die Dialoge des Menüs EXTRAS / OPTIONEN ein-gestellt werden, können aufgezeichnet werden. Das Makro ergibt – je nachausgewähltem Dialog – die Befehle der Objekte ActiveDocument, ActiveWindowund Application. Sehr viele Einstellungen werden in
221
12 Word VBA
Application.Options
gespeichert. Müßig, sie alle hier aufzuzählen. Einige interessante Application-Eigenschaften seien an dieser Stelle erwähnt:
Application.DisplayStatusBar = TrueApplication.DisplayRecentFiles = TrueApplication.RecentFiles.Maximum = 9Application.DefaultSaveFormat = ""
Auf die Sammlung der Sprache, Wörterbücher, und so weiter kann zurückge-griffen werden:
Application.LanguagesApplication.CustomDictionaries
und Grundeinstellungen finden sich:
Application.UserName = "René Martin"Application.UserInitials = "rem"Application.UserAddress = ""
Interessant in diesem Zusammenhang ist sicherlich die Eigenschaft
ActiveWindow.View
mit der eine Reihe von Einstellungen geregelt werden, die das Aussehen derDarstellung betreffen.
DATEI – EIGENSCHAFTEN
Jedes Word-Dokument besitzt Eigenschaften, die Sie im Menü DATEI / EIGEN-SCHAFTEN finden. Insgesamt existieren 30 Dokumenteigenschaften, auf dieman mit der Eigenschaft .BuiltInDocumentProperties zugreifen kann. Leiderkann man den Zugriff auf die Eigenschaften nicht per Makrorekorder aufzeich-nen. Da die Namen in Word auf Deutsch stehen, per Programmierung aller-dings auf Englisch abgefragt werden müssen, ist es leichter statt
ActiveDocument.BuiltInDocumentProperties("Author").Value
mit
ActiveDocument.BuiltInDocumentProperties(3).Value
zuzugreifen. Das folgende Makro listet alle Eigenschaften des aktiven Doku-ments auf und schreibt sie in ein neues Word-Dokument:
Sub Dokumenteigenschaften()Dim docAltesdok As DocumentDim i As IntegerOn Error Resume Next
Set docAltesdok = ActiveDocumentApplication.Documents.Add
222
Einige nützliche, erstaunliche und lustige Befehle
For i = 1 To 30 Selection.TypeText i & ": " Selection.TypeText _ docAltesdok.BuiltInDocumentProperties(i).Name & ": " Selection.TypeText _ docAltesdok.BuiltInDocumentProperties(i).Value Selection.TypeParagraphNext
End Sub
Umgekehrt können natürlich auch Dokumenteigenschaften gesetzt werden:
ActiveDocument.BuiltInDocumentProperties("Author").Value = _ "E.T.A. Hoffmann"
Benutzerdefinierte Eigenschaften können gesetzt, abgefragt und gelöscht wer-den. Sie erscheinen im Eigenschaftendialog im Registerblatt »Anpassen«:
Sub EigeneDokumenteigenschaften()ActiveDocument.CustomDocumentProperties.Add _Name:="Meine Eigenschaften", Type:=msoPropertyTypeString, _LinkToContent:=False, Value:="reich, schön und berühmt"End Sub
Sub EigeneDokumenteigenschaftenLesen()On Error Resume NextMsgBox ActiveDocument.CustomDocumentProperties _ ("Meine Eigenschaften").ValueEnd Sub
Sub EigeneDokumenteigenschaftenLöschen()On Error Resume NextActiveDocument.CustomDocumentProperties _ ("Meine Eigenschaften").DeleteEnd Sub
Selbstverständlich können Eigenschaften der Auflistung BuiltInDocumentPro-perties nicht gelöscht werden.
Integrierte Dialoge
Word und Excel stellen Möglichkeiten zur Verfügung, auf deren Standarddia-loge zuzugreifen. Die Kollektion DIALOGS ist eine Eigenschaft von Application.Nach Eingabe der Klammer erhält man die komplette Liste aller vordefiniertenDialoge. Zum Anzeigen wird die Methode Show verwendet:
Application.Dialogs(xlDialogAlignment).Show
223
12 Word VBA
Sollen Werte voreingestellt werden, so muss man herausfinden, wie diese Opti-onen heißen. Die AutoComplete-Liste verrät darüber nichts. In der Hilfe stehtdie vollständige Referenz über alle Optionen im Kapitel »Arbeiten mit Steuer-elementen« im Unterkapitel »Anzeigen von integrierten Dialogfeldern«.
Soll beispielsweise die rote Ameisenkolonne (der fünfte Eintrag in der Liste)beim Betreten aktiviert sein, dann leistet dies das folgende Programm:
Sub Word_Dialoge_Verändern()Dim dlgMeinDialog As DialogSet dlgMeinDialog = Dialogs(wdDialogFormatFont)dlgMeinDialog.animations = 5dlgMeinDialog.ShowEnd Sub
Umgekehrt kann abgefangen werden, welcher Wert vom Benutzer ausgewähltwurde:
Sub Word_Dialoge_Verändern()Dim dlgMeinDialog As DialogSet dlgMeinDialog = Dialogs(wdDialogFormatFont)dlgMeinDialog.ShowMsgBox dlgMeinDialog.FontEnd Sub
Abbildung 12.3:Sämtliche Dialoge
werden in der Hilfebeschrieben.
224
Einige nützliche, erstaunliche und lustige Befehle
Soll abgefangen werden, welcher der Schaltflächen gewählt wurde, dann kanndies über folgende Liste geschehen:
Tab. 12.8: Mit diesen Werten kann abgefangen werden, welche Schaltfläche vom Benutzer ausge-wählt wurde.
Word und Excel stellen neben Show noch die Methode Display zur Verfügung.Sie zeigt die Dialoge an, ohne sie auszuführen. Umgekehrt führt die MethodeExecute den Dialog aus, ohne ihn anzuzeigen.
Ändern von Word-Menübefehlen
Dialoge können sicherlich an bestimmte Funktionalitäten gebunden werden,wie beispielsweise an Schaltflächen von selbsterstellten Dialogboxen, oder anbestimmte Ereignisse. Die Steuerung der Standarddialoge kann allerdings auchüber die Standardmenüs erfolgen. Soll beispielsweise im Dialog »Drucken« derOptionsbutton auf »Aktuelle Seite« gestellt werden, so kann dies mit folgen-dem Makro eingerichtet werden:
Sub Drucken_AktualSeite()Dim dlg As DialogSet dlg = Dialogs(wdDialogFilePrint)dlg.Range = 2dlg.ShowEnd Sub
Damit dieses Makro aufgerufen wird, wenn der Benutzer auf DATEI / DRUCKENklickt, muss das Makro in DateiDrucken umbenannt werden:
Sub DateiDrucken()Dim dlg As DialogSet dlg = Dialogs(wdDialogFilePrint)dlg.Range = 2dlg.ShowEnd Sub
So kann jede Funktion, die hinter einem Menüpunkt steht, umbelegt werden.
Feldfunktionen
Über Felder oder Feldfunktionen ließe sich sicherlich auch noch eine ganzeReihe Dinge schreiben. An dieser Stelle sollen jedoch einige Bemerkungen ge-nügen:
Fields ist eine Eigenschaft des Objekts Document, Range oder Selection.
Nummer der Schaltfläche Beschriftung
- 2 Schließen
- 1 OK
0 Abbrechen
>0 1 bedeutet die erste Schaltfläche, 2, die zweite und so weiter
225
12 Word VBA
Mit der Methode Update werden alle Felder aktualisiert, beispielsweise aktuali-siert
Selection.Fields.Update
alle Felder einer Markierung,
ActiveDocument.Fields.Update
aktualisiert alle Felder des Dokuments. Soll ein neues Feld hinzugefügt werden,so geschieht dies mit der Methode Add.
Sub SeitenNummerHinzu()ActiveDocument.Fields.Update Selection.Fields.Add _ Range:=Selection.Range, _ Type:=wdFieldEmpty, _ Text:= "NUMPAGES ", _ PreserveFormatting:=TrueEnd Sub
Dabei verwendet der Parameter Text den Namen der Feldfunktion. Felder kön-nen zwischen der Ansicht der Funktion und der Ansicht des Ergebnisses hin-und herschalten. Dafür dient folgende Methode:
ActiveDocument.Fields.ToggleShowCodes
Welche Seite der Feldfunktion gerade angezeigt wird, wird mit ShowCodes abge-fragt. Analog wird mit PrintFieldCodes die Feldfunktion anstelle des Ergebnis-ses gedruckt.
Options.PrintFieldCodes = True
Mit der Eigenschaft UpdateFieldsAtPrint werden Felder vor dem Druck aktuali-siert.
Options.UpdateFieldsAtPrint = True
Verstecken von Infos in einer Word-Datei
In jedem Word-Dokument werden im Kopf eine Menge Informationen gespei-chert: Seiteneinstellungen, verwendete Schriftarten und noch vieles mehr. PerProgrammierung kann nun in ein Dokument eine Dokumentenvariable einge-fügt werden, die mit Inhalt gefüllt wird. Dazu wird die Sammlung Variablesverwendet.
Folgendes Beispiel fügt eine Variable hinzu und füllt sie mit einem geheimenText:
Sub TextVerstecken()Dim docvar As VariableSet docvar = ActiveDocument.Variables.Add _ (Name:="Freimaurer", _
226
Einige nützliche, erstaunliche und lustige Befehle
Value:="Wenn Tugend und Gerechtigkeit" & vbCr & _ "Den großen Pfad mit Ruhm bestreut," & vbCr & _ "Dann ist die Erd' ein Himmelreich" & vbCr & _ "Und Sterbliche den Göttern gleich.")End Sub
Wenn man den Variablennamen kennt, kann man den Inhalt direkt auslesen:
Sub TextFinden()Dim docvar As VariableSet docvar = ActiveDocument.Variables("Freimaurer")MsgBox docvar.ValueEnd Sub
Natürlich können alle Dokumentvariablen durchlaufen werden und die Inhalteausgelesen werden:
Sub AlleTexteFinden()Dim docvar As VariableFor Each docvar In ActiveDocument.Variables MsgBox docvar.Name & ":" & vbCr & _ docvar.ValueNextEnd Sub
Mit der Methode Delete wird eine Variable gelöscht. Nun kann allerdings derInhalt einer solchen Variablen auch verschlüsselt werden. Der Ascii-Code einesZeichens liegt zwischen 32 und 255. Man könnte den Text also als Zahlenfolgedechiffrieren:
Sub TextAlsAsciiVerstecken()Dim docvar As VariableDim strText As StringDim intLängenZähler As IntegerDim strKrypt As StringstrText = "Wenn Tugend und Gerechtigkeit" & vbCr & _"Den großen Pfad mit Ruhm bestreut," & vbCr & _"Dann ist die Erd' ein Himmelreich" & vbCr & _"Und Sterbliche den Göttern gleich."
For Each docvar In ActiveDocument.Variables If docvar.Name = "Freimaurer" Then docvar.Delete Exit For End IfNext
For intLängenZähler = 1 To Len(strText)strKrypt = strKrypt & _
227
12 Word VBA
Format(Asc(Mid(strText, intLängenZähler, 1)), "000")NextSet docvar = ActiveDocument.Variables.Add _ (Name:="Freimaurer", _ Value:=strKrypt)
End Sub
Die Dechiffrierung ist nicht allzu schwierig:
Sub TextAlsAsciiFinden()Dim docvar As VariableDim strText As StringDim intLängenZähler As IntegerDim strKrypt As String
For Each docvar In ActiveDocument.Variables If docvar.Name = "Freimaurer" Then strKrypt = docvar.Value Exit For End IfNext
If strKrypt = "" Then MsgBox "Es wurde kein verborgener Inhalt abgespeichert."Else For intLängenZähler = 1 To Len(strKrypt) Step 3 strText = strText & Chr(Mid(strKrypt, _ intLängenZähler, 3)) Next MsgBox strTextEnd IfEnd Sub
Da man ein Word-Dokument in einem Editor öffnen kann, könnte man den ver-borgenen Text hinter der Dokumentenvariablen »Freimaurer« entdecken. Mankönnte ihn durch etwas Ausprobieren schnell dechiffrieren. Also muss der Textbesser verschlüsselt werden. Ein Passwort wäre die geschickte Methode hierfür.Wie kann man nun den Text mit einem Passwort ver- und entschlüsseln? JedesZeichen des zu verschlüsselnden Texts und des Passworts besitzt einen eindeuti-gen Ascii-Code. Mit der Funktion Xor können sie verknüpft werden – das Er-gebnis ist eine andere Zahl. Beispiel: Der Text beginnt mit dem Buchstaben»W«, das den Ascii-Code 87 hat. Das Schlüsselwort beginnt mit dem Buchsta-ben »x«, das heißt Ascii 120. Nun ergibt 87 Xor 120 den Wert 47, welches demZeichen »/« entspricht. Umgekehrt liefert 47 Xor 120 den Wert 87. Da nun Pass-wort und zu verschlüsselnder Text unterschiedliche Längen haben, wird das
228
Einige nützliche, erstaunliche und lustige Befehle
Passwort so oft durchlaufen, bis der eigentliche Text verschlüsselt ist. Die fol-gende Tabelle verdeutlicht das Ver- und Entschlüsseln am Text »Wenn Tugend«und am Passwort »xyz«:
Die Zeichen mit Ascii < 32 können nicht dargestellt werden, werden aber alsSonderzeichen abgespeichert. So kann nun mit einer Funktion der Text ver-schlüsselt und entschlüsselt werden. Die Objektvariable sollte eine wenig auffäl-lige Bezeichnung bekommen, wie beispielsweise »Margin« oder »Footer« oder»Number«.
Die folgende Prozedur verwendet die Funktion Krypto, um einen Text mit Hilfeeines Passworts zu verschlüsseln und speichert diesen in einer Dokumentvariab-len ab.
Sub TextAlsKryptoVerstecken()Dim docvar As VariableDim strText As StringDim strPass As String
strText = InputBox("Welcher Text soll versteckt werden)")strPass = InputBox("Wie lautet das Passwort?")
For Each docvar In ActiveDocument.Variables If docvar.Name = "Margin" Then docvar.Delete Exit For End IfNext
Set docvar = ActiveDocument.Variables.Add _ (Name:="Margin", _ Value:=Krypto(strText, strPass))
End Sub
Text W e n n T u g e n d
Ascii 87 101 110 110 32 84 117 103 101 110 100
Pass-wort
x y z x y z x y z x y
Ascii 120 121 122 120 121 122 120 121 122 120 121
Xor 47 28 20 22 89 46 13 30 31 22 29
Ascii / | | | Y . | | | |
Pass-wort
x y z x y z x y z x y
Xor 47 28 20 22 89 46 13 30 31 22 29
Text W e n n T u g e n d
229
12 Word VBA
Function Krypto(strText As String, _ strPass As String) As StringDim intTextLänge As IntegerDim intTextAsc As IntegerDim intPassLänge As IntegerDim intPassAsc As IntegerDim intAscNeu As IntegerDim strAusgabeText As String
For intTextLänge = 1 To Len(strText) intTextAsc = Asc(Mid(strText, intTextLänge, 1)) intPassLänge = ((intTextLänge – 1) Mod Len(strPass)) + 1 intPassAsc = Asc(Mid(strPass, intPassLänge, 1)) intAscNeu = intTextAsc Xor intPassAsc strAusgabeText = strAusgabeText & Chr(intAscNeu)NextKrypto = strAusgabeText
End Function
Und nun die Prozedur zum Dechiffrieren. Sie verwendet die gleiche FunktionKrypto:
Sub TextAlsKryptoFinden()Dim docvar As VariableDim strText As StringDim strPass As String
strPass = InputBox("Wie lautet das Passwort?")
For Each docvar In ActiveDocument.Variables If docvar.Name = "Margin" Then strText = docvar.Value Exit For End IfNext
If strText = "" Then MsgBox "Es wurde kein verborgener Inhalt abgespeichert."Else MsgBox Krypto(strText, strPass)End IfEnd Sub
230
Oberstes Objekt von Excel ist Application. Dieses Objekt hat eine Reihe von Ei-genschaften:
Application.Name
liefert den Name des Programms, also »Microsoft Excel«.
Application.Path
liefert den Pfad der Programmdatei »Excel.exe«.
Application.Caption
gibt den Text der Titelzeile zurück. Dieser kann, da es sich um eine Eigenschafthandelt, geändert werden, beispielsweise in
Application.Caption = "Lotus 1-2-3"
Eine ganze Reihe von Grundeinstellungen findet sich im Objekt Application:
AddIns, AlertBeforeOverwriting, AltStartupPath, AnswerWizard, AskToUpdate-Links, Assistant, AutoPercentEntry, CalculationVersion, CellDragAndDrop,ControlCharacters, Cursor […]
13.1 DateizugriffDie aktuelle Excel-Datei heißt
Application.ActiveWorkbook
oder:
Application.ThisWorkbook
Alle offenen Dateien können auf folgende Art angesprochen werden:
Application.Workbooks
Man kann mit einem Zähler alle Dateien durchlaufen lassen und sie somit an-sprechen:
For i = 1 To Application.Workbooks.CountMsgBox Application.Workbooks(i).Name
oder direkt alle Objekte ansprechen, wie im folgenden Beispiel:
Sub Alle_Dateien()Dim xlsDatei As WorkbookDim strDatName As String
13 Excel
231
13 Excel
For Each xlsDatei In Workbooks strDatName = strDatName & vbCr & xlsDatei.NameNext
MsgBox strDatName
End Sub
Ähnlich wie das Word-Objektmodell besitzt Excel für die Sammlung der Work-books, beziehungsweise für ein Workbook, folgende Methoden:
DATEI / SCHLIESSEN
Workbooks(1).Close(SaveChanges, FileName, RouteWorkbook)
DATEI / SPEICHERN
Workbooks(1).Save
DATEI / SPEICHERN UNTER
Workbooks(1).SaveAs(Filename, FileFormat, Password, WriteResPassword, ReadOnlyRecommended, CreateBackup, AccessMode, ConflictResolution, AddToMru, TextCodePage, TextVisualLayout)Workbooks(1).SaveCopyAs(Filename)
Letzte Methode sichert die Datei unter einem anderen Namen, ohne die Dateidabei zu verändern.
DATEI / DRUCKEN
Workbooks(1).PrintOut(From, To, Copies, Preview, ActivePrinter, PrintToFile, Collate, PrToFileName)
DATEI / ÖFFNEN
Workbooks.Open(FileName, UpdateLinks, ReadOnly, Format, Password, WriteResPassword, IgnoreReadOnlyRecommended, Origin, Delimiter, Editable, Notify, Converter, AddToMRU)
DATEI / NEU
Workbooks.Add(Template)
Die Eigenschaft Saved prüft, ob eine Arbeitsmappe seit der letzten Änderunggespeichert wurde. Falls ja, wird der Wert »True« zurückgegeben.
13.2 Zugriff auf TabellenblätterJede Excel-Datei hat eine oder mehrere Tabellenblätter. Dabei ist das Objekt vonWorkbook entweder Sheet oder WorkSheet. Sheet ist dabei allgemeiner, da Tabel-lenblätter auch Diagramme beinhalten können. Deklariert wird es allerdingsvom Objekttyp Worksheet. Folgendes Beispiel durchläuft alle Tabellenblätter undmeldet die Blattnamen:
232
Übungen
Sub TabellenBlätterDurchlaufen()Dim xlsTabBlatt As WorksheetDim strBlattName As String
On Error Resume Next
For Each xlsTabBlatt In Sheets strBlattName = strBlattName & vbCr & xlsTabBlatt.NameNext
MsgBox strBlattName
End Sub
Ein Blatt wird mit der Methode Activate aktiviert. Ist es verborgen, so kann diesmit der Eigenschaft Visible überprüft werden. Gelöscht wird ein Blatt mit derMethode Delete, hinzugefügt mit Add. Die Eigenschaft Name übergibt den Na-men.
Übung 1
Überprüfen Sie, ob eine bestimmte Datei schon geöffnet ist oder nicht. Falls ja,so wird sie nach vorne geholt, falls nein, dann wird sie geöffnet.
Übung 2
Der Benutzer wird nach dem Namen eines Tabellenblatts gefragt. Existiert es, sowird es angesprungen, existiert es nicht, so erhält der Benutzer eine Fehlermel-dung.
Übung 3
Wie in Aufgabe 2 wird der Benutzer nach einem Tabellenblattnamen gefragt. Erhat die Möglichkeit, statt des gesamten Namens einen Teil des Namens einzu-geben. Existiert das Blatt, dann wird es angesprungen, falls nicht, so erhält derBenutzer eine Fehlermeldung.
13.3 Übungen
233
13 Excel
Lösung 1
Sub DateiÖffnen()Dim xlsDatei As WorkbookDim strDatName As String
On Error Resume Next
For Each xlsDatei In Workbooks If xlsDatei.Name = "Rechnung.xls" Then xlsDatei.Activate Exit Sub End IfNext
Workbooks.Open Filename:= _ "C:\Eigene Dateien\Uebungsdateien\Excel\Rechnung.xls"End Sub
Lösung 2
Sub BlattSprung1()Dim strBlattName As StringOn Error Resume NextstrBlattName = InputBox("Wie lautet das gesuchte Blatt?")ActiveWorkbook.Sheets(strBlattName).ActivateIf Err.Number = 9 Then MsgBox "Das Blatt " & strBlattName & " existiert nicht."End IfEnd Sub
Lösung 3
Sub BlattSprung2()Dim xlsTabBlatt As WorksheetDim strBlattName As String
On Error Resume Next
strBlattName = InputBox("Wie lautet das gesuchte Blatt?")
For Each xlsTabBlatt In Sheets If InStr(LCase(xlsTabBlatt.Name), _ LCase(strBlattName)) > 0 Then xlsTabBlatt.Activate
13.4 Lösungen
234
Zugriff auf Zellen
Exit Sub End IfNext
MsgBox "Das Blatt " & strBlattName & " existiert nicht."
End Sub
Die Methode aus Lösung 2 – das direkte Anspringen ist sicherlich die schnellereMöglichkeit als die, die in Lösung 3 vorgestellt wird. Allerdings auch die unsi-cherere, denn bei einer falschen Eingabe wird ein Fehler erzeugt. In Lösung 3wird der Name jedes Tabellenblatts, oder genauer, die kleingeschriebene Vari-ante mit dem in Kleinbuchstaben konvertierten, eingegebenen Text verglichen.Diese ist sicherlich mehr Rechenaufwand, allerdings auch die sicherere Varianteund die Möglichkeit, damit der Code weiter ausgebaut werden kann.
13.5 Zugriff auf ZellenDie wohl häufigste Zugriffsart ist sicherlich der Zellzugriff. Dabei kann der Cur-sor auf eine Zelle gesetzt werden, und diese kann dann modifiziert werden oderder Zugriff kann indirekt über einen Objektzugriff erfolgen. Für beide Variantenstehen eine ganze Reihe von Möglichkeiten zur Verfügung.
Angenommen, Sie möchten auf die Zelle B9 des Tabellenblatts »Filmliste« derDatei Sammlung.xls zugreifen. Ist diese Datei offen, dann kann sie angesprun-gen werden. Danach wird das Tabellenblatt aktiviert und schließlich die Zelle.Der Zugriff darüber erfolgt mit dem Objekt Range:
Sub AufB9Zugreifen()Application.Workbooks("Sammlung.xls").ActivateActiveWorkbook.Sheets("Filmliste").ActivateActiveSheet.Range("B9").ActivateEnd Sub
Nun sitzt der Cursor auf der Zelle B9. Den Inhalt dieser Zelle könnte man mit
MsgBox ActiveCell.Value
auslesen.
Es geht auch ohne »Anspringen«:
MsgBox Application.Workbooks("Sammlung.xls"). _ Sheets("Filmliste").Range("B9").Value
Solch eine riesige Befehlszeile ist weder übersichtlich noch praktisch zum Feh-lerabfangen. Deshalb empfiehlt sich das Aufsplitten und Aufteilen an Objektva-riablen. Beispielsweise so:
235
13 Excel
Sub AufB9Zugreifen3()Dim xlsDatei As WorkbookDim xlsTabelle As WorksheetDim xlsZelle As Range
Set xlsDatei = Application.Workbooks("Sammlung.xls")Set xlsTabelle = xlsDatei.Sheets("Filmliste")Set xlsZelle = xlsTabelle.Range("B9")
MsgBox xlsZelle.ValueEnd Sub
Zellinhalte können abgefragt (wie oben) oder auch gesetzt werden. Der Befehl
xlsZelle.Value = "Titanic"
schreibt den Wert »Titanic« in die Zelle xlsZelle. Activate oder Select sindzwei Methoden, mit denen Zellen aktiviert werden. Statt des Objekts Rangekann auch Cells als Kollektion verwendet werden:
Set xlsZelle = xlsTabelle.Cells(9, 2)
Dabei wird zuerst die Zeile (Rows) und dann die Spalte (Columns) angegeben. DerZugriff über Cells eignet sich sehr gut, wenn mit Variablen gearbeitet wird.
ActiveCell.ClearContents
löscht den Inhalt der aktiven Zelle. Sollen die Formatierungen gelöscht werden,so ist
ActiveCell.ClearFormats
zu verwenden. Weitere Löscheigenschaften finden sich mit:
ActiveCell.ClearCommentsActiveCell.ClearNotes
Beide löschen unterschiedslos die Kommentare der aktiven Zelle. Und alles wirdgelöscht mit:
ActiveCell.Clear
Schrift-Formatierungen können mit
ActiveCell.Font
festgelegt werden. Beispielsweise:
ActiveCell.Font.Bold = TrueActiveCell.Font.Name = "Times"ActiveCell.Font.Size = 24
236
Zugriff auf Zellen
Eleganter natürlich:
With ActiveCell.Font .Bold = True .Name = "Times" .Size = 24End With
Auch Kommentare können eingefügt werden:
ActiveCell.NoteText "Grunz"
Soll der Kommentar wieder ausgelesen werden, so kann dies mit der Eigen-schaft Comment.Text geschehen:
MsgBox ActiveCell.Comment.Text
Die Lage der angeklickten Zelle, die oft überprüft wird, kann mit folgenden Ei-genschaften abgefragt werden:
Sub ZellenLage()Dim strZellInfo As StringWith ActiveCellstrZellInfo = "Adresse: " & vbTab & vbTab & .Address & _ vbCr & "Lokale Adresse: " & vbTab & .AddressLocal & _ vbCr & "Spalte: " & vbTab & vbTab & .Column & _ vbCr & "Zeile: " & vbTab & vbTab & .RowEnd With
MsgBox strZellInfo
End Sub
Der umgekehrte Fall ist der Zugriff auf eine (oder mehrere) Zellen. Hierfür stehtdie Methode Range zur Verfügung. Das Verfahren
Range("A4").Activate
wählt die Zelle A4 aus. Soll ein Bereich markiert werden, so kann dies mit
Range("A4:D7").Activate
geschehen. Ebenso wählt
Range("A1:D7").Select
diesen Bereich aus. Mit Activate kann zusätzlich eine Zelle innerhalb des mar-kierten Bereichs ausgewählt werden:
Range("A1:F7").SelectRange("C3").Activate
237
13 Excel
Auf den ersten Blick umständlicher funktioniert das Auswählen über den Be-reich:
Range(Cells(1, 1), Cells(6, 7)).Activate
Der Vorteil davon ist allerdings, dass die Eckkoordinaten getrennt berechnetwerden können:
x1 = 1x2 = 6y1 = 1y2 = 7
Range(Cells(x1, y1), Cells(x2, y2)).Activate
Statt Range steht Ihnen auch der Befehl Evaluate zur Verfügung:
Evaluate(Cells(x1, y1), Cells(x2, y2)).Activate
führt zum gleichen Ergebnis, wie Range. Evaluate führt über Range hinaus undkann auf weitere Elemente angewendet werden.
Ähnlich wie die Range-Methode einen Bereich auswählt (oder bearbeitet), kannmit dem Objekt, beziehungsweise der Methode Worksheets ein Arbeitsblatt ak-tiviert werden. Soll beispielsweise der Zellbereich A1:C3 des Blatts »Tabelle3«fett formatiert werden, so kann dies folgendermaßen eingegeben werden:
Worksheets("Tabelle3").Activatex1 = 1x2 = 3y1 = 1y2 = 3
With Range(Cells(x1, y1), Cells(x2, y2)) .Select .Font.Bold = TrueEnd With
Oder analog per indirektem Zellzugriff so:
Dim x1 As Integer, x2 As IntegerDim y1 As Integer, y2 As IntegerDim xlsTab As WorksheetDim xlsZelle1 As Range, xlsZelle2 As RangeDim xlsBereich As Range
Set xlsTab = Application.ActiveWorkbook. _ Worksheets("Tabelle3")x1 = 1x2 = 3y1 = 1y2 = 3
238
Rechnen in Excel
Set xlsZelle1 = xlsTab.Cells(x1, y1)Set xlsZelle2 = xlsTab.Cells(x2, y2)Set xlsBereich = xlsTab.Range(xlsZelle1, xlsZelle2)
xlsBereich.Font.Bold = False
Mit einem ähnlichen Objekt wir Cells kann man sich bewegen. Sitzt der Cursorauf der Zelle B9, so wird er auf die Zelle B10 mit dem Befehl
ActiveCell.Offset(1, 0).Activate
gesetzt. Von B9 wird er auf B8 mit
ActiveCell.Offset(-1, 0).Activate
bewegt, auf C9 mit:
ActiveCell.Offset(0, 1).Activate
Soll dagegen nur ein Wert überprüft oder gesetzt werden, so genügt:
MsgBox ActiveCell.Offset(1, 0).Value
Der Cursor bleibt auf der alten Zelle sitzen und zeigt den Wert der darunter lie-genden Zelle an. Wird nun ein bestimmter Bereich durchlaufen, so hilft hierbeidas Objekt CurrentRegion. Es hat die beiden Eigenschaften Rows und Columns,die beide wiederum die Eigenschaft Count besitzen. Darüber kann die Anzahlder Zeilen oder Spalten aus einem ausgefüllten Bereich ermittelt werden.
13.6 Rechnen in ExcelDer Makrorekorder leistet nicht nur beim Zellformatieren und Sortieren un-schätzbare Dienste, sondern auch bei der Eingabe von Formeln und Funktio-nen. Angenommen in der Spalte B stehen Einnahmen, in der Spalte C Ausga-ben. In D soll nun die Differenz aus beiden, also der Gewinn stehen. Dazu kannaufgezeichnet werden:
ActiveCell.FormulaR1C1 = "=RC[-2]-RC[-1]"
Dies ist die amerikanische Schreibweise. Steht der Cursor in D2, so wird mitRC[-2] die Zelle zwei Spalten links davon bezeichnet, also B2. In der deutschenExcel-Schreibweise steht die Formel:
=B2-C2
Dies kann programmiertechnisch umgesetzt werden in:
ActiveCell.Formula = "=B2-C2"
Angenommen, in der Zelle G1 stünde ein Wert, der absolut addiert werden soll,dann liefert die amerikanische Schreibweise:
ActiveCell.FormulaR1C1 = "=RC[-2]-RC[-1]+R1C7"
239
13 Excel
Dabei stehen relative Zellbezüge in eckigen Klammern und beziehen sich aufActiveCell. Absolute Bezüge stehen ohne Klammern und beginnen ihre Zäh-lung bei 1. R1C7 entspricht folglich der Formel $G$1, oder in der deutschenSchreibweise:
ActiveCell.Formula = "=B2-C2+$G$7"
Soll dies nun auf mehrere Zeilen aufgefüllt werden, so könnte man es mit fol-genden Befehlen erzeugen:
Sub Automatisch_Rechnen()Dim intZeilenzahl As IntegerDim intZähler As Integer
intZeilenzahl = _ActiveWorkbook.Sheets(1).Range("B2").CurrentRegion.Rows.Count
ActiveWorkbook.Sheets(1).Range("D2").Activate
For intZähler = 1 To intZeilenzahl – 1 ActiveCell.FormulaR1C1 = "=RC[-2]-RC[-1]+R1C7" ActiveCell.Offset(1, 0).ActivateNext
End Sub
Und nun soll unter der Tabelle die Summe gezogen werden. Hierfür kann wie-der die US-amerikanische oder die deutsche Schreibweise verwendet werden:
ActiveCell.FormulaR1C1 = "=SUM(R[-11]C:R[-1]C)"ActiveCell.FormulaLocal = "=SUMME(B2:B12)"
Dabei ist zu beachten, dass die US-amerikanische Schreibweise auch in derdeutschen Excel-Version die englischsprachigen Funktionsnamen verwendet!
Am Ende des obigen Makros könnte also stehen:
Sub Automatisch_Rechnen()Dim iZeilenzahl As Integer[...]ActiveWorkbook.Sheets(1).Cells(iZeilenzahl + 1, 2).ActivateActiveCell.FormulaR1C1 = "=SUM(R[-" & iZeilenzahl – 1 & _ "]C:R[-1]C)"ActiveCell.Offset(0, 1).ActivateActiveCell.FormulaR1C1 = "=SUM(R[-" & iZeilenzahl – 1 & _ "]C:R[-1]C)"ActiveCell.Offset(0, 1).ActivateActiveCell.FormulaR1C1 = "=SUM(R[-" & iZeilenzahl – 1 & _ "]C:R[-1]C)"
End Sub
240
Zugriff auf Zeichen innerhalb einer Zelle
13.7 Zugriff auf Zeichen innerhalb einer Zelle
Nach der Zellebene geht es noch eine Ebene tiefer zu den Zeichen innerhalb ei-ner Zelle. Angenommen, für die Darstellung chemischer Formeln werden tief-gestellte Ziffern benötigt. Dazu wird die betreffende Zahl in der editierten Zellemarkiert und dann im Menü FORMAT / ZELLEN / SCHRIFT die Option »Tiefge-stellt« eingestellt.
Diese Funktion kann aufgezeichnet werden, beispielsweise für H2SO4.
Sub ZeichenTiefStellen()
ActiveCell.FormulaR1C1 = "H2SO4" With ActiveCell.Characters(Start:=1, Length:=1).Font .Name = "Arial" .FontStyle = "Standard" .Size = 10 .Strikethrough = False .Superscript = False .Subscript = False .OutlineFont = False .Shadow = False .Underline = xlUnderlineStyleNone .ColorIndex = xlAutomatic End With With ActiveCell.Characters(Start:=2, Length:=1).Font .Name = "Arial" .FontStyle = "Standard" .Size = 10 .Strikethrough = False .Superscript = False .Subscript = True .OutlineFont = False .Shadow = False .Underline = xlUnderlineStyleNone .ColorIndex = xlAutomatic End With With ActiveCell.Characters(Start:=3, Length:=3).Font .Name = "Arial" .FontStyle = "Standard" .Size = 10 .Strikethrough = False .Superscript = False .Subscript = False .OutlineFont = False .Shadow = False
241
13 Excel
.Underline = xlUnderlineStyleNone .ColorIndex = xlAutomatic End With Range("B5").SelectEnd Sub
Damit wird klar, dass die Zelle selbst eine weitere Eigenschaft besitzt: Charac-ters. Sollen nun in einer Zelle alle darin befindlichen Ziffern tiefer gestellt wer-den, dann geht das folgendermaßen:
Sub Zeichentieferstellen()Dim intZeichenAnzahl As IntegerDim intZähler As IntegerintZeichenAnzahl = ActiveCell.Characters.CountFor intZähler = 1 To intZeichenAnzahl If IsNumeric(ActiveCell.Characters _ (Start:=i, Length:=1).Caption) Then ActiveCell.Characters(Start:=i, _ Length:=1).Font.Subscript = True End IfNextEnd Sub
Übung 1
In einer Tabelle sind drei Spalten ausgefüllt. In der ersten, die mit »Nummer«überschrieben ist, stehen fortlaufende Nummern, beginnend mit 100. In derzweiten Spalte stehen die Bezeichnungen, beispielsweise die Filmnamen, in derdritten die (fiktiven) Preise (für die Videos).
Der Benutzer wird nach einer Nummer gefragt. Er trägt sie in eine Inputbox einund erhält den Namen des Films.
Übung 2
Ein zweites Makro in der Filmliste soll dafür sorgen, dass der Benutzer einenneuen Artikel eintragen kann. Ihm wird automatisch die nächsthöhere Nummervergeben, und der Artikel und sein Preis wird unten an die Liste angefügt.
Übung 3
Stellen Sie sich zwei Außendienstmitarbeiter vor, die auf ihrem Laptop jeweilseine Excel-Tabelle mit Namen haben. Nun ändern beide bestimmte Datensätze.Am Abend eines Tages oder am Ende eines Quartals sollen beide Listen mitei-nander verglichen werden. Nun gibt es verschiedene Möglichkeiten der Syn-
13.8 Übungen
242
Tipp
chronisation: In jeder der beiden Tabellen werden die Datensätze rot formatiert,die nur in einer der beiden Tabellen stehen, damit sofort die Änderungen er-kannt werden.
Übung 4
In Zelle C1 steht eine Formel. Dieselbe Formel wird in F7 noch einmal benötigt.Würde man sie kopieren, würden die Bezüge nicht mehr stimmen. Deshalb solldie Formel so nach F7 kopiert werden, dass dieselben relativen Bezügen in die-ser neuen Zelle stehen.
Übung 5
In einer Arbeitsmappe werden in allen Tabellenblättern in der Zelle C27 dieSumme der darüber stehenden Werte der Spalte C benötigt.
Übung 6
Eine Mappe besteht aus mehreren Blättern. Auf jedem Blatt befindet sich inZelle R37 ein Gesamtergebnis. Über eine Verknüpfung soll in jedem Blatt (be-ginnend ab dem zweiten) in der Zelle A1 Bezug auf die Zelle R37 des vorherge-henden Blatts genommen werden.
Tipp zu Übung 3
Die beiden Dateien heißen NAMENSLISTE1.XLS und NAMENSLISTE2.XLS. Es wirdüberprüft, ob beide offen sind. Wenn ja, dann werden sie nach der erstenSpalte sortiert, in der sich ein Zähler befindet. Nun benötigt man zwei Schleifen.In der äußeren Schleife durchläuft ein Zähler alle Werte. Jeder einzelne dieserWerte wird mit jedem Wert der zweiten Tabelle verglichen. Steht der Wert derersten Tabelle in der zweiten, wird die Zelle rot formatiert und der Zähler wirdum eins vergrößert. Wird er dagegen nicht gefunden, so wird weitergesucht.Nachdem die erste Tabelle durchlaufen wurde, wird auch die zweite Tabelledurchlaufen.
Lösung 1
Sub FilmAnzeigen1()Dim intNr As IntegerDim intZähler As Integer
13.9 Tipp
13.10 Lösungen
243
13 Excel
On Error GoTo endeThisWorkbook.Sheets("Hitchcock").ActivateActiveSheet.[A1].SelectintZähler = 0
intNr = InputBox("Bitte eine Nummer eingeben")
With ActiveCell For intZähler = 1 To .CurrentRegion.Rows.Count
If ActiveCell.Offset(intZähler, 0).Value = intNr Then MsgBox "Der Film mit der Nummer " & _ intNr & " lautet: " & vbCr & Chr(187) & _ ActiveCell.Offset(intZähler, 1).Value & _ Chr(171) & vbCr & " und kostet " & _ FormatCurrency(ActiveCell.Offset _ (intZähler, 2).Value) Exit Sub End If
Next intZählerEnd WithMsgBox "Schade, aber die Nummer " & intNr & _ " wurde nicht gefunden!"Exit Subende:MsgBox "Es trat ein Fehler auf: " & _ Err.Description, vbCritical, "Fehler!"End Sub
Zur Vorgehensweise: Der Benutzer wird nach einer Nummer gefragt. Im Tabel-lenblatt »Hitchcock« wird die Zelle A1 aktiviert. Eine For ... Next-Schleifedurchläuft die Tabelle von A1 bis zu der letzten gefüllten Zelle, die über die Ei-genschaft ActiveCell.CurrentRegion.Rows.Count ermittelt wird. Jede der Zel-len, wird mit dem Inhalt der Input-Box-Variablen vergleichen (intNr). Sind siegleich, bewegt sich der Zeiger eine Spalte nach rechts und zeigt den Inhalt die-ser Zelle an. Wird die Schleife ohne Erfolg durchlaufen, dann wird die Meldungunterhalb der Schleife angezeigt. Es funktioniert natürlich auch über einen Ob-jektzugriff. Diese Lösung ist jedoch eleganter:
Sub FilmAnzeigen2()Dim xlDatei As WorkbookDim xlTabelle As WorksheetDim xlZelle As RangeDim intNr As IntegerDim intZähler As Integer
On Error GoTo ende
244
Lösungen
Set xlDatei = ActiveWorkbookSet xlTabelle = xlDatei.Sheets("Hitchcock")Set xlZelle = xlTabelle.Range("A1")
intNr = InputBox("Bitte eine Nummer eingeben")
With xlZelle For intZähler = 1 To .CurrentRegion.Rows.Count
If xlZelle.Offset(intZähler, 0).Value = intNr Then MsgBox "Der Film mit der Nummer " & _ intNr & " lautet: " & vbCr & Chr(187) & _ xlZelle.Offset(intZähler, 1).Value & _ Chr(171) & vbCr & " und kostet " & _ FormatCurrency(xlZelle.Offset _ (intZähler, 2).Value) Exit Sub End If
Next intZählerEnd WithMsgBox "Schade, aber die Nummer " & intNr & _ " wurde nicht gefunden!"Exit Subende:MsgBox "Es trat ein Fehler auf: " & _ Err.Description, vbCritical, "Fehler!"End Sub
Lösung 2
Die Liste könnte mit einer Do Loop ... Until-Schleife durchlaufen werden (wiein Lösung 1) oder indem die Anzahl der vorhandenen Zellen bestimmt werden.Letzteres ist eleganter:
Sub NeuerFilm1()Dim xlsBereich As RangeDim iZeilen As IntegerDim strNeuTitel As StringDim curNeuPreis As Currency
ThisWorkbook.Sheets("Almodóvar").ActivateActiveSheet.[A1].Activate
Set xlsBereich = ActiveSheet.[A1].CurrentRegioniZeilen = xlsBereich.Rows.Count
strNeuTitel = InputBox("Wie lautet der Name " & _ "des neuen Films?")
245
13 Excel
curNeuPreis = InputBox("Und was kostet " & strNeuTitel & "?")
With ActiveCell .Offset(iZeilen, 0).Value = 100 + iZeilen .Offset(iZeilen, 1).Value = strNeuTitel .Offset(iZeilen, 2).Value = curNeuPreisEnd With
End Sub
Auch dieses Beispiel funktioniert »indirekt«, das heißt über Objektzugriff:
Sub NeuerFilm2()Dim xlDatei As WorkbookDim xlTabelle As WorksheetDim xlZelle As RangeDim intZeilen As IntegerDim strNeuTitel As StringDim curNeuPreis As Currency
Set xlDatei = ActiveWorkbookSet xlTabelle = xlDatei.Sheets("Hitchcock")Set xlZelle = xlTabelle.Range("A1")Set xlsBereich = xlZelle.CurrentRegion
intZeilen = xlsBereich.Rows.Count
strNeuTitel = InputBox("Wie lautet der Name " & _ "des neuen Films?")curNeuPreis = InputBox("Und was kostet " & strNeuTitel & "?")
With xlZelle .Offset(intZeilen, 0).Value = 100 + intZeilen .Offset(intZeilen, 1).Value = strNeuTitel .Offset(intZeilen, 2).Value = curNeuPreisEnd With
End Sub
Lösung 3
Sub ListenVergleichen()Dim xlsDatei1 As WorkbookDim xlsDatei2 As WorkbookDim xlsFenster As WorkbookDim iDatensätze1 As IntegerDim iDatensätze2 As IntegerDim iZähler1 As IntegerDim iZähler2 As Integer
246
Lösungen
For Each xlsFenster In Workbooks If xlsFenster.Name = "Namensliste1.xls" Then Set xlsDatei1 = xlsFenster ElseIf xlsFenster.Name = "Namensliste2.xls" Then Set xlsDatei2 = xlsFenster End IfNext
If TypeName(xlsDatei1) = "Nothing" Or _ TypeName(xlsDatei2) = "Nothing" Then MsgBox "Eine der beiden Dateien sind nicht geöffnet. " & _ vbCr & "Bitte erst öffnen!", vbCritical, "Achtung!" Exit SubEnd If
xlsDatei1.Worksheets(1).Range("A1").CurrentRegion.Sort _ Key1:=xlsDatei1.Worksheets(1).Range("A1"), _ Order1:=xlAscending, _ Header:=xlYes, OrderCustom:=1, MatchCase:=False, _ Orientation:=xlTopToBottomxlsDatei2.Worksheets(1).Range("A1").CurrentRegion.Sort _ Key1:=xlsDatei2.Worksheets(1).Range("A1"), _ Order1:=xlAscending, _ Header:=xlYes, OrderCustom:=1, MatchCase:=False, _ Orientation:=xlTopToBottom
iDatensätze1 = xlsDatei1.Sheets(1).Range("A1"). _ CurrentRegion.Rows.CountiDatensätze2 = xlsDatei2.Sheets(1).Range("A1"). _ CurrentRegion.Rows.Count
For iZähler1 = 1 To iDatensätze1
For iZähler2 = 1 To iDatensätze2
If xlsDatei1.Sheets(1).Range("A1"). _ Offset(iZähler1, 0).Value = xlsDatei2.Sheets(1). _ Range("A1").Offset(iZähler2, 0).Value Then xlsDatei1.Sheets(1).Range("A1"). _ Offset(iZähler1, 0).Font.ColorIndex = 3 Exit For End If
Next
Next
247
13 Excel
For iZähler2 = 1 To iDatensätze2
For iZähler1 = 1 To iDatensätze1
If xlsDatei2.Sheets(1).Range("A1"). _ Offset(iZähler2, 0).Value = xlsDatei1.Sheets(1). _ Range("A1").Offset(iZähler1, 0).Value Then xlsDatei2.Sheets(1).Range("A1"). _ Offset(iZähler2, 0).Font.ColorIndex = 3 Exit For End If
Next
Next
End Sub
Lösung 4
Sub FormelKopieren1()Dim strFormel As StringstrFormel = ActiveSheet.Range("C1").FormulaActiveSheet.Range("F7").Value = strFormelEnd Sub
Oder kürzer:
Sub FormelKopieren2()ActiveSheet.Range("F7").Value = _ ActiveSheet.Range("C1").FormulaEnd Sub
Lösung 5
Sub SummeErzeugen()Dim xlBlatt As Worksheet
For Each xlBlatt In Worksheets xlBlatt.Range("C27").FormulaLocal = "=Summe(C1:C26)"NextEnd Sub
Lösung 6
Sub BezugAufVorherigesBlatt()Dim intZähler As IntegerFor intZähler = 2 To ActiveWorkbook.Sheets.CountActiveWorkbook.Sheets(intZähler).Range("A1").Formula = _
248
Diagramme
"=" & ActiveWorkbook.Sheets(intZähler – 1).Name & "!R37"NextEnd Sub
Statt der Eigenschaft Formula kann auch FormulaLocal verwendet werden.
13.11 DiagrammeDiagramme sind sicherlich der Teil von Excel-VBA, der am mühevollsten zu pro-grammieren ist. Der Grund liegt in den vielen Dutzend Eigenschaften, die es beider Diagrammprogrammierung gibt. Sie sollen an dieser Stelle nicht einzelnaufgelistet werden (man findet sie in der Hilfe), sondern an einem Beispiel de-monstriert werden.
Gewiss erinnern Sie sich noch an die Schulzeit. Dort musste man in der Mittel-und Oberstufe Diagramme zeichnen: Graphen. Ausgehend von einer Werte-menge wurde zu jedem Datenpunkt der entsprechende Funktionswert ermit-telt, diese wurden in ein Koordinatensystem eingetragen und dann verbunden.Das Ergebnis war ein Diagramm. So etwas soll Excel nun erledigen. In einer Ta-belle werden die x-Werte eingetragen und die entsprechenden Funktionswertedazu berechnet.
Um ein Diagramm zu erzeugen, genügt es, wenn der Cursor innerhalb einerder Spalten auf einer Zelle sitzt (es gilt auch hier: CurrentRegion). Man kann dieSpalten allerdings auch markieren, um ein Diagramm zu basteln. Ein Klick aufdas Symbol für den Diagramm-Assistenten oder das Menü EINFÜGEN / DIA-GRAMM öffnet den Diagramm-Assistenten. Soll ein Graph dargestellt werden,ist der Typ »Linie« zu wählen.
Achtung: Zu jedem Diagrammtyp, der auf der linken Seite ausgewählt wird,existieren Diagrammuntertypen. Sie werden auf der rechten Seite des Dialogseingestellt.
Ein Klick auf die Schaltfläche »Weiter« führt zum zweiten Schritt. Die Funktionsieht schon ganz ordentlich aus, allerdings interpretiert der Assistent die x-Werte als Datenreihe. Dies muss im Blatt »Reihe« geändert werden. Die x-Da-tenreihe wird entfernt. Die Werte sollten im Textfeld »Beschriftung der Rubri-kenachse« eingetragen werden.
Ein Klick auf »Weiter« führt zum dritten Schritt, wo man Titel, Achsen, Gitter-netzlinien und Legende ein- oder ausschalten kann. Im vierten Schritt wird le-diglich festgelegt, ob das Diagramm als Objekt auf das Tabellenblatt eingefügtwerden soll.
Das fertige Diagramm kann (sollte) schließlich noch bearbeitet werden. Das all-gemeine Vorgehen besteht darin, dass man das zu bearbeitende Element desDiagramms anklickt und danach mit einem Doppelklick, mit der rechten Maus-taste oder über das Menü FORMAT weiterverarbeitet. Ist beispielsweise die
249
13 Excel
Schriftgröße der y-Achse zu groß, so kann dies im Registerblatt »Schrift« derRubrikenachse geändert werden. Soll die Schrift der Legende geändert werden,dann führt ein Doppelklick zu dem entsprechenden Dialog, in dem alle Optio-nen eingestellt werden können. Will man die Farbe des Graphen verändern, sogibt es auch dafür einen Formatierungsdialog. Die Hintergrundfarbe der Zeich-nungsfläche kann ebenfalls an der entsprechenden Stelle abgeändert werden.
Ein Problem kann die Skalierung der x-Achse darstellen, da diese an keinerStelle exakt eingestellt werden kann. Dagegen kann die Skalierung der y-Achsemodifiziert werden. Die Rubrikenachse (y-Achse) hat im Format-Dialog ein Re-gisterblatt »Skalierung«, in dem man Haupt- und Teilintervalle, Höchst- undTiefstwert verändern kann. Dies ist bei einigen Funktionen wichtig, da Excel ei-nen Algorithmus hat, der das Intervall für die y-Achse automatisch vorgibt.Excel geht dabei von dem größten Wert aus, der im Wertebereich gefundenwird. Gerade Funktionen, deren Werte asymptotisch gegen ∞ gehen, müssenauf einen Bereich begrenzt werden. Im Registerblatt »Muster« können Eigen-schaften der y-Achse, wie die Teilstriche und deren Beschriftung, ein- und aus-geschaltet werden.
Problematisch sind Funktionen, die gegen eine Asymptote streben – von der ei-nen Seite gegen +∞, auf der anderen Seite gegen -∞, wie beispielsweise sin/cos= tan. Das Diagramm verbindet automatisch den sehr großen positiven mit demsehr kleinen negativen Wert, so dass von +∞ eine Verbindungslinie nach -∞ ge-zogen wird. Diese muss ausgeschaltet werden. Ein Klick im Diagramm auf denGraphen der Funktion markiert alle Datenpunkte. Ein weiterer Klick auf denGraphen markiert nur einen Datenpunkt. Wenn Sie ihn nicht finden, so könnenSie sich ebenfalls mit den Pfeiltasten nach links oder rechts über alle Daten-punkte, oder genauer über alle Elemente des Diagramms, bewegen. Ist der Da-tenpunkt gefunden, das heißt markiert, dann kann er gelöscht oder »wegfor-matiert« werden, das heißt, man versieht ihn mit der Farbe »Ohne«. Sie können
Abbildung 13.1:Eine Potenzfunktion
(e-(1/x²))
250
Diagramme
den Datenpunkt aber auch einfach über die Taste (Entf) löschen. Sollten SieSchwierigkeiten haben, den Doppelklick richtig zu platzieren, dann können Sieauch über das Menü FORMAT – MARKIERTER DATENPUNKT zum entsprechen-den Dialog gelangen.
Damit nicht jedes Mal, wenn ein neues Diagramm erstellt wird, der Assistentvon neuem bemüht werden muss, beziehungsweise das Diagramm auf die glei-che Art und Weise »nachformatiert« werden muss, kann der Prozess der Dia-grammerstellung und der Nachbearbeitung mit dem Makrorekorder aufge-zeichnet werden. Der Code beginnt etwa wie folgt:
Sub Graph()Charts.Add ActiveChart.ChartType = xlLine ActiveChart.SetSourceData _Source:=Sheets("Tabelle1").Range("A1:B62"), PlotBy _ :=xlColumnsActiveChart.SeriesCollection(1).Delete ActiveChart.SeriesCollection(1).Xvalues = _"=Tabelle8!R1C1:R62C1" ActiveChart.Location Where:=xlLocationAsObject, _Name:="Tabelle8" ActiveChart.ApplyDataLabels _ Type:=xlDataLabelsShowNone, LegendKey:=False ActiveSheet.Shapes("Diagramm 1").ScaleWidth 1.4, _msoFalse, msoScaleFromTopLeft ActiveSheet.Shapes("Diagramm 1").ScaleHeight 1.41, _msoFalse, msoScaleFromBottomRight ActiveSheet.Shapes("Diagramm 1").ScaleWidth 1.21, _msoFalse, msoScaleFromBottomRight ActiveSheet.Shapes("Diagramm 1").ScaleHeight 1.3, _msoFalse, msoScaleFromTopLeft ActiveChart.PlotArea.Select[...]End Sub
An dieser Stelle wird abgebrochen, da Sie den Code am eigenen PC selbst ein-sehen können, nachdem Sie die Diagrammerstellung aufgezeichnet haben.Dieser Code kann und sollte modifiziert werden. Im Folgenden werden diewichtigsten Befehle, Methoden und Eigenschaften aufgelistet, mit denen einDiagramm erstellt werden kann.
Die Sammlung der Diagramme lautet Charts. Wird ein neues Diagramm er-zeugt, dann muss der Befehl mit folgenden optionalen Parametern
Charts.Add(Before, After, Count, Type)
verwendet werden.
251
13 Excel
Wird das Diagramm auf einem Tabellenblatt eingefügt, dann können vier Para-meter bei folgender Methode angegeben werden:
Activesheet.ChartObjects.Add(Left, Top, Width, Height)
Mit Chart und ChartObject wird allerdings nicht das Diagramm bezeichnet,sondern lediglich der Rahmen, der später das Diagramm halten wird. Das Ob-jekt ChartObject hat folgende Eigenschaften:
Height und Width, Left und Top, Shadow und RoundedCorners und Name, überden es angesprochen werden kann. Ihm stehen die Methoden Activate, Selectund Delete, BringToFront und SendToBack, Copy, Cut und Duplicate zur Verfü-gung. Das eigentliche Objekt ist jedoch
Chart
Dabei besitzt das Diagramm folgende Eigenschaften und Methoden:
SetSourceData(Source, PlotBy)
legt die Quelle (Source) der Daten fest und bezeichnet, ob sie nach Spalten (xl-Columns) oder nach Zeilen (xlRows) gelesen werden.
ChartType
legt den Diagrammtyp fest. Dabei stehen folgende Werte zur Verfügung:
Tab. 13.1:Die verschiedenen
Diagrammtypen
Diagrammtyp Beschreibung Konstante
Säulen-diagramm
Säulen (gruppiert) xlColumnClustered
3D-Säulen (gruppiert) xl3DColumnClustered
Gestapelte Säulen. Vergleicht die Bei-träge einzelner Werte mit dem Ge-samtwert aller Kategorien.
xlColumnStacked
3D-Gestapelte Säulen. Vergleicht die Beiträge einzelner Werte mit dem Ge-samtwert aller Kategorien.
xl3DColumnStacked
Säulen (100%, gestapelt) xlColumnStacked100
3D-Säulen (100%, gestapelt) xl3DColumnStacked100
3D-Säulen xl3DColumn
Balken-diagramm
Balken (gruppiert) xlBarClustered
3D-Balken (gruppiert) xl3DBarClustered
Balken (gestapelt) xlBarStacked
3D-Balken (gestapelt) xl3DBarStacked
Balken (100%, gestapelt) xlBarStacked100
3D-Balken (100%, gestapelt) xl3DBarStacked100
252
Diagramme
Liniendiagramm Linie xlLine
Linien mit Datenpunkten xlLineMarkers
Linien (gestapelt) xlLineStacked
Linien (gestapelt) mit Datenpunkten xlLineMarkersStacked
Linien (100%, gestapelt) xlLineStacked100
Linien (100%, gestapelt, mit Daten-punkten)
xlLineMarkersStacked100
3D-Linien xl3DLine
Kreisdiagramm Kreis xlPie
Kreis (explodiert) xlPieExploded
3D-Kreis xl3DPie
3D-Kreis (explodiert) xl3DPieExploded
Kreis aus Kreis xlPieOfPie
Balken aus Kreis xlBarOfPie
Punkt (XY)-Dia-gramm
Punkte xlXYScatter
Punkte mit interpolierten Linien xlXYScatterSmooth
Punkte mit interpolierten Linien ohne Datenpunkte
xlXYScatterSmoothNo-Markers
Punkte mit Linien xlXYScatterLines
Punkte mit Linien ohne Datenpunkte xlXYScatterLinesNo-Markers
Blasendiagramm Blasen xlBubble
Blasen mit 3D-Effekt xlBubble3DEffect
Flächen-diagramm
Flächen xlArea
3D-Flächen xl3DArea
Flächen (gestapelt) xlAreaStacked
3D-Flächen (gestapelt) xl3DAreaStacked
Flächen (100%, gestapelt) xlAreaStacked100
3D-Flächen (100%, gestapelt) xl3DAreaStacked100
Ringdiagramm Ring xlDoughnut
Ring (explodiert) xlDoughnutExploded
Netzdiagramm Netz xlRadar
Netz mit Datenpunkten xlRadarMarkers
Netz (gefüllt) xlRadarFilled
Diagrammtyp Beschreibung Konstante
253
13 Excel
Oberflächen-diagramm
3D-Oberfläche xlSurface
Oberfläche (Draufsicht) xlSurfaceTopView
3D-Oberfläche (Drahtmodell) xlSurfaceWireframe
Oberfläche (Draufsicht, Drahtmodell) xlSurfaceTopViewWire-frame
Kursdiagramm Höchst-Tiefst-Geschlossen xlStockHLC
Volumen-Höchst-Tiefst-Geschlossen xlStockVHLC
Geöffnet-Höchst-Tiefst-Geschlossen xlStockOHLC
Volumen-Öffnung-Höchst-Tiefst-Ge-schlossen
xlStockVOHLC
Zylinder-diagramm
Zylindersäulen (gruppiert) xlCylinderColClustered
Zylinderbalken (gruppiert) xlCylinderBarClustered
Zylindersäulen (gestapelt) xlCylinderColStacked
Zylinderbalken (gestapelt) xlCylinderBarStacked
Zylindersäulen (100%, gestapelt) xlCylinderColStacked100
Zylinderbalken (100%, gestapelt) xlCylinderBarStacked100
3D-Zylindersäulen xlCylinderCol
Kegeldiagramm Kegelsäulen (gruppiert) xlConeColClustered
Kegelbalken (gruppiert) xlConeBarClustered
Kegelsäulen (gestapelt) xlConeColStacked
Kegelbalken (gestapelt) xlConeBarStacked
Kegelsäulen (100%, gestapelt) xlConeColStacked100
Kegelbalken (100%, gestapelt) xlConeBarStacked100
3D-Kegelsäulen xlConeCol
Pyramiden-diagramm
Pyramidensäulen (gruppiert) xlPyramidColClustered
Pyramidenbalken (gruppiert) xlPyramidBarClustered
Pyramidensäulen (gestapelt) xlPyramidColStacked
Pyramidenbalken (gestapelt) xlPyramidBarStacked
Pyramidensäulen (100%, gestapelt) xlPyramidColStacked100
Pyramidenbalken (100%, gestapelt) xlPyramidBarStacked100
3D-Pyramidensäulen xlPyramidCol
Diagrammtyp Beschreibung Konstante
254
Diagramme
Das Diagramm besitzt folgende Elemente als Eigenschaften:
Tab. 13.2: Die Eigenschaften des Diagramms
Um auf die Achsen zugreifen zu können, muss die Methode Axes(Type, Axis-Group) verwendet werden. Dabei ist Type der Achsentyp und AxisGroup dieAchsengruppe. Type kann eine der folgenden Konstanten annehmen: xlCate-gory, xlSeriesAxis (nur bei 3D-Diagrammen) oder xlValue. AxisGroup kanneine der folgenden Konstanten sein: xlPrimary oder xlSecondary. 3D-Dia-gramme haben nur eine Achsengruppe.
Daneben verfügt das Diagramm über einige Methoden, über die man wie-derum auf weitere Elemente des Diagramms zugreifen kann:
Tab. 13.3: Die Methoden des Diagramms, mit denen auf zwei-dimensionale Grup-pen zugegriffen werden kann.
Es existiert noch eine Reihe weiterer Eigenschaften und Methoden, die auf dasDiagramm angewendet werden können. Hier einige davon:
Tab. 13.4: Weitere Eigen-schaften und Methoden des Diagramms
Eigenschaft Bezeichnung
Legende Legend
Diagrammfläche ChartArea
Titel ChartTitle
Ecken Corners
Datentabelle DataTable
PlotArea Zeichnungsfläche
Wände Walls
Diagrammgruppen Area3DgroupBar3DgroupColumn3DgroupLine3DgroupPie3Dgroup
Methode Bezeichnung
2D-Flächendiagrammgruppe AreaGroups
2D-Ringdiagrammgruppe DoughnutGroups
2D-Liniendiagrammgruppe LineGroups
2D-Kreisdiagrammgruppe PieGroups
2D-Netzdiagrammgruppe RadarGroups
2D-Punktdiagrammgruppe XYGroups
Eigenschaft/Methode Beschreibung
BarShape Die Form der 3D-Säulen oder -Balken. Gültige Konstanten sind:xlBox, xlConeToMax, xlConeToPoint, xlCylinder, xlPyramid-ToMax, xlPyramidToPoint
DepthPercent Die Tiefe des 3D-Diagramms
255
13 Excel
Es ließen sich noch viele Seiten mit Beschreibungen der einzelnen Objekte, Ei-genschaften und Methoden füllen; doch das ist nicht die Aufgabe des vorlie-genden Buchs. Vielmehr soll an einem Beispiel gezeigt werden, wie aus einerSpalte »Werte« und einer zweiten Spalte »Funktionswerte« ein Liniendia-gramm generiert werden kann. Da es sich um ein langes Codebeispiel handelt,sind die einzelnen Blöcke kommentiert.
Sub Graph()Dim xlDia As ChartDim xlZelle As Range
On Error Resume Next
'Es wird überprüft, ob sich der Cursor'auf einem Tabellenblatt befindetIf ActiveWorkbook.ActiveSheet.Type <> xlWorksheet Then MsgBox "Der Cursor sitzt nicht in einer Tabelle", _ vbExclamation, "Achtung" Exit SubEnd If
'Es wird überprüft, ob sich der Cursor'im Zahlenbereich befindetSet xlZelle = ActiveCellIf xlZelle.CurrentRegion.Rows.Count < 3 Then MsgBox "Bitte den Cursor korrekt platzieren!", _ vbExclamation, "Achtung!" Exit Sub
DisplayBlankAs Darstellung leerer Zeilen. Gültige Konstanten sind:xlNotPlotted, xlInterpolated, xlZero
Elevation Betrachtungshöhe eines 3D-Diagramms
HasAxis Information über das Vorhandensein einer bestimmten Achse
HasDataTable »True«, wenn eine Datentabelle vorhanden ist
HasLegend »True«, wenn eine Legende vorhanden ist
HasTitle »True«, wenn ein Titel vorhanden ist
HeightPecent Die Höhe eines 3D-Diagramms als relativer Prozentsatz der Breite
Perspective Perspektive des 3D-Diagramms
ProtectContents »True«, wenn das Diagramm geschützt ist
Rotation Die Drehung eines 3D-Diagramms
Visible »True«, wenn das Diagramm sichtbar ist
Eigenschaft/Methode Beschreibung
256
Diagramme
End If
'ein neues DiagrammSet xlDia = Charts.AddWith xlDia .ChartType = xlLine 'ein Liniendiagramm .SetSourceData Source:=xlZelle.CurrentRegion, _ PlotBy:=xlColumns .SeriesCollection(1).Delete .SeriesCollection(1).XValues = _ xlZelle.CurrentRegion.Columns(1)End With
With xlDia'die Elemente werden festgelegt .HasAxis(xlValue, xlPrimary) = True .HasAxis(xlCategory) = True .Axes(xlValue).HasMajorGridlines = True .Axes(xlCategory).HasMajorGridlines = False .HasDataTable = False .HasLegend = True .HasPivotFields = False .HasTitle = True .Visible = xlSheetVisible
'Gitternetzlinien: With .Axes(xlValue).MajorGridlines.Border .ColorIndex = 1 .LineStyle = xlContinuous .Weight = xlThin End With
'keine Farbe für die Diagrammfläche With .PlotArea .Interior.ColorIndex = xlNone'eine Linie für das Diagramm With .Border .ColorIndex = 1 .LineStyle = xlContinuous .Weight = xlThin End With End With
'keine Farbe für die Zeichnungsfläche With .ChartArea'eine Linie für die Zeichnungsfläche
257
13 Excel
.Interior.ColorIndex = xlNone With .Border .ColorIndex = 1 .LineStyle = xlContinuous .Weight = xlThin End With End With
'die Diagrammlinie With .SeriesCollection(1)'keine Werte, keine Datenpunkte .HasDataLabels = False .MarkerStyle = xlMarkerStyleNone'die Linienfarbe und -formatierung With .Border .ColorIndex = 1 .Weight = xlThin .LineStyle = xlContinuous End With End With
'Beschriftung und Größe der x-Achse With .Axes(xlCategory) .HasTitle = True .AxisTitle.Caption = "x"
With .Border .ColorIndex = 1 .Weight = xlThin .LineStyle = xlContinuous End With .TickLabels.Orientation = xlHorizontal With .TickLabels.Font .Name = "Arial" .FontStyle = "Standard" .Size = 8 End With End With
'Beschriftung und Größe der y-Achse With .Axes(xlValue) .HasTitle = True .AxisTitle.Caption = "y" With .Border .ColorIndex = 1 .Weight = xlThin .LineStyle = xlContinuous
258
Diagramme
End With .TickLabels.Orientation = xlHorizontal With .TickLabels.Font .Name = "Arial" .FontStyle = "Standard" .Size = 8 End With End With
'die Formatierung der Legende With .Legend.Font .Name = "Arial" .FontStyle = "Standard" .Size = 8 End With
'die Formatierung des Titels With .ChartTitle .Caption = "Funktionen" With .Font .Name = "Arial" .FontStyle = "Bold" .Size = 14 End With End With
.Deselect
End With
End Sub
Abbildung 13.2: Eine Schwingungs-funktion (x²*sin(1/x)
259
13 Excel
Viele der verwendeten Befehle sind überflüssig, da man auch die Standardein-stellung von Excel verwenden könnte. Allerdings kann in einem Projekt nicht si-chergestellt sein, dass der Benutzer nicht einige Grundeinstellungen geänderthat. Dann würde er ein anderes Diagramm erhalten.
Und so können alle mathematischen Funktionen (auch für technische, physika-lische, chemische ... Prozesse) dargestellt werden, dazu zählen zum Beispielganzrationale Funktionen, rationale Funktionen oder Absolutfunktionen, Po-tenzfunktionen, Schwingungsfunktionen und Algebraische Funktionen.
Übung 1
Wie muss der Code aus dem obenstehenden Beispiel modifiziert werden, damiter nicht nur für eine Funktion, sondern gleich für mehrere Funktionen verwen-det werden kann?
Übung 2
Wie muss der Code aus dem obenstehenden Beispiel modifiziert werden, damitdas Diagramm nicht als eigenes Blatt sondern als Objekt auf dem Tabellenblattangezeigt wird?
Übung 3
Das Diagramm aus Übung 2 hat einen Nachteil: Diagrammfläche und Zeich-nungsfläche sind transparent. Was muss geändert werden, damit diese beidenFlächen weiß formatiert sind?
Übung 4
Einige Funktionen streben asymptotisch gegen ∞. Skalieren Sie den Wertebe-reich zwischen -5 und +5.
Übung 5
Der Tangens bewegt sich bei Vielfachen von π/2 asymptotisch gegen +∞ vonlinks und gegen -∞ von rechts. Finden Sie in den Werten die Sprünge herausund formatieren Sie sie weg (xlNone).
13.12 Übungen
260
Tipps
Tipp zu Übung 1
Überprüfen Sie, wo im Code lediglich auf zwei Spalten zugegriffen wird!
Tipp zu Übung 3 und 4
Dieser Befehl kann per Makrorekorder ermittelt werden.
Tipp zu Übung 5
Für die Lösung dieser Aufgabe muss ein Zähler jeweils zwei übereinanderlie-gende Werte miteinander vergleichen. Ist das Produkt negativ und kleiner einebestimmte Zahl (beispielsweise 30), dann wird dieser Datenpunkt wegforma-tiert.
Lösung 1
Der Code kann auch für mehrere Funktionen verwendet werden, da an keinerStelle explizit auf die zweite Spalte für die y-Werte Bezug genommen wird.
Lösung 2
Es wird ein weiteres Objekt deklariert:
Dim xlChart As ChartObject
Damit wird das Diagramm erzeugt:
[...]Set xlChart = ActiveSheet.ChartObjects.Add(100, 50, 600, 350)Set xlDia = xlChart.Chart[...]
Der Rest des Codes kann bleiben.
Lösung 3
Dazu muss geändert werden:
With .PlotArea .Interior = xlSolid .Interior.ColorIndex = 2[...]End With
13.13 Tipps
13.14 Lösungen
261
13 Excel
With .ChartArea .Interior = xlSolid .Interior.ColorIndex = 2[...]
Lösung 4
With ActiveChart.Axes(xlValue) .MinimumScale = -5 .MaximumScale = 5[...]
Lösung 5
Die größte Schwierigkeit dürfte hierbei das Durchlaufen und das Überprüfender Zellen sein. Ist die Zeile und die Spalte gefunden, so kann die Linieneigen-schaft auf xlNone gesetzt werden. Die Lösung wurde in einer zweiten Prozedurausgelagert:
Sub UnendlichEntfernen(xlDia As Chart, xlZelle As Range)Dim intZeilen As IntegerDim intSpalten As IntegerDim i As IntegerDim j As IntegerDim dblProdukt As Double
intZeilen = xlZelle.CurrentRegion.Rows.CountintSpalten = xlZelle.CurrentRegion.Columns.Count
For i = 2 To intSpalten For j = 3 To intZeilen dblProdukt = xlZelle.CurrentRegion.Cells(j, i).Value * _ xlZelle.CurrentRegion.Cells(j – 1, i).Value If dblProdukt < -30 Then xlDia.SeriesCollection(i – 1). _ Points(j – 1).Border.LineStyle = xlNone End If Next jNext i
End Sub
Diese Prozedur wird am Ende der anderen Routine aufgerufen:
UnendlichEntfernen xlDia, xlZelle
262
Ereignisse in Excel
13.15 Ereignisse in ExcelIm Projekt der Arbeitsmappe stehen zwei verschiedene Objekttypen zur Verfü-gung. Das »oberste« Objekt »DieseArbeitsmappe« und die einzelnen Tabellen.Die Mappe besitzt folgende Ereignisse:
Activate(), AddinInstall(), AddinUninstall(), BeforeClose(Cancel As Boolean), BeforePrint(Cancel As Boolean), BeforeSave(ByVal SaveAsUI As Boolean, Cancel As Boolean), Deactivate(), NewSheet(ByVal Sh As Object), Open(), SheetActivate(ByVal Sh As Object), SheetBeforeDoubleClick(ByVal Sh As Object, ByVal Target As Range, Cancel As Boolean), SheetBeforeRightClick(ByVal Sh As Object, ByVal Target As Range, Cancel As Boolean), SheetCalculate(ByVal Sh As Object), SheetChange(ByVal Sh As Object, ByVal Target As Range), SheetDeactivate(ByVal Sh As Object), SheetFollowHyperlink(ByVal Sh As Object, ByVal Target As Hyperlink), SheetSelectionChange(ByVal Sh As Object, ByVal Target As Range), WindowActivate(ByVal Wn As Window), WindowDeactivate(ByVal Wn As Window), WindowResize(ByVal Wn As Window)
Für ein einzelnes Tabellenblatt liegen die nachfolgenden acht Ereignisse vor:
Activate(), BeforeDoubleClick(ByVal Target As Range, Cancel As Boolean), BeforeRightClick(ByVal Target As Range, Cancel As Boolean), Calculate(), Change(ByVal Target As Range), Deactivate(), FollowHyperlink(ByVal Target As Hyperlink), SelectionChange(ByVal Target As Range)
Abbildung 13.3: Trigonometrische Funktionen
263
13 Excel
Daneben kann mit den vier Methoden
Application.OnKeyApplication.OnRepeatApplication.OnTimeApplication.OnUndo
per Programmierung auf weitere Ereignisse reagiert werden.
Übung 1
Ein Klick auf das letzte Tabellenblatt soll bewirken, dass auf das erste Blatt zu-rückgesprungen wird.
Übung 2
In der Spalte C kann ein Benutzer verschiedene Werte eintragen. Die Summedavon wird in der Zelle D1 als Wert gespeichert. Schreibt der Benutzer also inC1 den Wert 13, dann steht in D1 13. Wird der Wert in C1 mit 7 überschrieben,dann steht in D1 20.
Übung 3
Beim Öffnen einer Datei wird eine Userform geöffnet.
Übung 4
Beim Schließen der Datei wird eine Sicherheitskopie der Datei in dem OrdnerC:\Eigene Dateien\Sicherung unter dem Dateinamen plus dem aktuellen Datumerzeugt.
Lösung 1
Damit sich der Benutzer nicht wundert, sollte das Tabellenblatt umbenanntwerden (beispielsweise in »<<Zurück«). Im VBA-Editor wird das Blatt dieserMappe ausgewählt, dem Objekt »Worksheet« wird das Ereignis Activate zuge-wiesen. Der Befehl lautet:
Worksheets(1).Activate
13.16 Übungen
13.17 Lösungen
264
Lösungen
Damit ist der Fehler ausgeschlossen, wenn der Benutzer das erste Blatt umbe-nennt oder das erste Blatt verschiebt (dann wäre es nicht mehr das erste Blatt).Angesprungen wird immer die Nummer 1.
Private Sub Worksheet_Activate() Worksheets(1).ActivateEnd Sub
Lösung 2
Im entsprechenden Arbeitsblatt wird folgender Code im Ereignis Worksheet_Change eingegeben:
Private Sub Worksheet_Change(ByVal Target As Range)If Target.Column = 3 Then If IsNumeric(Target.Value) Then ActiveSheet.Range("D1").Value = _ ActiveSheet.Range("D1").Value _ + Target.Value End IfEnd IfEnd Sub
Lösung 3
Private Sub Workbook_Open() frmEingabeMaske.ShowEnd Sub
Lösung 4
Private Sub Workbook_BeforeClose(Cancel As Boolean)Application.ActiveWorkbook.SaveCopyAs _ Filename:="c:\Eigene Dateien\" & _ Left(ActiveWorkbook.Name, Len(ActiveWorkbook.Name) – 4) _ & Format(Date, "DDMMYY") & ".xls"End Sub
Achtung: Wenn Sie die Sicherungskopie öffnen und die Makros aktivieren,dann enthält diese Datei die gleichen Makros wie die Ursprungsdatei und damitauch das Workbook_BeforeClose-Makro. Wird nun die Sicherungsdatei ge-schlossen, dann wird diese Datei unter ihrem Namen plus dem Datum gespei-chert. So wird also aus »Test070600.xls« die Datei »Test070600070600.xls«.
265
13 Excel
13.18 Einige nützliche, erstaunliche und lustige Befehle
Einige der Befehle, die in VBA für Word verwendet wurden, könnten auch hierstehen. Dazu zählen: Application.Caption und Application.Dialogs. Alle übri-gen sind Word-spezifisch. An dieser Stelle soll erläutert werden, wie Makros ausanderen Dateien verwendet werden können und wie man Makros in andereDateien schreiben kann. Diese Befehle können auch in Word verwendet wer-den.
13.18.1 Starten von Makros aus anderen Dateien
Mit der Run-Methode des Application-Objekts kann ein Makro aus einer ande-ren Excel-Datei gestartet werden. Das folgende Beispiel öffnet eine Datei, star-tet das Makro und schließt die Datei wieder:
Sub FremderZugriff()Application.Workbooks.Open _ "c:\Eigene Dateien\Excel\Test.xls"Application.Run "Test.xls!Versuch"Application.Workbooks("Test.xls").CloseEnd Sub
In VBA in Office 97 gab es den Befehl
Options.VirusProtection
mit dem der Makrovirusschutz per Makro ausgeschaltet werden konnte. DieserBefehl steht glücklicherweise in Office 2000 nicht mehr zur Verfügung. Leiderfunktioniert der Befehl SendKeys dafür!
13.18.2 Lesen und Schreiben von Makros aus/in andere Dateien
Aus einer anderen Datei können auf alle Speicherorte für Makros zugegriffenwerden. Hierzu steht die Eigenschaft VBProject zur Verfügung. Sie enthält dieVBComponents. Das folgende Makro listet alle Speicherorte, Mappe, Tabellen-blätter, Module, Klassen und Formulare auf:
Sub MakroSpeicherortListe()Dim xlMappe As WorkbookSet xlMappe = Application.Workbooks("Test.xls")For i = 1 To xlMappe.VBProject.VBComponents.Count strliste = strliste & vbCr & _ xlMappe.VBProject.VBComponents(i).NameNext
266
Einige nützliche, erstaunliche und lustige Befehle
MsgBox strliste
End Sub
Nun kann auf eines der Module zugegriffen werden. Das folgende Makro zähltdie Deklarationszeilen und die Befehlszeilen in Modul1:
Sub MakrosAuflisten()Dim xlMappe As WorkbookSet xlMappe = Application.Workbooks("Test.xls")With xlMappe.VBProject.VBComponents("Modul1").CodeModule MsgBox .CountOfLines MsgBox .CountOfDeclarationLinesEnd WithEnd Sub
Das folgende Makro liest alle Codezeilen aus:
Sub MakrosLesen()Dim xlMappe As WorkbookDim i As IntegerSet xlMappe = Application.Workbooks("Test.xls")With xlMappe.VBProject.VBComponents _ ("Modul1").CodeModule i = .CountOfLines MsgBox .Lines(1, i)End WithEnd Sub
Leider kann man nicht den Code aus geschützten Projekten auslesen.
Module können auch per Programmierung erzeugt werden. Das folgendeMakro erzeugt ein neues Modul und gibt ihm einen Namen:
Sub NeuesModul()Dim xlMappe As WorkbookDim xlModul As VBComponentSet xlMappe = Application.Workbooks("Test.xls")Set xlModul = _ xlMappe.VBProject.VBComponents.Add(vbext_ct_StdModule)xlModul.Name = "Wuschi" & _ xlMappe.VBProject.VBComponents.CountEnd Sub
Das folgende Makro schreibt Code in Modul1. Dafür wird der Befehl InsertLinesverwendet. Er verlangt zwei Werte: die Position der neuen Codezeile und denCode als Zeichenkette.
267
13 Excel
Sub MakrosNeuSchreiben()Dim xlMappe As WorkbookSet xlMappe = Application.Workbooks("Test.xls")With xlMappe.VBProject.VBComponents("Modul1").CodeModule .InsertLines 1, "Sub Bösartig()" .InsertLines 2, "MsgBox ""Festplatte wird formatiert""" .InsertLines 3, "End Sub"End WithEnd Sub
Das folgende Makro erzeugt ein AutoOpen-Makro in einer anderen Datei, spei-chert diese und schließt sie:
Sub MakrosNeuSchreiben2()Dim xlMappe As WorkbookSet xlMappe = Application.Workbooks("Test.xls")With xlMappe.VBProject.VBComponents _ ("DieseArbeitsmappe").CodeModule .DeleteLines 1, .CountOfLines .InsertLines 1, "Private Sub Workbook_Open()" .InsertLines 2, "MsgBox ""Sie sind nicht berechtigt, " & _ "diese Datei zu bearbeiten."", vbCritical" .InsertLines 3, "End Sub"End WithxlMappe.SavexlMappe.CloseEnd Sub
268
Es gibt wenig Unterschiede zwischen dem Aufbau und der Hierarchie der Ob-jekte, Listen, Eigenschaften und Methoden in Powerpoint, und derer in Exceloder Word. Da die Powerpoint-Programmierung nur einen geringen Stellen-wert innerhalb der Office-Programmierung einnimmt, wird dieses Kapitel kür-zer als die beiden vorhergehenden gehalten. Auch in Powerpoint steht Ihnen,wie in Excel und Word, ein Makro-Rekorder zur Verfügung, mit dem die wich-tigsten Befehle aufgezeichnet werden können. Allerdings gelangt man bei derPowerpoint-Programmierung schnell an die Grenzen, weil viele Objekte und Ei-genschaften in Powerpoint nicht für die VBA-Programmierung zur Verfügungstehen.
14.1 Datei- und ProgrammzugriffOberstes Objekt ist Application. Ihm sind eine Reihe von weiteren Objektenuntergeordnet, wie ActivePresentation, ActiveWindow, AddIns, CommandBars,FileSearch, Windows, und andere. Aber auch Eigenschaften wie Visible undWindowState. Daneben finden sich die bekannten Eigenschaften Name und Path,die den Namen und den Pfad von Powerpoint liefern (zum Beispiel »MICROSOFT
POWERPOINT« und C:\Programme\Microsoft Office\Office). Mit Caption wirdebenfalls der Name angezeigt – mit dieser Eigenschaft kann allerdings auch derEintrag der Titelleiste geändert werden:
Application.Caption = "Winzigweich KraftPunkt"
Nützliche Methoden von Application sind Quit und Run. Die wichtigste Eigen-schaft ist Presentations – und davon wiederum die wichtigste Slides: die ein-zelnen Seiten, Folien oder Dias. Eine Präsentation kann geöffnet werden mit derMethode Open:
Application.Presentations.Open ReadOnly, Untiteld, WithWindow
Das Gegenteil ist die Methode Close:
Application.Presentations("DUCK.pot").Close
14 Powerpoint
Parameter Bedeutung
ReadOnly öffnet die Datei schreibgeschützt.
Untitled öffnet eine Kopie der Datei.
WithWindow öffnet die Datei in einem sichtbaren Fenster.
269
14 Powerpoint
und das Speichern besorgt Save, SaveAs und SaveAsCopy. Beispielsweise:
Application.Presentations("DUCK.pot").Save
oder:
ActivePresentation.Save
Eine neue Präsentation wird mit der Methode Add erzeugt:
Presentations.Add
Und schließlich wird zum Drucken die Methode PrintOut verwendet. Solltenmehrere Präsentationen geöffnet sein, dann kann über die Presentations-Sammlung oder über die Windows-Sammlung darauf zugegriffen werden. Da-bei kann die Caption eines Window-Objekts oder die Eigenschaft Name einesPresentation-Objekts abgefragt werden.
14.2 FolienEine neue Folie wird mit der Methode Add des Objekts Slides hinzugefügt. DieMethode Add benötigt zwei Parameter: die Nummer der Folie, die nicht größersein darf als die Anzahl der vorhandenen Folien + 1 und das Layout der Folie.Beides kann an eine Objektvariable übergeben werden. Beispielsweise:
ActivePresentation.Slides.Add Index:=18, _ Layout:=ppLayoutTextAndClipart
oder:
Dim ppFolie As SlideSet ppFolie = ActivePresentation.Slides.Add(18, _ ppLayoutTextAndClipart)
Die Layout-Bezeichnungen in VBA:
Tab. 14.1:Die verschiedenen
Folien in Power-point
ppLayoutTitle ppLayoutText ppLayoutTwoCo-lumnText
ppLayoutTable
ppLayoutTextAnd-Chart
ppLay-outChartAndText
ppLayoutOrgChart ppLayoutChart
ppLayoutTextAnd-Clipart
ppLayout-ClipartAndText
ppLayoutTitelOnly ppLayoutBlank
ppLayoutTextAnd-Object
ppLayout-ObjectAndText
ppLayoutLarge-Object
ppLayoutObject
ppLayoutTextAnd-MediaClip
ppLayoutMedia-ClipAndText
ppLayoutObject-OverText
ppLayoutTextOver-Object
ppLayoutTextAnd-TwoObjects
ppLayoutTwo-ObjectsAndText
ppLayoutTwo-ObjectsOverText
ppLayoutFour-Objects
270
Folienhintergründe
Daneben existieren vier weitere Layouts, die nur durch Programmierung er-zeugt werden können:
ppLayoutClipArtAndVerticalTextppLayoutVerticalTextppLayoutVerticalTitleAndTextppLayoutVerticalTitleAndTextOverChart
Die Anzahl der vorhandenen Seiten kann über die Eigenschaft Count ermitteltwerden. Damit kann ans Ende einer Präsentation eine neue Folie eingefügt wer-den:
ActivePresentation.Slides.Add _ Index:=ActivePresentation.Slides.Count + 1, _ Layout:=ppLayoutVerticalTitleAndTextOverChart
Mit der Methode Delete wird eine Folie gelöscht. Der folgende Befehl löscht dieletzte Folie der aktuellen Präsentation:
ActivePresentation.Slides(ActivePresentation.Slides.Count). _ Delete
Mit den Methoden Cut, Copy und Paste können einzelne Folien verschobenwerden und mit Duplicate dupliziert. Die Eigenschaft Name weist einer Folie ei-nen Namen zu.
14.3 FolienhintergründeEine Folie erhält mit der Eigenschaft Background.Fill einen Hintergrund:
ActivePresentation.Slides(1).Background.Fill
Allerdings benötigt die Eigenschaft Fill noch weitere Eigenschaften:
Das folgende Makro erzeugt fünf neue Folien am Beginn der Präsentation undweist ihnen verschiedene Fülleffekte zu.
Eigenschaften von Fill Bedeutung
ForeColor legt die Musterfarbe fest.
BackColor legt die Hintergrundfarbe des Musters fest.
OneColorGradient erzeugt einen Farbverlauf mit einer Farbe.
TwoColorGradient erzeugt einen zweifarbigen Farbverlauf.
Patterned legt ein Hintergrundmuster fest.
PresetGradient verwendet einen vordefinierten Verlauf für den Hinter-grund.
PresetTextured verwendet eine vordefinierte Struktur für den Hinter-grund.
271
14 Powerpoint
Sub Folienhintergründe()Dim intZähler As IntegerFor intZähler = 1 To 5 ActivePresentation.Slides.Add 1, ppLayoutBlankNext intZähler 'Die erste Folie erhält einen einfachen Hintergund With ActivePresentation.Slides(1) .FollowMasterBackground = msoFalse With .Background .Fill.ForeColor.RGB = RGB(216, 27, 221) .Fill.Solid End With End With
'Die zweite Folie erhält einen diagonalen Verlauf With ActivePresentation.Slides(2) .FollowMasterBackground = msoFalse With .Background .Fill.ForeColor.RGB = RGB(255, 51, 0) .Fill.BackColor.SchemeColor = ppAccent1 .Fill.TwoColorGradient msoGradientFromCorner, 1 End With End With
'Die dritte Folie erhält einen vordefinierten Verlauf With ActivePresentation.Slides(3) .FollowMasterBackground = msoFalse With .Background .Fill.ForeColor.RGB = RGB(166, 3, 171) .Fill.BackColor.RGB = RGB(166, 3, 171) .Fill.PresetGradient msoGradientVertical, 1, _ msoGradientRainbow End With End With
'Die vierte Folie erhält eine Struktur With ActivePresentation.Slides(4) .FollowMasterBackground = msoFalse With .Background .Fill.ForeColor.RGB = RGB(255, 204, 102) .Fill.BackColor.SchemeColor = ppAccent1 .Fill.PresetTextured msoTextureWovenMat End With End With
'Die fünfte Folie erhält ein Muster With ActivePresentation.Slides(5)
272
Objekte auf Folien
.FollowMasterBackground = msoFalse With .Background .Fill.ForeColor.RGB = RGB(0, 255, 0) .Fill.BackColor.RGB = RGB(255, 255, 0) .Fill.Patterned msoPatternWideUpwardDiagonal End With End WithEnd Sub
14.4 Objekte auf FolienSoll auf einer Folie ein Objekt – zum Beispiel eine Grafik – eingefügt werden, sokann dies mit dem Befehl
AddPicture
geschehen. Dabei werden mehrere Eigenschaften verwendet, wie die Bildgröße(Width und Height), die Lage des Bildes (Left und Top) und die Frage, ob das Bildverknüpft werden soll (LinkToFile).
Sub Bilder()Dim ppBuildl As ShapeOn Error Resume NextActivePresentation.Slides.Add 1, ppLayoutBlank
Set ppBuildl = ActivePresentation.Slides(1). _ Shapes.AddPicture(FileName:="D:\TEXTE\BILDER\SCHWU.BMP", _ LinkToFile:=msoFalse, _ SaveWithDocument:=msoTrue, _ Left:=575, Top:=75, _ Width:=100, Height:=100)
End Sub
Dabei ist Filename der (vollständige) Dateiname der Grafik und LinkToFile derParameter, der festlegt, ob die Graphik eingefügt oder verknüpft ist. Ist sie ver-knüpft, so kann darüber hinaus festgelegt werden, ob sie mit dem Dokumentgespeichert wird:
Left und Top geben den Abstand vom linken und oberen Seitenrand an, Widthund Height die Breite und Höhe. Auch dieses Objekt muss nicht an eine Objekt-variable übergeben werden, sondern kann alleine stehen:
ActiveWindow.Selection.SlideRange. _ Shapes.AddPicture( _ FileName:="D:\TEXTE\BILDER\SCHWLOGO.BMP", _ LinkToFile:=msoFalse, _ SaveWithDocument:=msoTrue, _
273
14 Powerpoint
Left:=575, Top:=75, _ Width:=100, Height:=100).Select
Das Ganze funktioniert auch hier »ohne Markierung«, das heißt ohne den Be-fehl Select, wie er durch Aufzeichnung ermittelt wird:
Dim ppBild As ShapeSet ppBild = _ ActivePresentation.Slides(1).Shapes.AddPicture _ (FileName:="C:\Eigene Dateien\MonaLisa.BMP", _ LinkToFile:=msoFalse, _ SaveWithDocument:=msoTrue, _ Left:=575, Top:=75, _ Width:=100, Height:=100)
Um Text auf einer Folie an eine vorgegebene Position einzufügen, wählen Siedas Objekt Shapes. Dazu müssen Sie die Namen der verschiedenen Shapes wis-sen. Die wiederum kann man sich bei vorhandenen Folien sichtbar machen las-sen mit der Eigenschaft Name:
Sub Objekteauflisten()Dim ppObjekte As ShapeDim strNamensListe As StringFor Each objekte In ActiveWindow.Selection.SlideRange.Shapes strNamensListe = strNamensListe & objekte.Name & " / "Next
MsgBox strNamensListe
End Sub
Die Objekte beginnen ihre Zählung mit Rectangle 2. Soll also auf einer Titelfolieeine Überschrift und ein Untertitel eingetragen werden, so erreichen Sie diesmit:
Sub Text_Auf_Titelfolie()
ActivePresentation.Slides.Add 1, ppLayoutTitle
With ActivePresentation.Slides(1) .Shapes("Rectangle 2").TextFrame.TextRange.Text = _ "Der Duck-Konzern"
.Shapes("Rectangle 3").TextFrame.TextRange.Text = _ "Wir über uns"End With
End Sub
Soll ein neuer Textblock eingefügt werden, dann mit AddLabel:
274
Objekte auf Folien
Sub Neuer_Text_Einfügen()Dim ppTextNeu As ShapeDim ppBuildl As ShapeActivePresentation.Slides.Add 3, ppLayoutBlank
With ActivePresentation.Slides(3).Shapes
Set ppTextNeu = .AddLabel(msoTextOrientationHorizontal, _ 36, 48, 240, 360) ppTextNeu.TextFrame.TextRange.Text = _ "Und was wir noch zu sagen haben..."
With ppTextNeu.TextFrame.TextRange.Font .Name = "Arial" .Size = 36 .Bold = msoTrue .Color = 3 End WithEnd With
Set ppBuildl = ActivePresentation.Slides(3). _ Shapes.AddPicture(FileName:="D:\TEXTE\BILDER\SCHWU.BMP", _ LinkToFile:=msoFalse, _ SaveWithDocument:=msoTrue, _ Left:=575, Top:=100, _ Width:=100, Height:=100)
End Sub
Folgende Add-Methoden stehen Ihnen für das Objekt Shape zur Verfügung:
Tab. 14.2: Die verschiedenen Add-Methoden
Methode Erstellt
AddCallout Legende
AddComment Kommentar
AddConnector Verbindung
AddCurve Kurve
AddLabel Beschriftungsfeld
AddLine Linie
AddMediaObject Mediendatei (Sound, Video, ...)
AddOLEObject OLE-Objekt
AddPicture Bild
AddPlaceholder Platzhalter
AddPolyline Vielecke
AddShape AutoForm
275
14 Powerpoint
Es ist müßig, die einzelnen Elemente zu beschreiben. So besitzt beispielsweiseAddShape 139 verschiedene Typen (Types), von msoShape16pointStar bis mso-ShapeWave.
Exemplarisch sollen die verschiedenen WordArt-Einstellungen erläutert werden,die der Benutzer über das Menü EINFÜGEN / GRAFIK / WORDART erhält.
Der Parameter PresetTextEffect besitzt 30 Konstanten, die von msoTextEffect1bis msoTextEffect30 durchnummeriert sind. Ihnen entsprechen die jeweiligenEinstellungen. Das folgende Makro erzeugt eine neue Folie, auf der ein forma-tiertes WordArt-Objekt eingefügt wird:
Sub WordArt_Einfügen()Dim ppTextNeu As Shape
ActivePresentation.Slides.Add 4, ppLayoutBlankWith ActivePresentation.Slides(4).Shapes
Set ppTextNeu = .AddTextEffect _ (PresetTextEffect:=msoTextEffect26, _ Text:="Wir über uns", _ FontName:="Arial", _ FontSize:=36#, _ FontBold:=msoTrue, _ FontItalic:=msoFalse, _ Left:=100, _ Top:=100)End WithWith ppTextNeu .ScaleWidth factor:=2.27, _ relativetooriginalsize:=msoFalse, _ fscale:=msoScaleFromTopLeft .ScaleHeight factor:=1.86, _ relativetooriginalsize:=msoFalse, _ fscale:=msoScaleFromTopLeft With .Fill .Visible = msoTrue .ForeColor.RGB = RGB(166, 3, 171) .BackColor.RGB = RGB(166, 3, 171) .PresetGradient msoGradientVertical, _
AddfTable Tabelle
AddTextbox Textfeld
AddTextEffect WordArt-Objekt
AddTitle Folientitel
Methode Erstellt
276
Besonderheiten bei der Powerpoint-Programmierung
1, msoGradientRainbow End WithEnd WithEnd Sub
14.5 Besonderheiten bei der Powerpoint-Programmierung
Steuerelemente
Auf eine Präsentation können Befehlsschaltflächen aus der Symbolleiste »Steu-erelemente« gelegt werden, die während einer Bildschirmpräsentation gestar-tet werden können.
Infos hinter Shapes speichern
An ein Shape kann man eine Information über die Eigenschaft Name binden.Wird diese Eigenschaft nicht belegt, dann vergibt Powerpoint einen eigenenNamen, wie beispielsweise »Rectange2«. Allerdings muss jeder Name auf einerFolie eindeutig sein, darf also nicht zwei Mal vorkommen. Im folgenden Beispielwird ein schwarzer Stern auf der letzten Folie eingefügt, dem ein Name zuge-wiesen wird:
Sub NeueShapesMitInfos()Dim ppFolie As SlideDim ppShp As Shape
Set ppFolie = Application.ActivePresentation.Slides _(Application.ActivePresentation.Slides.Count)
Set ppShp = ppFolie.Shapes.AddShape _ (msoShape5pointStar, 0, 0, 0, 0)With ppShp .Left = 170 .Height = 210 .Top = 240 .Width = 210 .Name = "Anarchie ist machbar!" .Fill.Solid .Fill.ForeColor.RGB = RGB(0, 0, 0) .Line.BackColor.RGB = RGB(255, 255, 255)End WithSet ppShp = NothingSet ppFolie = NothingEnd Sub
Man könnte nun alle Namen aller Shapes durchlaufen und auslesen. Beispiels-weise so:
277
14 Powerpoint
Sub InfosAuslesen()Dim ppFolie As SlideDim ppShp As ShapeDim strNamen As String
Set ppFolie = Application.ActivePresentation.Slides _(Application.ActivePresentation.Slides.Count)
For Each ppShp In ppFolie.Shapes If ppShp.Name <> "" Then strNamen = strNamen & vbCr & ppShp.Name End IfNext
MsgBox strNamen
End Sub
Statt der Eigenschaft Name kann auch die Eigenschaft AlternativeText verwen-det werden. Sie hat den Vorteil, dass sie nicht eindeutig sein muss. Allerdingsschreibt Powerpoint den Text eines Textfeldes auch in die Eigenschaft Alterna-tiveText.
Zugegeben: Visio ist für das Thema »Daten an Shapes binden« das bessere Pro-gramm.
Übung 1
Eine Schleife durchläuft alle geöffneten Präsentationen und schließt alle, außerder, die gerade sichtbar ist.
Übung 2
Schreiben Sie ein Makro, das die letzten drei Folien einer Präsentation löscht.
Übung 3
Auf der MasterFolie wird ein Firmenname in die rechte obere Ecke gesetzt, un-ter und neben dem sich ein Strich befindet.
14.6 Übungen
278
Tipps
Tipp zu Übung 1 – 3
Mit dem Makrorekorder können viele der Befehle aufgezeichnet werden, dieanschließend nur noch modifiziert werden müssen.
Lösung 1
Sub SchließeFastAlle1()Dim strAktuellPräsName As StringDim intZähler As IntegerstrAktuellPräsName = Application.ActivePresentation.NameFor intZähler = 1 To Presentations.Count If Presentations(intZähler).Name <> _ strAktuellPräsName Then Presentations(intZähler).Save Presentations(intZähler).Close End IfNextEnd Sub
Es funktioniert analog auch mit Objektvariablen:
Sub SchließeFastAlle2()Dim strAktuellPräsName As StringDim ppPräsi As PresentationstrAktuellPräsName = Application.ActivePresentation.NameFor Each ppPräsi In Presentations If ppPräsi.Name <> strAktuellPräsName Then ppPräsi.Save ppPräsi.Close End IfNextEnd Sub
Lösung 2
Achten Sie beim Löschen auf die korrekten Nummern! Wenn eine Präsentationbeispielsweise sieben Folien hat und die letzte gelöscht wird, dann hat die Prä-sentation nunmehr sechs Folien.
14.7 Tipps
14.8 Lösungen
279
14 Powerpoint
Sub LöscheDieLetztenDrei()Dim intZähler As IntegerDim intFolienZahl As IntegerintFolienZahl = ActivePresentation.Slides.CountIf intFolienZahl < 3 Then MsgBox "Die Präsentation hat weniger als drei Folien"Else For intZähler = 1 To 3 ActivePresentation.Slides _ (intFolienZahl – intZähler + 1).Delete NextEnd IfEnd Sub
Lösung 3
Auf die Lösung dieser Aufgabe kommt man leicht, wenn man den Makrorekor-der zu Hilfe nimmt. Sie sollten das aufgezeichnete Makro allerdings überarbei-ten:
Sub Makro1()Dim ppPräsi As PresentationDim ppMeister As MasterDim ppForm As Shape
Set ppPräsi = Application.ActivePresentationSet ppMeister = ppPräsi.SlideMasterSet ppForm = _ ppMeister.Shapes.AddLabel(msoTextOrientationHorizontal, _ 460.75, 27.25, 14.5, 36#)
With ppForm.TextFrame.TextRange .Text = "Firmenname" With .Font .Name = "Arial" .Size = 24 .Bold = msoTrue .Italic = msoFalse .Underline = msoFalse .Shadow = msoFalse .Emboss = msoFalse .BaselineOffset = 0 .AutoRotateNumbers = msoFalse .Color.SchemeColor = ppForeground End With End With ppMeister.Shapes.AddLine 450#, 96#, 618#, 96# ppMeister.Shapes.AddLine 432#, 18#, 432#, 66#End Sub
280
Das Programm Visio wurde 1999 von Microsoft aufgekauft. Schon früh lehntees seine Oberfläche und seine Bedienung an die Microsoft-Produkte an. Andersals Powerpoint ist es weniger für den Einsatz von Präsentationen mit Beameroder LCD-Display geeignet, sondern dient in erster Linie zur Erstellung vonGeschäftsdiagrammen. Diese können aus verschiedenen Bereichen stammen:Organisationsdiagramme, Ablaufdiagramme, Raumpläne, technische Zeich-nungen aus den Bereichen Pneumatik, Hydraulik, Maschinenbau und Elektro-technik werden ebenso damit erstellt wie Darstellungen zur Softwareentwick-lung, Datenbankprogrammierung oder Webdesign. Da dieses Programm mitSicherheit in den nächsten Jahren einen Aufschwung erleben wird, soll an die-ser Stelle das Objektmodell von Visio vorgestellt werden. Da es einige Unter-schiede in den Ereignissen und im Erzeugen neuer Symbole und Menüeinträgebeinhaltet, wurden diesem Kapitel mehr Seiten gewidmet als Word oder Excel.Wer nicht bis ins letzte Detail einsteigen möchte, kann getrost Kapitel 7 (Visio-Ereignisse) überblättern und die letzten beiden Kapitel (Menüs, Symbole undTastenkombinationen) auslassen.
15 Zugriff auf Visio
281
15 Zugriff auf Visio
15.1 Die oberste Ebene: Application
Wenn Sie sich mit dem Objektmodell von VBA beschäftigen möchten, mit demSie auf Visio zugreifen, dann finden Sie das vollständige Modell als Visio-Zeich-nung im Ordner DVS unter dem Namen Object Modell.vsd.
Auch in Visio wird das Programm, also Visio selbst, mit Application bezeichnet.Auf dieses Objekt kann zugegriffen werden. So liefert folgender Programm-code den Namen von Visio:
Sub VisioZugriff()MsgBox Application.ProductNameEnd Sub
Die folgenden Zeilen listen weitere Informationen über Visio auf:
Sub VisioZugriff()
MsgBox "Das Programm " & Application.ProductName & _ " liegt im Ordner " & Application.Path & vbCr & _ "Es speichert folgende Verzeichnisse: " & vbCr & vbCr & _ Zeichnungen: " & vbTab & Application.DrawingPaths & _ vbCr & "Vorlagen: " & vbTab & Application.TemplatePaths _ & vbCr & "Schablonen: " & vbTab & _ Application.StencilPaths & vbCr & "Hilfsdatei: " & vbTab _
Abbildung 15.1:Visio ist äußerst
vielseitig einsetzbar.
282
Die oberste Ebene: Application
& Application.HelpPaths & vbCr & "Zusatzprogramme: " & _ vbTab & Application.AddonPaths & vbCr & _ "Start: " & vbTab & vbTab & Application.StartupPaths & _ vbCr & "Filter: " & vbTab & vbTab & _ Application.FilterPaths & vbCr
End Sub
Da mit dem alleinigen Objekt Application nicht allzu viel anzufangen ist, wer-den weitere Objekte benötigt. Die Liste der (offenen) Fenster kann über dieSammlung Windows abgefragt werden:
MsgBox Application.Windows.Count
Folgende Schleife (die bei 0 beginnt) durchläuft alle Fenster und meldet die Be-schriftung:
Sub VisioDateien1()Dim i As IntegerDim strFensterNamen As StringFor i = 1 To Application.Windows.Count strFensterNamen = strFensterNamen & vbCr & _ Application.Windows(i).CaptionNext
MsgBox strFensterNamen
End Sub
Interessanter ist die Sammlung der offenen Dateien:
Sub VisioDateien2()Dim i As IntegerDim strDateiNamen As StringFor i = 1 To Application.Documents.Count strDateiNamen = strDateiNamen & vbCr & _ Application.Documents(i).NameNext
MsgBox strDateiNamen
End Sub
Das oberste Objekt – Application – muss nicht jedes Mal neu geschrieben wer-den. Das Beispiel funktioniert auch ohne Application. Und schließlich steht Ih-nen noch die Variante mit der Objektvariablendeklaration zur Verfügung.
Sub VisioDateien3()Dim i As IntegerDim strDateiNamen As String
283
15 Zugriff auf Visio
Dim appVisio As Visio.ApplicationDim docsObj As Visio.Documents
Set appVisio = Visio.ApplicationSet docsObj = Visio.Documents
For i = 1 To docsObj.Count strDateiNamen = strDateiNamen & vbCr & docsObj(i).NameNext
MsgBox strDateiNamen
End Sub
Soll dagegen auf das aktuelle Dokument zugegriffen werden, dann steht Ihnenauch das Objekt
Application.ActiveDocument
oder kürzer:
ActiveDocument
zur Verfügung. Alternativ kann auch das Objekt ThisDocument verwendet wer-den. Dieses Objekt hat nun weitere Eigenschaften und Methoden.
15.2 Das Document-ObjektOben wurde bereits gezeigt, dass mit
Application.Documents.Open
eine bestimmte Datei geöffnet wird. Mit der Methode
Application.Documents.Add
wird eine leere neue Datei hinzugefügt, wobei auch hier ein Filename als Para-meter angegeben werden kann. Folgender Befehl öffnet eine Visio-Dokument-vorlage:
Application.Documents.Add _Filename:="C:\PROGRAMME\Visio2000\Lösungen\" & _"Blockdiagramm\Blockdiagramm.vst"
Diese beiden Methoden – Add und Save – sind auf die Sammlung der Doku-mente anzuwenden. Ein Dokument, beispielsweise auf ActiveDocument, kannmit dem Befehl Save (ohne Parameter) gespeichert werden:
ActiveDocument.Save
284
Schablonen
Der Befehl SaveAs verlangt einen Dateinamen. Beispielsweise so:
ActiveDocument.SaveAs _Filename:="C:\PROGRAMME\Visio2000\Lösungen\Test.vsd"
Mit der Methode SaveAsEx kann noch ein Parameter hinzugefügt werden, dererläutert, ob die Datei als Read-Only (visSaveAsRo) gespeichert wird oder alsWorkspace (visSaveAsWS).
Mit der Methode Close wird die Datei geschlossen:
ActiveDocument.Close
Und Drucken? Dafür ist schnell der Befehl Print gefunden:
ActiveDocument.Print
Was aber, wenn beim Drucken eine Einstellung vorgenommen werden soll?Dann muss mit einer der Print-Eigenschaften gearbeitet werden:
Tab. 15.1: Die Print-Eigen-schaften
Und Beenden? Dafür ist wieder das Objekt Application zuständig:
Application.Quit
Nachdem nun erklärt wurde, wie per Automation auf Dateien zugegriffen wird,soll im nächsten Schritt eine Ebene tiefer auf Schablonen und Zeichenblätter zu-gegriffen werden. In jeder Visio-Zeichnung sind eine oder mehrere Schabloneneingebettet (es ist sehr selten, dass zu einer Zeichnung keine Schablonen geöff-net werden). Eine Zeichnung hat immer ein oder mehrere Zeichenblätter. Beideskann angesteuert werden.
15.3 SchablonenIn Zeichnungen eingebundene Schablonen sind Dateien mit der Endung»*.vss«. Und als solche werden sie in der Programmierung angesteuert. Siekönnen geöffnet und geschlossen werden. Das folgende Beispiel öffnet die Do-kumentvorlage »Mind-Map-Diagramm«, fügt eine weitere Schablone hinzu(»Grundlegende Flußdiagramm-Shapes.vss«) und schließt eine vorhandene
Print-Eigenschaft Erklärung
PrintCenteredH horizontal zentriert
PrintCenteredV vertikal zentriert
PrintFitOnPages auf Seite anpassen
PrintLandscape drucke im Querformat
PrintPagesAcross drucke über mehrere Seiten hinweg
PrintPagesDown drucke von oben nach unten
PrintScale Druckskala
285
15 Zugriff auf Visio
Schablone (»Hintergründe.vss«). Vergessen Sie nicht die Endung »*.vss« beimÖffnen und beim Schließen der Schablone.
Sub SchabloneAuf_Und_Zu1()Documents.Add _Filename:="D:\PROGRAMM\Visio2000\Lösungen\" & _ "Flußdiagramm\Mind-Map-Diagramm.vst"Documents.OpenEx _"D:\PROGRAMM\Visio2000\Lösungen\Flußdiagramm\" & _ "Grundlegende Flußdiagramm-Shapes.vss", visOpenDockedDocuments("Hintergründe.vss").CloseEnd Sub
Das Programm kann auch ohne Pfadangabe geschrieben werden:
Sub SchabloneAuf_Und_Zu2()Documents.Add Filename:="Mind-Map-Diagramm.vst"Documents.OpenEx "Grundlegende Flußdiagramm-Shapes.vss", _ visOpenDockedDocuments("Hintergründe.vss").CloseEnd Sub
Da in Visio im Menü EXTRAS / OPTIONEN im Registerblatt »Dateipfadnamen«zwei Pfade für die Vorlagen und Schablonen festgelegt sind, kann auf den Pfadverzichtet werden.
15.4 Seiten (das Page-Objekt)Jede Visio-Zeichnung besitzt eine oder mehrere Seiten. Diese werden – wiekönnte es anders sein – durch das Page-Objekt angesteuert. Die SammlungPages und das Objekt Page sind Eigenschaften des Dokumentenobjekts. DieAnzahl der Seiten kann mit der Eigenschaft
Pages.Count
ermittelt werden. Auf eine einzelne Seite wird entweder mit dem Item zugegrif-fen oder über den Namen der Seite, also beispielsweise mit Pages("Hinter-grund") oder Pages(6). Beide Varianten haben ihre Vor- und Nachteile, bei jederMethode sollte überprüft werden, ob der Benutzer möglicherweise die Seiteverschoben oder umbenannt hat. Die Methode Add fügt eine neue leere Seitean das Ende des Dokuments, die Methode Delete löscht eine Seite. Die Eigen-schaft Name kann abgefragt oder gesetzt werden – im letzteren Fall wird derZeichnungsballname umbenannt. Soll ein Blatt zu einem Hintergrund werden,dann kann die Eigenschaft
Page.Background
verwendet werden. Dieser Eigenschaft wird ein Wert zugewiesen. Ist er größerals 0, dann bedeutet es, dass es sich um ein Hintergrundblatt handelt, ist er 0,
286
Shape-Zugriff
ist das Blatt ein Vordergrundblatt. Soll nun einem Zeichenblatt ein Hintergrundzugewiesen werden, dann ist die Eigenschaft BackPage auf die entsprechendeHintergrundseite zu setzen.
Das folgende Beispiel durchläuft alle Zeichnungsblätter und zeigt die Namenan. Dann wird ein neues Blatt hinzugefügt, zu einem Hintergrundblatt gemachtund »Hintergrund« genannt. Dem ersten Blatt wird anschließend dieser Hinter-grund zugewiesen:
Sub Seitenändern()Dim i As IntegerDim strSeitennamen As StringFor i = 1 To ActiveDocument.Pages.Count strSeitennamen = strSeitennamen & vbCr & _ ActiveDocument.Pages(i).NameNext i
MsgBox strSeitennamen
ActiveDocument.Pages.AddActivePage.Background = 1ActivePage.Name = "Hintergrund"ActiveDocument.Pages(1).BackPage = "Hintergrund"
End Sub
15.5 Shape-ZugriffWird auf eine Schablone zugegriffen, dann kann man auch auf dortige Mas-tershapes zugreifen. Der Befehl
Documents(i).Masters.GetNames
übergibt die Namen aller Mastershapes an einen Array, wenn es sich bei Docu-ments(i) um eine Schablone handelt. Das folgende Beispiel durchläuft alle Da-teien, überprüft, ob es sich um Schablonen handelt, und zeigt deren Master-shapenamen an:
Sub MastersAnzeigen()Dim intMaster As IntegerDim intDokumente As IntegerDim strMasternames() As StringDim strAusgabe As String
For intDokumente = 1 To Documents.Count
If Right(Documents(intDokumente).Name, 3) = "vss" Then
287
15 Zugriff auf Visio
Documents(intDokumente).Masters.GetNames strMasternames
For intMaster = LBound(strMasternames) _ To UBound(strMasternames) strAusgabe = strAusgabe & ", " & _ strMasternames(intMaster) Next
MsgBox Documents(intDokumente).Name & _ " enthält folgende Mastershapes:" & _ vbCr & vbCr & Right(strAusgabe, Len(strAusgabe) – 2) strAusgabe = ""
End If
NextEnd Sub
Eine Zeichnung kann folgende drei Arten von Shapes beinhalten: Shapes, dieauf einer Schablone liegen (Mastershapes), Shapes, die sich auf einem Zeichen-blatt befinden, und benutzte Mastershapes, die über das Menü FENSTER / DO-KUMENT-SCHABLONE ANZEIGEN angezeigt (und weiter verwendet) werdenkönnen. Folgende Prozedur durchläuft das aktuelle Dokument und zeigt alleShapes des Zeichenblatts und alle verwendeten Mastershapes an:
Sub Shapes_anzeigen()Dim intShapeZähler As IntegerDim intBlattzähler As IntegerDim intBlattZahl As IntegerDim strShapeNamen As String
intBlattZahl = ActiveDocument.Pages.Count
For intBlattzähler = 1 To intBlattZahl For intShapeZähler = 1 To _ ActiveDocument.Pages(intBlattzähler).Shapes.Count strShapeNamen = strShapeNamen & ", " & _ ActiveDocument.Pages(intBlattzähler).Shapes _ (intShapeZähler).Name NextNext
strShapeNamen = "Die verwendeten Shapes lauten:" & _ vbCr & vbCr & Right(strShapeNamen, _ Len(strShapeNamen) – 2) & vbCr & vbCr & _ "Die verwendeten Mastershapes lauten:" & vbCr
288
Shape-Zugriff
For intShapeZähler = 1 To ActiveDocument.Masters.Count strShapeNamen = strShapeNamen & vbCr & _ "* " & ActiveDocument.Masters(intShapeZähler).Name Next
MsgBox strShapeNamen
End Sub
15.5.1 Shapes markieren
Der Befehl Select markiert ein (oder mehrere) Shape(s). Select ist eine Methodedes Window-Objekts. Das folgende Beispiels zeigt, wie das erste Shape des ers-ten Zeichenblatts markiert wird:
Sub Shapes_Markieren01()Dim shpObj As Visio.ShapeSet shpObj = Visio.ActivePage.Shapes(1)ActiveWindow.Select shpObj, visSelectEnd Sub
Abbildung 15.2: Die Namen der Shapes – allerdings nicht vollständig
289
15 Zugriff auf Visio
Die Methode Select hat mehrere Parameter:
Tab. 15.2:Die Parameter der
Methode Select
Im folgenden Makro werden nacheinander mehrere Aktionen durchlaufen. Beieinem Testlauf empfiehlt sich der Einzelschrittmodus:
Die ersten drei Shapes der aktiven Seite werden als Objekte gespeichert. Dieersten zwei Shapes werden markiert und gruppiert. Innerhalb der Gruppierungwird ein Shape (das erste) markiert. Danach wird die Markierung aufgehoben.Alle Shapes der Seite werden markiert und die Markierung wird erneut aufge-hoben.
Sub Shapes_Markieren01()Dim shpObj(1 To 3) As Visio.ShapeDim i As Integer
For i = 1 To 3 Set shpObj(i) = Visio.ActivePage.Shapes(i)Next
For i = 1 To 2 ActiveWindow.Select shpObj(i), visSelectNext
ActiveWindow.Group
ActiveWindow.Select shpObj(1), visSubSelect
ActiveWindow.Select shpObj(1), visDeselectAll
ActiveWindow.SelectAll
ActiveWindow.Select shpObj(3), visDeselect
End Sub
Der folgende Befehl zeigt an, wie viele Shapes zur Zeit markiert sind:
MsgBox ActiveWindow.Selection.Count
Konstante Wert Bedeutung
visDeselect 1 hebt die Markierung von einem Shape auf
visSelect 2 markiert ein Shape
visSubSelect 3 markiert innerhalb einer Gruppe
visSelectAll 4 markiert alle Shapes
visDeselectAll 256 hebt die Markierung aller Shapes auf
290
Shape-Zugriff
15.5.2 Shape-Aktionen
Mit Hilfe des Selection-Objekts können die Shapes ebenso weiter verarbeitetwerden, wie dies von den Visio-Funktionalitäten bekannt ist. Sie können dupli-ziert, kopiert und ausgeschnitten, eingefügt und gelöscht werden. Das fol-gende Makro führt diese Aktionen in eben dieser Reihenfolge aus:
Sub Shape_Aktionen01()Dim shpObj As Visio.Shape
Set shpObj = Visio.ActivePage.Shapes(1)
With ActiveWindow .DeselectAll .Select shpObj, visSelect .Selection.Duplicate
.DeselectAll .Select shpObj, visSelect .Selection.Copy .Paste
.DeselectAll .Select shpObj, visSelect .Selection.Cut .Paste
.DeselectAll .Select shpObj, visSelect .Selection.Delete
End WithEnd Sub
Auch die übrigen Methoden, FlipHorizontal, FlipVertical, ReverseEnds,Rotate90, SendBackward und BringForward beziehungsweise SendToBack undBringToFront, stehen zur Verfügung. Und schließlich finden sich die Mengen-operationen:
Combine, Fragment, Intersect, Join, Subtract, Trim und Union.
Die Methode Group wurde in einem oberen Beispiel schon erwähnt – analogstehen die Methoden Ungroup und die Methode ConvertToGroup zur Verfügung.
All diese Methoden müssen nicht auf eine Markierung (Selection) angewandtwerden – man kann mit ihnen auch direkt auf ein (oder mehrere) Shapes zu-greifen ohne es zu markieren.
291
15 Zugriff auf Visio
15.6 Neue Shapes zeichnenSo wie es auch in Visio mehrere Möglichkeiten gibt, ein Shape zu zeichnen, soexistieren auch in VBA mehrere Möglichkeiten, um ein neues Shape zu kreieren.
15.6.1 Rechteck und Ellipse zeichnen
Soll auf dem Zeichenblatt ein Rechteck gezeichnet werden, dann ist dafür derBefehl DrawRectangle zuständig. Dabei sind vier Parameter anzugeben, welchedie Koordinaten der beiden Eckpunkte bestimmen. Dabei wird von den Koordi-naten des Zeichenblatts ausgegangen (so sitzt beispielsweise der Ursprung in(0/0)) und die Werte selbst müssen in inch angegeben werden. Das folgendeBeispiel zeichnet ein Rechteck mit den Eckkoordinaten (1/1) und (3/2):
Sub Rechteck_Zeichnen() ActivePage.DrawRectangle 1, 1, 3, 2End Sub
Zum gleichen Ergebnis wäre man auch folgendermaßen gekommen:
ActivePage.DrawRectangle 1, 2, 3, 1
oder auch so:
ActivePage.DrawRectangle 3, 1, 1, 2
Wichtig sind dabei lediglich die beiden gegenüberliegenden Eckpunkte.
Analog wird eine Ellipse gezeichnet:
Sub Ellipse_Zeichnen() ActivePage.DrawOval 1, 1, 3, 2End Sub
Dabei sind die Koordinaten die gleichen wie die des Rechtecks: Die Ellipse wirdin das Rechteck einbeschrieben. Und auch eine gerade Linien kann über die vierKoordinaten der zwei Punkte per Programmierung gezeichnet werden:
Sub Linie_Zeichnen() ActivePage.DrawLine 1, 1, 3, 2End Sub
Sehr viel komplexer sind gekrümmte Linien: Splines. Sie werden mit einem derfolgenden Befehle gezeichnet, wobei noch eine Reihe von Parametern hinzuge-fügt werden müssen:
ActivePage.DrawBezierActivePage.DrawNURBSActivePage.DrawSplineActivePage.DrawPolyline
Darauf soll an dieser Stelle nicht eingegangen werden.
292
Neue Shapes zeichnen
15.6.2 Shapes aus der Schablone ziehen
Einfacher ist es, aus einer (geöffneten) Schablone ein Shape herauszuziehenund auf dem Zeichenblatt fallenzulassen:
Sub Shape_Aus_Schablone01()Dim stnObj As DocumentDim mastObj As Master
Set stnObj = Documents _ ("Grundlegende Flußdiagramm-Shapes.vss")Set mastObj = stnObj.Masters("Entscheidung")
ActivePage.Drop mastObj, 3, 4
End Sub
Man könnte den Code sicherlich ohne Deklaration der Objektvariablen erzeu-gen, allerdings würde er dann unübersichtlich werden. Auf eine Variable stnObjwird eine Schablone gelegt. Von ihr wird ein Master auf eine weitere Objekt-variable gelegt (mastObj). Dieser Master wird nun mit dem Befehl Drop auf dasaktuelle Zeichenblatt gezogen.
15.6.3 Shapes beschriften
Soll nun ein neues Shape einen Text erhalten, dann kann er mit der EigenschaftText gesetzt werden:
Sub Shape_Aus_Schablone()Dim stnObj As DocumentDim mastObj As MasterDim shpObj As Shape
Set stnObj = Documents _ ("Grundlegende Flußdiagramm-Shapes.vss")Set mastObj = stnObj.Masters("End-Shape")
Set shpObj = ActivePage.Drop(mastObj, 2, 3.5)shpObj.Text = "Ich bin der Terminator!"
End Sub
Leider hat das Selection-Objekt keine Text-Eigenschaft, so dass man den Textauch mit:
ActiveWindow.Selection.Text
hinzufügen könnte. Dies klappt aber nicht!
293
15 Zugriff auf Visio
15.6.4 Shapes formatieren
So wie die Shapes in Visio mit Text versehen werden können, können sie auchformatiert werden. Das folgende Beispiel erzeugt neun Rechtecke auf einemZeichenblatt und formatiert sie mit verschiedenen Füllstilen:
Sub Verschiedene_Rechtecke()Dim sngBreite As SingleDim sngHöhe As SingleDim i As IntegerDim j As Integer
Dim shpShape(1 To 3, 1 To 3) As Shape
ActiveWindow.SelectAllActiveWindow.Selection.Delete
sngBreite = ActiveDocument.PaperWidth("in") / 3sngHöhe = ActiveDocument.PaperHeight("in") / 3
For i = 1 To 3 For j = 1 To 3
Set shpShape(i, j) = ActivePage.DrawRectangle((i – 1) * _ sngBreite, (j – 1) * sngHöhe, _ i * sngBreite, j * sngHöhe)
Next jNext i
ActiveWindow.Select shpShape(i – 1, j – 1), visDeselect
shpShape(1, 1).FillStyle = "Fluß grau"shpShape(1, 2).FillStyle = "Fluß normal"shpShape(1, 3).FillStyle = "Fluß-Marker"shpShape(2, 1).FillStyle = "Fluß-Marker"shpShape(2, 2).FillStyle = "Fluß grau"shpShape(2, 3).FillStyle = "Fluß normal"shpShape(3, 1).FillStyle = "Fluß normal"shpShape(3, 2).FillStyle = "Fluß-Marker"shpShape(3, 3).FillStyle = "Fluß grau"
End Sub
Natürlich fehlen eine ganze Reihe von Formatierungen. Wäre das programmge-steuerte Formatieren der Shapes nur über Stile möglich, dann stünden dem Pro-grammierer nur sehr wenige Möglichkeiten zur Verfügung. Um nun auf alleFormatierungsoptionen zugreifen zu können, muss eine Ebene weitergegan-
294
Neue Shapes zeichnen
gen werden: man muss per Programmierung auf die Shapesheets zugreifen.Soll beispielsweise das erste Shape rot werden, dann ist ihm die Füllfarbe 2 zu-zuweisen:
ActivePage.Shapes(1).Cells("FüllVGrund").ResultIU = 2
Folgende Liste zeigt die Eigenschaften, mit denen auf Zellen zugegriffen wer-den kann:
Tab. 15.3: Die Eigenschaften, die einen Zellzugriff erlauben
Da man auf Zellen zugreifen kann, sind alle Veränderungen von Shapes mög-lich. Dies soll an drei verschiedenen Beispielen erläutert werden. Im ersten Bei-spiel wird ein neues Shape aus einem Rechteck erzeugt:
Sub Form_Erzeugen()Dim DrawPageObj As Visio.PageDim shpObj As Visio.ShapeDim cellObj As Visio.CellDim strZellname As String, strFormel As StringDim intRechteck As Integer, i As Integer
strZellname = "Versuch.X1"strFormel = "=MIN(Breite;Höhe)/5"
Set DrawPageObj = ActivePage
Set shpObj = DrawPageObj.DrawRectangle(1, 5, 5, 1)
Eigenschaft Bedeutung
Result liest oder schreibt einen Zellinhalt.
ResultForce schreibt einen Zellinhalt – auch wenn er mit der SCHÜTZEN-Funktion geschützt ist.
ResultInt liest einen Zellinhalt, der einen Integer-Wert darstellt.
ResultIU liest oder schreibt einen Zellinhalt ohne interne Einheiten.
ResultIUForce schreibt einen Zellinhalt ohne interne Einheiten – auch wenn er mit der SCHÜTZEN-Funktion geschützt ist.
ResultFromInt setzt einen Integer-Wert.
ResultFromIntForce schreibt einen Zellinhalt als Integer-Wert – auch wenn er mit der SCHÜTZEN-Funktion geschützt ist.
ResultStr liefert einen Wert, der als String vorliegt.
Formula trägt eine Formel ein oder liest sie aus.
FormulaU trägt eine Formel ein oder liest sie in der universellen Form aus.
FormulaForce trägt eine Formel ein, auch wenn die Zelle geschützt ist.
FormulaForceU trägt eine Formel in der universellen Form ein, auch wenn die Zelle geschützt ist.
295
15 Zugriff auf Visio
shpObj.AddSection visSectionScratchshpObj.AddRow visSectionScratch, visRowScratch, 0
Set cellObj = shpObj.Cells(strZellname)cellObj.Formula = strFormel
For i = 1 To 4 shpObj.RowType(visSectionFirstComponent, _ visRowVertex + i) = visTagArcTo Set cellObj = shpObj.CellsSRC _ (visSectionFirstComponent, visRowVertex + i, 2) cellObj.Formula = "-" & strZellnameNext i
intRechteck = visSectionFirstComponent + 1shpObj.AddSection intRechteck
shpObj.AddRow intRechteck, visRowComponent, visTagComponentshpObj.AddRow intRechteck, visRowVertex, visTagMoveTo
For i = 1 To 4 shpObj.AddRow intRechteck, visRowLast, visTagLineToNext i
Set cellObj = shpObj.CellsSRC(intRechteck, 1, 0)cellObj.Formula = "Width * 0 + " & strZellname
Set cellObj = shpObj.CellsSRC(intRechteck, 1, 1)cellObj.Formula = "Height * 0 + " & strZellname
Set cellObj = shpObj.CellsSRC(intRechteck, 2, 0)cellObj.Formula = "Width * 1 – " & strZellname
Set cellObj = shpObj.CellsSRC(intRechteck, 2, 1)cellObj.Formula = "Height * 0 + " & strZellname
Set cellObj = shpObj.CellsSRC(intRechteck, 3, 0)cellObj.Formula = "Width * 1 – " & strZellname
Set cellObj = shpObj.CellsSRC(intRechteck, 3, 1)cellObj.Formula = "Height * 1 – " & strZellname
Set cellObj = shpObj.CellsSRC(intRechteck, 4, 0)cellObj.Formula = "Width * 0 + " & strZellname
Set cellObj = shpObj.CellsSRC(intRechteck, 4, 1)cellObj.Formula = "Height * 1 – " & strZellname
296
Neue Shapes zeichnen
Set cellObj = shpObj.CellsSRC(intRechteck, 5, 0)cellObj.Formula = "Geometry2.X1"
Set cellObj = shpObj.CellsSRC(intRechteck, 5, 1)cellObj.Formula = "Geometry2.Y1"
Set cellObj = shpObj.Cells("FüllVGrund")cellObj.ResultIU = 2End Sub
Dazu eine Reihe von Erläuterungen. Der Befehl DrawRectangle wurde schon er-läutert – damit wird ein Rechteck erzeugt. Dem Shape kann mit der MethodeAddSection eine Sektion hinzugefügt werden. Im Objektkatalog werden unterder Kategorie VisSectionIndices alle Bereiche aufgelistet:
Tab. 15.4: Die Bereiche der Shapesheets
Abbildung 15.3: Ein Shape wird gezeichnet
VBA-Befehl deutscher Abschnitt-Name
visSectionAction Aktionen
visSectionCharacter Zeichen
visSectionConnectionPts Verbindungspunkte
visSectionControls Steuerelemente
visSectionFirstComponent Geometrie
visSectionHyperlink Hyperlinks
297
15 Zugriff auf Visio
Umgekehrt kann mit dem Befehl DeleteSection wieder ein Abschnitt gelöschtwerden. Nun muss eine Zeile in den Abschnitt eingefügt werden. Hierfür stehtder Befehl AddRow mit folgender Syntax zur Verfügung:
retVal = Shape.AddRow (section, row, tag)
Mit Section wird einer der Abschnitte ausgewählt, mit Row die Zeile, in der sichdie neue Zeile befindet. Dabei kann mit Konstanten gearbeitet werden, wie mitvisRowFirst+0, visRowFirst+1, bis zur letzten, die visRowLast heißt. Dabeikann die erste Zeile auch mit dem Namen des Abschnitts benannt werden, alsovisRowAction, visRowAlign, visRowCharacter, visRowComponent, visRowConnec-tionPts, ... visRowScratch, visRowShapeLayout, visRowStyle, visRowTab, vis-RowText, visRowTextXForm, visRowUser, ... Wird der Tag auf 0 gesetzt, dann wirdder Standardtyp verwendet. In der Geometrie-Sektion, im Abschnitt Verbin-dungspunkte und Steuerelemente empfiehlt es sich, mit anderen Werten zu ar-beiten. Soll eine neu hinzugefügte Zeile einen Namen besitzen, dann ist die Me-thode AddNamedRow zu verwenden.
Nun wird die Formel in die Zelle geschrieben. Statt der deutschen Schreibweise("=MIN(Breite;Höhe)/5") hätte man auch die amerikanische verwenden kön-nen:
"=Min(Width, Height) / 5"
Nun werden die vier Zellen der Geometriesektion in Bogen verwandelt, und ihreKrümmungen greifen auf die benutzerdefinierte Zelle zu.
Es wird ein weiteres Rechteck eingefügt, das auf den Wert der benutzerdefi-nierten Zelle zugreift. Ihm werden eine Reihe von Formeln einbeschrieben.Schließlich wird das Shape rot eingefärbt, das heißt, der Zelle FüllVGrund wirdder Wert 2 zugewiesen.
visSectionInval Geometrie
visSectionLastComponent Geometrie
visSectionLayer Layer-Zugehörigkeit
visSectionObject Transformation
visSectionParagraph Absatz
visSectionProp Datenfelder
visSectionScratch Entwurf
visSectionTab Tabulatoren
visSectionTextfield Textblockformat
visSectionUser Benutzerdefinierte Zellen
VBA-Befehl deutscher Abschnitt-Name
298
Neue Shapes zeichnen
Da per Programmierung Werte in Shapesheetzellen hineingeschrieben und aus-gelesen werden können, ist der Zugriff auf einzelne Shapes kein Problem mehr.Wie sieht es allerdings aus, wenn mehrere Shapes miteinander verbunden wer-den?
15.6.5 Shapes verbinden
Auch für das Verbinden sind Zellen nötig. Dabei wird mit der Methode GlueToeine Zelle mit einer anderen verbunden. Die Syntax:
Zelle1.GlueTo Zelle2
Bei den Zellen kann es sich um einen Verbindungspunkt, einen Punkt der Geo-metriesektion oder ein Steuerelement handeln. Allerdings muss beim eindimen-sionalen Verbinder der Endpunkt oder der Anfangspunkt Cells("BeginX") oderCells("EndX") verwendet werden. Dabei ist es gleichgültig, ob BeginnX oderBeginnY benutzt wird. Das folgende Beispiel holt aus der Schablone »Grundle-gende Flußdiagramm-Shapes.vss« zwei Prozess-Shapes und einen Dynami-schen Verbinder. Dann wird der Anfang des Verbinders mit einem Shape ver-bunden und schließlich das Ende mit dem anderen Shape:
Sub Verbinden01()Dim stnObj As DocumentDim mastObj As MasterDim shpShape1 As Shape, shpShape2 As ShapeDim shpVerbinder As ShapeDim celZelle1 As Cell, celZelle2 As Cell
Set stnObj = Documents _ ("Grundlegende Flußdiagramm-Shapes.vss")Set mastObj = stnObj.Masters("Prozeß")
Set shpShape1 = ActivePage.Drop(mastObj, 3, 4)Set shpShape2 = ActivePage.Drop(mastObj, 6, 8)
Set mastObj = stnObj.Masters("Dynamischer Verbinder")Set shpVerbinder = ActivePage.Drop(mastObj, 4, 5)
Set celZelle1 = shpShape1.Cells("Connections.X4")Set celZelle2 = shpVerbinder.Cells("BeginX")
celZelle2.GlueTo celZelle1
Set celZelle1 = shpShape2.Cells("Connections.X3")Set celZelle2 = shpVerbinder.Cells("EndX")
celZelle2.GlueTo celZelle1End Sub
299
15 Zugriff auf Visio
Das Ergebnis sieht folgendermaßen aus:
Man hätte ebenso die beiden Ecken (das heißt die Geometriesektion) miteinan-der verbinden können. Dazu hätte man lediglich andere Zellen verwenden müs-sen:
Sub Verbinden02()[...]Set celZelle1 = shpShape1.Cells("Geometry1.X3")Set celZelle2 = shpVerbinder.Cells("BeginX")
celZelle2.GlueTo celZelle1
Set celZelle1 = shpShape2.Cells("Geometry1.X1")Set celZelle2 = shpVerbinder.Cells("EndX")
celZelle2.GlueTo celZelle1
End Sub
Man hätte auch die Methode GlueToPos verwenden können, mit der an einebeliebige Position des Shapes angeklebt wird. Diese Methode benötigt dieX- und Y-Koordinate des Shapes, an das die Linie geklebt wird. Die Syntax:
Zelle.GlueToPos Shape, X-Pos, Y-Pos
300
Visio-Ereignisse
Das Programm wird verändert:
Sub Verbinden02()[...]Set celZelle1 = shpVerbinder.Cells("BeginX")Set celZelle2 = shpVerbinder.Cells("EndX")
celZelle1.GlueToPos shpShape1, 0.75, 1celZelle2.GlueToPos shpShape2, 0.25, 0
15.7 Visio-EreignisseBislang wurden alle Prozeduren direkt aus dem Visual-Basic-Editor gestartetoder in Visio über das Menü EXTRAS – MAKRO – MAKROS. Dies ist in der Praxisallerdings nicht der Fall. Normalerweise starten die Makros, wenn ein spezifi-sches Ereignis ausgelöst wird. Dies kann an die Zelle gebunden sein. Dafür ste-hen in der Sektion »Ereignisse« fünf Ereignisse zur Verfügung: »DieDaten«,»DerText«, »EreignisDpplKlck«, »EreignisXFMod« und »Einfügeereignis«. Mitder Funktion RUNADDON kann ein Makro gestartet werden, beispielsweise:
=RUNADDON("Verbinden01")
Diese fünf Ereignisse sind jedoch noch lange nicht alle. Im Visual-Basic-Editorfindet sich im Projektexplorer das Visio-Objekt »ThisDocument«. Dieses verfügtüber folgende Ereignisse:
Tab. 15.5: Die Visio-Ereignisse
BeforeDocument-Close
DocumentChanged PageAdded QueryCancel-Ungroup
BeforeDocument-Save
Document-CloseCanceled
PageChanged RunModeEntered
BeforeMaster-Delete
DocumentCreated PageDelete-Canceled
SelectionDelete-Canceled
BeforePageDelete DocumentOpened QueryCancel-ConvertToGroup
ShapeAdded
BeforeSelection-Delete
DocumentSaved QueryCancelDocu-mentClose
ShapeExitedText-Edit
BeforeShapeText-Edit
DocumentSavedAs QueryCancel-MasterDelete
ShapeParent-Changed
BeforeStyleDelete MasterAdded QueryCancelPage-Delete
StyleAdded
ConvertToGroup-Canceled
MasterChanged QueryCancelSelec-tionDelete
StyleChanged
DesignMode-Entered
MasterDelete-Canceled
QueryCancelStyle-Delete
StyleDelete-Canceled
UngroupCanceled
301
15 Zugriff auf Visio
Visio liefert einige Beispieldateien auf seiner CD-ROM, die im Ordner DVS/VBASOLUTIONS gespeichert sind. An ihnen kann das Objektmodell erklärt werden.In der Datei VBA DISTANCE FROM.VSD befindet sich ein Tankstellensymbol aufdem Zeichenblatt.
Dieses Shape trägt den Namen »Fuel«. Damit es bei allen Ereignissen eindeutigidentifiziert werden kann, wird beim Öffnen der Datei mit einer Objektvariablenein Bezug auf dieses Shape hergestellt:
Private Sub Document_DocumentOpened(ByVal doc As IVDocument) Set objBaseShape = ActivePage.Shapes("Fuel")End Sub
Wird nun ein (beliebiges) Shape aus einer Schablone auf das Zeichenblatt gezo-gen, dann tritt das Ereignis »ShapeAdded« ein. Mit ihm wird eine Objektvari-able vom Typ »Shape« übergeben. Damit kann die Lage des neuen Shapes aus-findig gemacht werden:
Private Sub Document_ShapeAdded(ByVal Shape As IVShape)Dim strMsg As StringDim dblMinimumDistance As Double, dblDistance As Double
dblMinimumDistance = 84
If objBaseShape.Parent = Shape.Parent Then
dblDistance = Shape.DistanceFromPoint _ (objBaseShape.Cells("PinX"), Shape.Cells("PinY"), 0)
If dblDistance > dblMinimumDistance Then strMsg = "Der Sicherheitsabstand wurde eingehalten." Else strMsg = "Die Entfernung ist zu gering!" End If
Else strMsg = "Die Shapes befinden sich auf " & _ "unterschiedlichen Zeichenblättern."End If
MsgBox strMsg
End Sub
Damit das Makro funktioniert, muss selbstverständlich die Objektvariable amAnfang prozedurübergreifend deklariert werden:
Private objBaseShape As Shape
302
Visio-Ereignisse
Auch im folgenden Beispiel wird das Ereignis ShapeAdded verwendet, um denOrt des auf das Zeichenblatt gezogenen Shapes ausfindig zu machen:
Private Sub Document_ShapeAdded(ByVal Shape As IVShape)Dim ShapeOnPage As ShapeDim ReturnedSelection As SelectionDim strShapeText As StringOn Error GoTo errHandler
Set ReturnedSelection = _ Shape.SpatialNeighbors(visSpatialContainedIn, 0#, 0)
If ReturnedSelection.Count = 0 Then Shape.Text = Shape.Name & " befindet sich außerhalb."Else For Each ShapeOnPage In ReturnedSelection strShapeText = strShapeText & Shape.Name & _ " befindet sich im " & ShapeOnPage.Name & vbLf NextEnd If
Shape.Text = strShapeText
errHandler:End Sub
Dabei stellt die Eigenschaft SpatialNeighbors ein Selection-Objekt zur Verfü-gung. Die allgemeine Syntax lautet:
objRet = Shape.SpatialNeighbors(Relation, Tolerance, Flags, [ResultRoot])
303
15 Zugriff auf Visio
Mit Relation ist eine Objektkonstante gemeint, die folgende Werte annehmenkann:
Tab. 15.6:Die Werte von
Relation
Natürlich ist »Document« nicht das einzige Objekt, auf das verwiesen werdenkann und das Ereignisse besitzt. Die Liste der Visio-Objekte, die zur Verfügungstehen, lauten:
Tab. 15.7:Die Liste der
Visio-Objekte
VBA stellt das Schlüsselwort WithEvents zur Verfügung, mit dem eine Ereignis-bearbeitung des Quellen-Objekts möglich ist. Wird beispielsweise ThePage alsVisio-Zeichenblatt deklariert, dann kann damit gearbeitet werden:
Private WithEvents ThePage As Visio.Page
ThePage enthält die beiden Ereignisse ConnectionsAdded und ConnectionsDele-ted. Mit ihnen kann überprüft werden, welcher Verbinder mit welchem Shapeeine Verbindung eingeht oder löst:
Private Sub ThePage_ConnectionsAdded _ (ByVal Connects As Visio.IVConnects)Dim cnt As Connect
For Each cnt In Connects With cnt MsgBox .FromCell.Name & " in " & .FromSheet.Name & _ " wurde verbunden mit " & .ToCell.Name " in " & _ .ToSheet.Name, vbInformation End With
NextEnd Sub
Bezeichnung Wert Bedeutung
visSpatialOverlap 1 Zwei Shapes können sich überlappen.
visSpatialContain 2 Ein Shape beinhaltet vollkommen das andere Shape.
visSpatialContainedIn 3 Ein Shape wird vollkommen von einem anderen Shape eingeschlossen.
visSpatialTouching Ein Shape berührt ein anderes Shape ohne es einzu-schließen.
Application Master Section Window
Cell Masters Selection Windows
Characters Page Shape
Documents Pages Style
InvisibleApp Row Styles
304
Visio-Ereignisse
Private Sub ThePage_ConnectionsDeleted _ (ByVal Connects As Visio.IVConnects)Dim cnt As Connect
For Each cnt In Connects With cnt MsgBox .FromCell.Name & " in " & .FromSheet.Name & _ " wurde gelöst von " & .ToCell.Name & " in " & _ .ToSheet.Name, vbInformation End With
Next
End Sub
Damit dies funktioniert, muss beim Start ThePage festgelegt werden:
Private Sub Document_DocumentOpened _ (ByVal doc As Visio.IVDocument) Set ThePage = Visio.ActivePageEnd Sub
Analog funktioniert auch das folgende Beispiel. Ein Verbinder mit Namen »Ver-binder.1« besitzt zwei benutzerdefinierte Datenfelder »Von« und »Zu«. Diesewerden als Felder vor und nach dem Text » ist der Boss von » eingefügt. Per Pro-grammierung wird nun beim Verknüpfen der Linie an ein Shape der Name desShapes (nicht der Text!) in die Datenfelder geschrieben und diese werden ange-zeigt:
Dim WithEvents pagobj As Visio.Page
Private Sub Document_RunModeEntered(ByVal doc As Visio.IVDocument) Set pagobj = Visio.ActivePageEnd Sub
Private Sub pagobj_ConnectionsAdded(ByVal Connects As Visio.IVConnects)Dim celobj As Visio.CellDim PosPeriod As IntegerDim strFromName As String
strFromName = Connects.FromSheet.NamePosPeriod = InStr(1, strFromName, ".")If PosPeriod <> 0 Then strFromName = Left(strFromName, PosPeriod – 1)End If
If strFromName <> "Verbinder" Then Exit Sub
305
15 Zugriff auf Visio
If Connects(1).FromPart = visEnd Then Set celobj = Connects.FromSheet.Cells("Prop.Zu.Value")ElseIf Connects(1).FromPart = visBegin Then Set celobj = Connects.FromSheet.Cells("Prop.Von.Value")End If
celobj.Formula = Chr$(34) & Connects.ToSheet.Name & Chr$(34)
End Sub
Private Sub pagobj_ConnectionsDeleted _ (ByVal Connects As Visio.IVConnects)Dim celobj As Visio.CellDim PosPeriod As IntegerDim strFromName As String
strFromName = Connects.FromSheet.NamePosPeriod = InStr(1, strFromName, ".")
If PosPeriod <> 0 Then strFromName = Left(strFromName, PosPeriod – 1)End If
If strFromName <> "Verbinder" Then Exit Sub
If Connects(1).FromPart = visEnd Then Set celobj = Connects.FromSheet.Cells("Prop.Zu.Value")ElseIf Connects(1).FromPart = visBegin Then Set celobj = Connects.FromSheet.Cells("Prop.Von.Value")End If
celobj.Formula = Chr$(34) & Chr$(34)
End Sub
Im ersten Teil der beiden Prozeduren wird jeweils überprüft, ob es sich um einenVerbinder handelt. Wenn ja, dann wird überprüft, ob Anfang oder Ende ge-klebt oder gelöst wurde. Bei jeder der vier Aktionen wird in die Zelle »Von«oder »Zu« entweder »« geschrieben (das heißt, der Text wird gelöscht) oder eswird der Name des Shapes in Anführungszeichen hineingeschrieben.
So angenehm einfach sich der Umgang mit den verschiedenen Ereignissen ge-staltet, umso schwieriger ist es, wenn bestimmte Ereignisse gesucht werden. Sosoll beispielsweise abgefangen werden, ob der Benutzer ein Shape verändert,das heißt: verschiebt, formatiert oder in seiner Größe ändert. Das Ereignis»ShapeChanged« gilt erstaunlicherweise nur für Dinge, die nicht in den
306
Visio-Ereignisse
Shapesheet-Zellen gespeichert werden, also Änderungen des Namens, der IDund den drei Werten, die im Menü FORMAT – OBJEKTDATEN in Data1 bis Data3gespeichert werden.
Um das Ereignis-Modell vollständig verwenden zu können, muss ein Sink-Ob-jekt im Add-On erstellt werden. Dies ist ein Klassenmodul, für das die visEvt-Proc-Methode definiert wurde. Das Klassenmodul wird über das Menü EINFÜ-GEN hinzugefügt; im Eigenschaftenfenster kann sein Name geändert werden.
Nachdem mit der Deklaration
Dim sinks As New Collection
in den ThisDocument-Objekten die neue Sammlung deklariert ist, kann in derneuen Klasse mit
Private WithEvents m_shpObj As Visio.Shape
eine Referenz auf ein Visio-Shape hergestellt werden. Damit jedes neue Sink-Objekt der Sammlung hinzugefügt werden kann, wird eine Startprozedur »Init-With« im Klassenmodul erstellt:
Abbildung 15.4: Die Beschriftung ändert sich ...
307
15 Zugriff auf Visio
Public Sub InitWith(ByVal aShape As Visio.Shape) Set m_shpObj = aShapeEnd Sub
Sie wird aufgerufen, wenn ein neues Shape erzeugt wird. Der zugehörige Be-fehl lautet:
Private Sub Document_ShapeAdded(ByVal Shape As Visio.IVShape)Dim sinkObj As New ShapeSink
sinkObj.InitWith Shape
sinks.Add sinkObj, Shape.UniqueID(visGetOrMakeGUID)End Sub
So wird ein Sink-Objekt zu der Sammlung hinzugefügt. Damit das Objekt ein-deutig identifiziert ist, wird die »UniqueID« verwendet.
Wird nun das Shape geändert – verschoben, deformiert oder formatiert – dannkann das Ereignis CellChanged des Objekts »m_shpObj« verwendet werden:
Private Sub m_shpObj_CellChanged(ByVal Cell As Visio.IVCell) MsgBox Cell.Shape.Name & " " & Cell.Name & _ " wurde geändert in: =" & Cell.FormulaEnd Sub
Das Ereignis ShapeChanged ist bekannt:
Private Sub m_shpObj_ShapeChanged(ByVal Shape As IVShape) MsgBox "Ich bin das neue Shape: " & Shape.NameEnd Sub
Und beim Löschen? Dort können beispielsweise die Elemente der Sink-Samm-lung wieder gelöscht werden. Beispielsweise so:
Private Sub Document_BeforeSelectionDelete _ (ByVal Selection As Visio.IVSelection)Dim i As IntegerOn Error Resume Next
For i = 1 To Selection.Count sinks.Remove Selection(i).UniqueID(visGetGUID) Next i
End Sub
Damit kann auf jedes einzelne Ereignis reagiert werden:
Der Programmierer kann Ereignis-Objekte der Ereignis-Liste hinzufügen, undzwar jedes Objekt, das von der Schnittstelle der Visio Automation gefördertwird. Die Ereignis-Liste fördert zwei Methoden zum Anhängen von Vorfällen:
308
Visio-Ereignisse
Event.AddEvent.AddAdvice
Während Erstere ein Ereignis hinzufügt, das gestartet wird, wenn das Ereigniseintritt, fügt AddAdvice ein Ereignis hinzu, das innerhalb des aufgerufenen Pro-gramms eine Handlungsfunktion startet, wenn das Ereignis eintritt. Die Adressedesjenigen, der das Ereignis bearbeitet, wird weitergeleitet. Konkret könntedies so aussehen: Im Objekt »ThisDocument« wird beim Start folgende Proze-dur aufgerufen:
Private Sub Document_RunModeEntered(ByVal doc As Visio.IVDocument)Dim appEvtList As ObjectDim g_sink As New EventSink
Set appEvtList = Application.EventList
appEvtList.AddAdvise visEvtCodeDocSave, g_sink, "", _ "Das Dokument wird gespeichert"
appEvtList.AddAdvise visEvtCodeBefSelDel, g_sink, "", _ "Vor dem Löschen der Shapes"
appEvtList.AddAdvise &H8040, g_sink, "", _ "Ein Shape wird hinzugefügt"
appEvtList.AddAdvise (visEvtDel + visEvtPage), g_sink, _ "", "Seite wird gelöscht"
appEvtList.AddAdvise (&H8010), g_sink, "", _ "Seite wird hinzugefügt"
End Sub
Der Text, der am Ende übergeben wird (»Seite wird hinzugefügt«) ist überflüs-sig. Er dient lediglich als Kommentar. Nun können die einzelnen Ereignisse ab-gefangen werden:
Public Sub VisEventProc(eventCode As Integer, _ sourceObj As Object, eventID As Long, _ seqNum As Long, subjectObj As Object, moreInfo As Variant)
Dim i As Integer
If eventCode = visEvtCodeBefSelDel Then For i = 1 To subjectObj.Count MsgBox subjectObj(i).Name & " wird nun gelöscht!" NextElseIf eventCode = &H8010 Then
309
15 Zugriff auf Visio
MsgBox "Neue Seite"ElseIf eventCode = visEvtCodeDocSave Then MsgBox "Nun wird gespeichert"ElseIf eventCode = visEvtDel + visEvtPage Then MsgBox "Seite wird gelöscht: " & ActivePage.NameElseIf eventCode = &H8040 Then MsgBox "Shape wird nun hinzugefügt: " & subjectObj.NameElse MsgBox "Unbekanntes Ereignis: " & Str$(eventCode)End If
End Sub
Dabei haben die Parameter folgende Bedeutung: Der eventCode entspricht derübergebenen EventID. SourceObj ist die Referenz auf die Quelle des Objekts,eventID die ID des Ereignisses in der EventList der Quelle des Objekts. Mit seq-Num ist die Event sequence ID dieser Visio-Instanz gemeint, subjectObj bezeich-net das Objekt des Ereignisses und moreInfo liefert weitere Informationen überdas Ereignis. Im obigen Fall genügt der eventCode. Dafür stehen dem Benutzerdie folgenden Ereignisse zur Verfügung:
Tab. 15.8:Sämtliche Visio-
Ereignisse
Ereignis EventCode Zahlencode
AfterModal visEvtApp+visEvtAfterModal &H1040
AppActivated visEvtApp+visEvtAppActivate &H1001
AppDeactivated visEvtApp+visEvtAppDeactivate &H1002
AppObjectActivated visEvtApp+visEvtObjActivate &H1004
AppObjectDeactivated visEvtApp+visEvtObjDeactivate &H1008
BeforeDocumentClose visEvtDel+visEvtDoc &H4002
BeforeDocumentSave visEvtCodeBefDocSave &H0007 (7)
BeforeDocumentSaveAs visEvtCodeBefDocSaveAs &H0008 (8)
BeforeMasterDelete visEvtDel+visEvtMaster &H4008
BeforeModal visEvtApp+visEvtBeforeModal &H1020
BeforePageDelete visEvtDel+visEvtPage &H4010
BeforeQuit visEvtApp+visEvtBeforeQuit &H1010
BeforeSelectionDelete visEvtCodeBefSelDel &H0385 (901)
BeforeShapeDelete visEvtDel+visEvtShape &H4040
BeforeStyleDelete visEvtDel+visEvtStyle &H4004
BeforeWindowClosed visEvtDel+visEvtWindow &H4001
BeforeWindowPageTurn visEvtCodeBefWinPageTurn &H02BF (703)
BeforeWindowSelDelete VisEvtCodeBefWinSelDel &H02BE (702)
CellChanged visEvtMod+visEvtCell &H2800
ConnectionsAdded visEvtAdd+visEvtConnect &H8100
310
Visio-Ereignisse
ConnectionsDeleted visEvtDel+visEvtConnect &H4100
DesignModeEntered visEvtCodeDocDesign &H0006 (6)
DocumentAdded visEvtAdd+visEvtDoc &H8002
DocumentChanged visEvtMod+visEvtDoc &H2002
DocumentCreated visEvtCodeCreate &H0001 (1)
DocumentOpened visEvtCodeOpen &H0002 (2)
DocumentSaved visEvtCodeSave &H0003 (3)
DocumentSavedAs visEvtCodeSaveAs &H0004 (4)
EnterScope visEvtCodeEnterScope &H00ca (202)
ExitScope visEvtCodeExitScope &H00cb (203)
FormulaChanged visEvtMod+visEvtFormula &H3000
MarkerEvent visEvtApp+visEvtMarker &H1100
MasterAdded visEvtAdd+visEvtMaster &H8008
MasterChanged visEvtMod+visEvtMaster &H2008
MustFlushScopeBegin-ning
visEvtApp+visEvtCodeBefForced-Flush
&H00C8 (200)
MustFlushScopeEnded visEvtApp+visEvtCodeAfterForced-Flush
&H00C9 (201)
NoEventsPending visEvtApp+visEvtNonePending &H1200
PageAdded visEvtAdd+visEvtPage &H8010
PageChanged visEvtMod+visEvtPage &H2010
RunModeEntered visEvtCodeDocRunning &H0005 (5)
SelectionAdded visEvtCodeSelAdded &H0386 (902)
SelectionChanged visEvtCodeBefWinSelChange &H02BD (701)
ShapeAdded visEvtAdd+visEvtShape &H8040
ShapeChanged visEvtMod+visEvtShape &H2040
ShapeParentChanged visEvtCodeShapeParentChange &H0322 (802)
ShapesDeleted visEvtCodeShapeDelete &H0321 (801)
StyleAdded visEvtAdd+visEvtStyle &H8004
StyleChanged visEvtMod+visEvtStyle &H2004
TextChanged visEvtMod+visEvtText &H2080
ViewChanged visEvtCodeViewChanged &H02c1 (705)
VisioIsIdle visEvtApp+visEvtIdle &H1400
WindowActivated visEvtApp+visEvtWinActivate &H1080
WindowOpened visEvtAdd+visEvtWindow &H8001
WindowChanged visEvtMod+visEvtWindow &H2001 (8193)
WindowTurnedToPage visEvtCodeWinPageTurn &H02C0 (704)
Ereignis EventCode Zahlencode
311
15 Zugriff auf Visio
15.8 Menüs, Symbole und Tastenkombinationen
Eine ganz andere Art der Ereignisse sind die, die der Benutzer bewusst angesto-ßen hat. Dazu zählen Menüeinträge und Symbole, die angeklickt werden kön-nen, oder Tastenkombinationen, die der Benutzer drücken kann.
Für diese Menüs, Icons und Tastenkombinationen steht Ihnen im Ordner »DVS«eine Zeichnung mit dem Objektmodell zur Verfügung. Ein Teil davon beschäf-tigt sich mit den UI-Objekten:
Dabei ist Folgendes wichtig zu wissen:
� Es kann nur ein MenüSet pro Datei erstellt werden.
� Jedes MenüSet beinhaltet eine Liste von Menüs (ihre Zählung beginnt bei0!).
� Jedes Menü enthält eine Liste von MenüItems.
� Ein MenüItem kann eine Liste von MenüItems haben.
� Visio verwendet maximal zwei Toolbarsets (Werkzeugleisten) pro Set.
� Für das gesamte MenüSet gilt die gleiche Accel-Tabelle (Kombinations-Ta-belle).
Folgendes Makro durchläuft alle gespeicherten Menüs, alle Menüpunkte, alleMenüeinträge des Menüs SHAPE und davon alle Untermenüpunkte und listetsie auf:
Sub Menü_Anzeige()Dim appVisio As Visio.ApplicationDim UIObj As Visio.UIObjectDim menuSetsObj As Visio.MenuSetsDim menuSetObj As Visio.MenuSetDim menusObj As Visio.MenusDim menuObj As Visio.MenuDim menuItemsObj As Visio.MenuItemsDim menuItemsObj2 As Visio.MenuItemsDim menuItemObj As Visio.MenuItem
Dim i As IntegerDim strText As String
Set appVisio = Visio.ApplicationSet UIObj = appVisio.BuiltInMenus
Set menuSetsObj = UIObj.MenuSets
For i = 0 To UIObj.MenuSets.Count – 1 strText = strText & ", " & menuSetsObj(i).Caption
312
Menüs, Symbole und Tastenkombinationen
Next
strText = Right(strText, Len(strText) – 2)strText = "Visio enthält folgende Menüs:" & vbCr & strTextMsgBox strTextstrText = ""
Set menuSetObj = menuSetsObj.ItemAtID(visUIObjSetDrawing)
Set menusObj = menuSetObj.Menus
For i = 0 To menusObj.Count – 1 strText = strText & ", " & menusObj(i).CaptionNext
strText = Right(strText, Len(strText) – 2)strText = "Die Menüleiste """ & menuSetObj.Caption & _ """ enthält:" & vbCr & strTextMsgBox strTextstrText = ""
Set menuObj = menusObj(6)
Set menuItemsObj = menuObj.MenuItemsFor i = 0 To menuItemsObj.Count – 1 strText = strText & ", " & menuItemsObj(i).CaptionNext
strText = Right(strText, Len(strText) – 2)strText = "Das Menü """ & menuObj.Caption & """ enthält:" & _ vbCr & strTextMsgBox strTextstrText = ""
Set menuItemObj = menuItemsObj(10)
Set menuItemsObj2 = menuItemObj.MenuItemsFor i = 0 To menuItemsObj2.Count – 1 strText = strText & ", " & menuItemsObj2(i).CaptionNext
strText = Right(strText, Len(strText) – 2)strText = "Der Menüpunkt """ & menuItemObj.Caption & _ """ enthält:" & vbCr & strTextMsgBox strText
End Sub
313
15 Zugriff auf Visio
Die Objekte des obigen Beispiels, die sich aus dem Objektmodell ergeben, kön-nen verwendet werden, um neue Menüs zu kreieren. Wichtig ist dabei, dass derletzte Befehl SetCustomMenus lautet – dann erst werden die Menüs hinzugefügt.Beispielsweise so:
appVisio.SetCustomMenus UIObj
Das Beispielmenü mit neuen Menüeinträgen kann wie folgt erstellt werden.
Sub Neues_Menü()Dim appVisio As Visio.ApplicationDim UIObj As Visio.UIObjectDim menuSetsObj As Visio.MenuSetsDim menuSetObj As Visio.MenuSetDim menusObj As Visio.MenusDim menuObj As Visio.MenuDim menuItemsObj As Visio.MenuItemsDim menuItemObj As Visio.MenuItem
Set appVisio = Visio.ApplicationSet UIObj = appVisio.BuiltInMenusSet menuSetsObj = UIObj.MenuSetsSet menuSetObj = menuSetsObj.ItemAtID(visUIObjSetDrawing)Set menusObj = menuSetObj.MenusSet menuObj = menusObj.AddAt(7)menuObj.Caption = "&Organigramm"
Set menuItemsObj = menuObj.MenuItemsSet menuItemObj = menuItemsObj.AddWith menuItemObj .Caption = "&Layout der untergeordneten" & _ " Elemente festlegen..." .CmdNum = 0 .ActionText = "Layout festlegen" .AddOnName = "Layout_Festlegen" .Enabled = True .MiniHelp = "Legt das Layout fest."End With
Set menuItemObj = menuItemsObj.AddWith menuItemObj .Caption = "&Untergeordnete Elemente verbergen..." .CmdNum = 1 .ActionText = "Untergeordnete Elemente verbergen" .AddOnName = "Elemente_Verbergen" .Enabled = True .MiniHelp = "Blendet untergeordnete Elemente aus."End With
314
Menüs, Symbole und Tastenkombinationen
Set menuItemObj = menuItemsObj.AddWith menuItemObj .Caption = "&Shape verschieben" .CmdNum = 2 .ActionText = "Shape verschieben" .AddOnName = "Shape_Verschieben" .Enabled = True .MiniHelp = "Verschiebt Shapes."End With
appVisio.SetCustomMenus UIObj
End Sub
Da die Objekte selbst zu Sammlungen werden können, kann jeder Menüpunktzum übergeordneten Punkt weiterer Menüs werden. Beispielsweise so:
[...]Set menuItemsObj = menuItemObj.MenuItems
Set menuItemObj = menuItemsObj.AddWith menuItemObj .Caption = "&Links" .CmdNum = 0 .ActionText = "Links Verschieben" .AddOnName = "Verschieben_Links" .Enabled = True .MiniHelp = "Verschiebt nach links."End With
Set menuItemObj = menuItemsObj.AddWith menuItemObj .Caption = "&Rechts" .CmdNum = 1 .ActionText = "Rechts Verschieben" .AddOnName = "Verschieben_Rechts" .Enabled = True .MiniHelp = "Verschiebt nach rechts."End With[...]
Die wichtigsten Eigenschaften der Menüpunkte sind folgende:
Tab. 15.9: Die wichtigsten Eigenschaften der Menüpunkte
Eigenschaft Beschreibung
ActionText der Text, der im Rückgängig-, Wiederholen- und Wiederherstellen-Menü erscheint.
AddOnArgs setzt Argumente für AddOns, beispielsweise:menuItemObj.AddOnArgs = "/DVS=Fun"
315
15 Zugriff auf Visio
Wichtig: Wenn Sie benutzerdefinierte Menüs testen möchten, dann muss eineProzedur, die aufgerufen wird, vorhanden sein, da sonst die Menüpunkte nichtaktivierbar sind!
Damit wird auch deutlich, dass neue Menüs entweder an das Objekt Applica-tion oder auch an ActiveDocument gebunden werden kann.
Wenn Sie Anwendungen schreiben wollen, die auf Visio basieren und größereMenüänderungen enthalten, dann ist es sinnvoll, in einem leeren Dokumentdiese Menüleisten als »*.vsu«-Datei abzuspeichern. Nun kann beim Start einerneuen Vorlage diese Datei daran gebunden werden:
Application.CustomMenusFile = _ "C:\Programme\Visio\Lösungen\Menüs.vsu"
oder:
docObj.CustomMenusFile = _ "C:\Programme\Visio\Lösungen\Menüs.vsu"
Die Bindung selbst kann in der Datei VISIO.INI festgehalten werden.
15.9 Symbole und SymbolleistenÄhnlich wie benutzerdefinierte Menüleisten funktionieren die Symbolleisten.Dabei kann sowohl auf Pixeldateien (»*.ico«) zurückgegriffen werden, die dasBild des Icons anzeigen, als auch und auf *.exe-Dateien, die einen Befehl aus-
AddOnName Damit wird ein Makro oder AddOn aufgerufen, beispielsweise
Sub Verschieben_Rechts
odermenuItemObj.AddOnName = "ShowArgs.EXE"
BuiltIn greift auf Standard-Visio-Objekte zurück.
Caption die Beschriftung, die im Menü erscheint.
CmdNum die Command ID, über die das Menü aufgerufen werden kann.
Enabled Ausführbar
IsSeperator fügt einen Trennstrich ein.
MenuItems gibt die Sammlung der Menüpunkte zurück.
MiniHelp erzeugt einen Hilfetext in der Statusleiste.
Visible macht einen Menüpunkt sichtbar oder unsichtbar.
Methoden
Delete löscht einen Menüpunkt.
Eigenschaft Beschreibung
316
Symbole und Symbolleisten
führen. Oder es können die Standard-Visio-Symbole verwendet werden, um soneue Symbolleisten zu kreieren. Auch diese Dateien könnten abgespeichertwerden, beispielsweise so:
UIObj.SaveToFile ("c:\minmenus.vsu")Set appVisio = Visio.ApplicationappVisio.CustomMenusFile = "c:\minmenus.vsu"appVisio.CustomToolbarsFile = "c:\minmenus.vsu"
Das folgende Beispiel erzeugt eine neue Symbolleiste mit drei neuen Symbolen.Das erste greift auf zwei Dateien (»SIMPLE.EXE« und »SIMPLE.ICO«) zurück, wäh-rend die anderen beiden Icons Visio-Symbole verwenden:
Sub Meine_Symbole()
Dim UIObj As Visio.UIObjectDim appVisio As Visio.ApplicationDim ToolbarSetsObj As Visio.ToolbarSetsDim ToolbarSetObj As Visio.ToolbarSetDim ToolbarsObj As Visio.ToolbarsDim ToolbarObj As Visio.ToolbarDim ToolbarItemsObj As Visio.ToolbarItemsDim ToolbarItemObj As Visio.ToolbarItem
Set appVisio = Visio.ApplicationSet UIObj = CreateObject("Visio.UIObject")UIObj.Name = "Visio Custom Menus"
Set ToolbarSetsObj = UIObj.ToolbarSetsSet ToolbarSetObj = _ ToolbarSetsObj.AddAtID(visUIObjSetDrawing)
Set ToolbarsObj = ToolbarSetObj.ToolbarsSet ToolbarObj = ToolbarsObj.Add
Set ToolbarItemsObj = ToolbarObj.ToolbarItemsSet ToolbarItemObj = ToolbarItemsObj.AddWith ToolbarItemObj .CntrlType = visCtrlTypeBUTTON .CntrlID = visCtrlIDNEW .IconFileName (ActiveDocument.Path & _ "add-ons\simple.ico") .CmdNum = 0 .Enabled = True .AddOnName = "Simple.exe" .ActionText = "Einfaches Beispiel"End With
317
15 Zugriff auf Visio
Set ToolbarItemObj = ToolbarItemsObj.AddWith ToolbarItemObj .CntrlType = visCtrlTypeSTATE_BUTTON .CntrlID = visCtrlIDPENCILTOOL .CmdNum = visCmdDRPencilTool .TypeSpecific1 = visIconIXPENCILTOOL .TypeSpecific2 = 2 .Spacing = visCtrlSpacingFIXED_BEFOREEnd With
Set ToolbarItemObj = ToolbarItemsObj.AddWith ToolbarItemObj .CntrlType = visCtrlTypeSTATE_BUTTON .CntrlID = visCtrlIDPOINTERTOOL .CmdNum = visCmdDRPointerTool .TypeSpecific1 = visIconIXPOINTERTOOL .TypeSpecific2 = 2End With
appVisio.SetCustomToolbars UIObj
End Sub
318
Auch bei Outlook ist das Objektmodell nicht grundsätzlich anders aufgebaut,als in den übrigen Anwendungsprogrammen. An der Spitze der Objekthierar-chie steht das Objekt Application, das Outlook selbst repräsentiert.
Das folgende Beispiel gibt den Typ des aktiven Fensters zurück. Dabei ist jedesFenster ein Explorer- oder ein Inspector-Objekt:
Sub OutlookFensterZugriff()MsgBox TypeName(Application.ActiveWindow)End Sub
Das folgende Beispiel zeigt das aktive Explorer-Fenster an, auch wenn geradedas Inspector-Fenster darüber liegt:
Application.ActiveExplorer.Display
16.1 Neue Elemente erzeugenMit der Methode CreateItem kann ein neues Standardelement erzeugt werden.Das folgende Beispiel erzeugt eine neue Email:
Sub OutlookNeueNachricht()Dim olMail As MailItemSet olMail = Application.CreateItem(olMailItem)With olMail .To = "[email protected]" .Subject = "Biergarten" .Body = "Es bleibt dabei: Treff: 17:00 Uhr im Biergarten." .Attachments.Add _ Source:="c:\Eigene Dateien\Bier.jpg" .DisplayEnd WithEnd Sub
Diese Methode kann folgende Objekte erzeugen:
Tab. 16.1: Neue Objekte werden erzeugt
16 Outlook
Parameter Typ Wert
olAppointmentItem Besprechnung 1
olContactItem Kontakt 2
olDistributionListItem Verteilerliste 7
olJournalItem Journal 4
319
16 Outlook
16.2 Das Namespace-ObjektDas Namespace-Objekt repräsentiert den aktuellen Arbeitsbereich mit der ent-sprechenden Ablage von Outlook-Daten. Es stellt Methoden für An- und Ab-meldung in Outlook bereit, verweist auf voreingestellte Ordner und gibt Ob-jekte zurück. Zudem erlaubt das Namespace-Objekt Zugriff auf viele Methodenund Eigenschaften, die über das Application-Objekt nicht verfügbar sind. DerTyp des Namespace-Objekts ist immer MAPI (Messaging Application Program-ming Interface).
Das folgende Beispiel öffnet den Kalender über die Eigenschaft GetDefaultFol-der:
Sub OutlookKalenderZeigen()Application.GetNamespace("MAPI"). _ GetDefaultFolder(olFolderCalendar).DisplayEnd Sub
Auf folgende Standardorder kann zugegriffen werden:
Tab. 16.2:Die Standardordner
olMailItem Nachricht 0
olNoteItem Notiz 5
olPostItem Bereitstellen 6
olTaskItem Aufgabe 3
Parameter Typ Wert
Parameter Typ Wert
olFolderCalendar Kalender 9
olFolderContacts Kontakte 10
olFolderDeletedItems Gelöschte Objekte 3
olFolderDrafts Entwürfe 16
olFolderInbox Posteingang 6
olFolderJournal Journal 11
olFolderNotes Notizen 12
olFolderOutbox Postausgang 4
olFolderSentMail Gesendete Objekte 5
olFolderTasks Aufgaben 13
320
Das Namespace-Objekt
Das folgende Programm durchläuft alle Benutzerordner und zeigt sie nament-lich an:
Sub OutlookEigeneOrdnerZeigen()Dim i As IntegerDim strONamen As StringFor i = 1 To Application.GetNamespace("MAPI").Folders.Count strONamen = strONamen & vbCr & _ Application.GetNamespace("MAPI").Folders(i).NameNextMsgBox strONamenEnd Sub
Man könnte die deutschen Begriffe der Standardordner durch folgende Befehleherausbekommen:
MsgBox Application.GetNamespace("MAPI"). _ GetDefaultFolder(olFolderDeletedItems).Name
Mit dem Namespace-Objekt können noch weitere Informationen ausgelesenwerden, beispielsweise der Benutzer:
MsgBox Application.GetNamespace("MAPI").CurrentUser
Mit der Methode PickFolder kann ein Dialogfeld (ANSICHT / GEHE ZU / ORD-NER) eingeblendet werden, aus dem der Benutzer seinen Ordner auswählt.Klickt er auf Abbrechen, so wird auch dies abgefangen:
Sub OutlookOrdnerWählen()Dim olNS As NameSpaceDim olMAPIFolder As MAPIFolderSet olNS = Application.GetNamespace("MAPI")Set olMAPIFolder = olNS.PickFolder If olMAPIFolder Is Nothing Then MsgBox "Der Vorgang wurde abgebrochen" Else olMAPIFolder.Display End IfSet olNS = NothingSet olMAPIFolder = NothingEnd Sub
Mit einer rekursiven Funktion können alle Ordner und Unterordner angezeigtwerden:
Sub AlleFoldersAuslisten()Dim olNS As NameSpace
Set olNS = Application.GetNamespace("MAPI")strNamen = ""
321
16 Outlook
ListFolder olNS.Folders, 0
MsgBox strNamen
End Sub
Sub ListFolder(parentfolder As Folders, i As Integer)Dim olFold As MAPIFolder
For Each olFold In parentfolder strNamen = strNamen & vbCr & String(i * 2, vbTab) & _ olFold.Name & ": " & olFold.DefaultMessageClass ListFolder olFold.Folders, i + 1 DoEventsNext
End Sub
16.3 Die ItemsMit diesem Wissen ist es nun nicht mehr schwer, auf einzelne Einträge zuzu-greifen.
Sub KontakteAuflisten()Dim olNS As NameSpaceDim olMAPIFolder As MAPIFolderDim olItems As ItemsDim olKontakt As ContactItemDim strName As String
Set olNS = Application.GetNamespace("MAPI")Set olMAPIFolder = olNS.GetDefaultFolder(olFolderContacts)Set olItems = olMAPIFolder.Items
For Each olKontakt In olItems strName = strName & vbCr & olKontakt.FullName & _ ": " & olKontakt.Email1AddressNext
MsgBox strName
Set olNS = NothingSet olMAPIFolder = NothingSet olItems = Nothing
End Sub
322
Die Items
Natürlich kann man mit Hilfe dieser Prozedur alle Kontakte in eine Excel-Tabelleoder in eine Access-Datenbank exportieren.
Ähnlich wie in Access kann mit der Methode Find ein bestimmter Kontakt ge-sucht werden:
Sub KontaktSuchen()Dim olNS As NameSpaceDim olMAPIFolder As MAPIFolderDim olItems As ItemsDim olKontakt As ContactItemDim strName As StringDim strSuchName As StringOn Error Resume Next
strName = InputBox("Wer soll gesucht werden?" & vbCr & _ "Bitte nur den Zunamen eingeben!")strSuchName = "[LastName]= """ & strName & """"
Set olNS = Application.GetNamespace("MAPI")Set olMAPIFolder = olNS.GetDefaultFolder(olFolderContacts)Set olItems = olMAPIFolder.Items
Set olKontakt = olItems.Find(strSuchName)olKontakt.Display
If Err.Number = 91 Then MsgBox "Der Kontakt " & strName & " wurde nicht gefunden."End If
Set olKontakt = NothingSet olNS = NothingSet olMAPIFolder = NothingSet olItems = Nothing
End Sub
Dabei ist der Filterausdruck eine Zeile der Form:
[LastName]= "Maier"
Die im Filterausdruck zulässigen Vergleichsoperatoren umfassen: >, <, >=, <=,= und <>. Die zulässigen logischen Operatoren sind: And, Not und Or. Einigewichtige Felder finden sich in der folgenden Tabelle:
323
16 Outlook
deutscher Feldname englischer Feldname
Kundennr. CustomerID
Anrede Title
Vorname FirstName
Weiterer Vorname MiddleName
Nachname LastName
Namenszusatz Suffix
Name FullName
Position JobTitle
Kategorien Categories
Spitzname Nickname
Beruf Profession
Geschlecht Gender
Adresse geschäftlich: Straße BusinessAdressStreet
Adresse geschäftlich: Ort BusinessAdressCity
Adresse geschäftlich: Region BusinessAdressState
Adresse geschäftlich: PLZ BusinessAdressPostalCode
Adresse geschäftlich: Land BusinessAdressCountry
Adresse geschäftlich BusinessAdress
Adresse privat: Straße HomeAdressStreet
Adresse privat: Ort HomeAdressCity
Adresse privat: Region HomeAdressState
Adresse privat: PLZ HomeAdressPostalCode
Adresse privat: Land HomeAdressCountry
Adresse privat HomeAdress
Telefon geschäftlich BusinessTelephoneNumber
Fax geschäftlich BusinessFaxNumber
Telefon privat HomeTelephoneNumber
Fax privat HomeFaxNumber
E-Mail EmailAdress1
E-Mail 2 EmailAdress2
Mobiltelefon MobileTelephoneNumber
Autotelefon AutoTelephoneNumber
ISDN ISDNNumber
324
Die Items
In der Items-Auflistung kann Find bei den folgenden Eigenschaften nicht ver-wendet werden. Es führt zu einem Fehler:
Tab. 16.3: Einige Felder der Kontakte
Eine weitere Möglichkeit zu filtern besteht durch die Restrict-Methode:
Sub KategorienAuswählen()Dim olNS As NameSpaceDim olMAPIFolder As MAPIFolderDim olItems As ItemsDim olResItems As ItemsDim olResKontakt As ContactItemDim strName As StringDim strSuchName As StringDim strNamensListe As StringOn Error Resume Next
strName = InputBox("In welcher Kategorie " & _ "soll gesucht werden?")strSuchName = "[Kategorien]= """ & strName & """"
Set olNS = Application.GetNamespace("MAPI")Set olMAPIFolder = olNS.GetDefaultFolder(olFolderContacts)Set olItems = olMAPIFolder.Items
Set olResItems = olItems.Restrict(strSuchName)
For Each olResKontakt In olResItems strNamensListe = strNamensListe & vbCr _ & olResKontakt.FullName
Body Email2EntryID NetMeetingAutoStart
Categories Email3EntryID NetMeetingServer
Children EntryID NetMeetingType
Class HTMLBody RecurrenceState
Companies IsOnlineMeeting ReplyRecipients
CompanyLastFirstNoSpace LastFirstAndSuffix ReceivedByEntryID
CompanyLastFirstSpace-Only
LastFirstNoSpace ReceivedOnBehalfOfEnt-ryID
ContactNames LastFirstNoSpaceCompany ResponseState
Contacts LastFirstSpaceOnly Saved
ConversationIndex LastFirstSpaceOnlyCom-pany
Sent
DLName MemberCount Submitted
Email1EntryID NetMeetingAlias VotingOptions
325
16 Outlook
Next
If strNamensListe = "" Then MsgBox "Die Kategorie " & strName & _ " existiert nicht, oder enthält keinen Eintrag."Else MsgBox strNamensListeEnd If
Set olKontakt = NothingSet olNS = NothingSet olMAPIFolder = NothingSet olItems = Nothing
End Sub
Und so ist es auch nicht mehr schwer, neue Elemente, das heißt Items, zu erstel-len. Im folgenden Beispiel wird in Outlook ein neuer Kontakt generiert:
Sub NeuerKontakt()Dim olNS As NameSpaceDim olMAPIFolder As MAPIFolderDim olKontakt As ContactItemDim strZuName As StringDim strVorName As StringDim strStraße As StringDim strPLZ As StringDim strOrt As StringDim strKategorie As String
strZuName = InputBox("Wie lautet der neue Nachname?")strVorName = InputBox("Wie lautet der neue Vorname?")strStraße = InputBox("Wie lautet die zugehörige Straße?")strPLZ = InputBox("Wie lautet die zugehörige Postleitzahl?")strOrt = InputBox("Wie lautet der zugehörige Ort?")strKategorie = InputBox("Wie lautet die Kategorie?")
Set olNS = Application.GetNamespace("MAPI")Set olMAPIFolder = olNS.GetDefaultFolder(olFolderContacts)Set olKontakt = olMAPIFolder.Items.AddWith olKontakt .FirstName = strVorName .LastName = strZuName .HomeAddressStreet = strStraße .HomeAddressPostalCode = strPLZ .HomeAddressCity = strOrt .Categories = strKategorieEnd With
326
Gruppen und Verknüpfungen
olKontakt.Save
Set olNS = NothingSet olMAPIFolder = NothingSet olKontakt = Nothing
End Sub
Man könnte die Zeile, in der ein neuer Kontakt erstellt wird, auch folgenderma-ßen schreiben:
Set olKontakt = olMAPIFolder.Items.Add(olContactItem)
Die Konstante ist nicht zwingend notwendig, da das Objekt olKontakt als Con-tactItem deklariert wurde.
16.4 Gruppen und VerknüpfungenWill man nun auf Gruppen und deren Verknüpfungen zugreifen, so wird diePanes-Auflistung verwendet:
Sub AlleGruppen()Dim olBar As OutlookBarPaneDim olGroups As OutlookBarGroupsDim strMeldung As StringDim intGruppen As IntegerstrMeldung = "Outlook enthält folgende Gruppen:"Set olBar = Application.ActiveExplorer.Panes. _ Item("Outlook-Leiste")Set olGroups = olBar.Contents.GroupsFor intGruppen = 1 To olGroups.Count strMeldung = strMeldung & vbCr & _ olGroups.Item(intGruppen).NameNextMsgBox strMeldungEnd Sub
Die Panes-Auflistung enthält nur ein Element. Deshalb kann auf sie nicht nurmit Item(»Outlook-Leiste«) zugegriffen werden, sondern auch mit folgenderZeile:
Set olBar = Application.ActiveExplorer.Panes.Item(1)
Letztere Variante ist beim Austausch zwischen verschiedenen Sprachen wichtig,da in den USA diese Zeile so lautet:
Set olBar = Application.ActiveExplorer.Panes. _
Item("OutlookBar")
In der deutschen Anwendung führt diese Zeile zu einem Fehler!
327
16 Outlook
Über die Panes-Auflistung können nun neue Gruppen generiert werden:
Sub NeueGruppe()Dim olBar As OutlookBarPaneDim olGroups As OutlookBarGroupsDim olGroup As OutlookBarGroupDim olTyp As MAPIFolderDim olSC As OutlookBarShortcutDim strName As StringDim intGruppen As Integer
strName = InputBox("Wie lautet die neue Gruppe?")
Set olBar = Application.ActiveExplorer.Panes.Item(1)Set olGroups = olBar.Contents.GroupsSet olGroup = olGroups.Add(strName)
Set olTyp = Application.Session. _ GetDefaultFolder(olFolderCalendar)strName = InputBox("Wie lautet die erste Verknüpfung?" & _ vbCr & "Ein Kalender")Set olSC = olGroup.Shortcuts.Add(olTyp, strName)
Set olTyp = Application.Session. _ GetDefaultFolder(olFolderTasks)strName = InputBox("Wie lautet die zweite Verknüpfung?" & _ vbCr & "Eine Aufgabe.")Set olSC = olGroup.Shortcuts.Add(olTyp, strName)
Set olBar = NothingSet olGroups = NothingSet olGroup = NothingSet olTyp = Nothingsetolsc = Nothing
End Sub
16.5 Ereignisse in OutlookAuch Outlook stellt neben den mächtigen und differenzierten Zugriffsmöglich-keiten auf die Objekte, eine Reihe von Ereignissen zur Verfügung. Genau wie inWord sind sie an zwei verschiedenen Orten zu finden. Im Ordner »MicrosoftOutlook Objekte« befindet sich das Objekt »DieseOutlookSitzung«. Im Listingkann auf das Outlook-Objekt »Application« zugegriffen werden, das folgendeEreignisse besitzt:
328
Ereignisse in Outlook
Private Sub Application_ItemSend _ (ByVal Item As Object, Cancel As Boolean)Private Sub Application_NewMail()Private Sub Application_OptionsPagesAdd _ (ByVal Pages As PropertyPages)Private Sub Application_Quit()Private Sub Application_Reminder(ByVal Item As Object)Private Sub Application_Startup()
Einige Beispiele hierzu:
Der Benutzer ist nicht berechtigt einen Anhang zu versenden. Alle Anhängewerden beim Ereignis ItemSend gelöscht:
Private Sub Application_ItemSend(ByVal Item As Object, _ Cancel As Boolean)Dim olAnhang As AttachmentIf Item.Attachments.Count > 0 And _ Item.MessageClass = "IPM.Note" Then Do Until Item.Attachments.Count = 0 Set olAnhang = Item.Attachments.Item(1) olAnhang.Delete LoopEnd IfEnd Sub
In einem zweiten Beispiel werden in einer Notiz eine Reihe von Schimpfwörterneingeben. Sie sind mit einem Leerzeichen getrennt. Nun wird der Inhalt einerEmail mit diesen Schimpfwörtern verglichen. Stimmt eines der geschriebenenWörtern mit einem nicht erlaubten Wort überein, so wird der Inhalt der Emailgeändert:
Private Sub Application_ItemSend _ (ByVal Item As Object, Cancel As Boolean)Dim strSchimpfwörter() As StringDim olNS As NameSpaceDim olMAPIFolder As MAPIFolderDim olItems As ItemsDim olNotiz As NoteItemDim i As Integer
Set olNS = Application.GetNamespace("MAPI")Set olMAPIFolder = olNS.GetDefaultFolder(olFolderNotes)Set olItems = olMAPIFolder.Items
For Each olNotiz In olItems If olNotiz.Categories = "Schimpfwörter" Then strSchimpfwörter = Split(olNotiz.Body, " ")
329
16 Outlook
End IfNext
For i = 0 To UBound(strSchimpfwörter) MsgBox "-" & strSchimpfwörter(i) & "-" If InStr(Item.Body, strSchimpfwörter(i)) > 0 Then MsgBox "mail darf nicht verschickt werden!" Item.Body = "Dies ist eine Testmail" Exit Sub End IfNext
Set olNS = NothingSet olMAPIFolder = NothingSet olItems = Nothing
End Sub
Natürlich kann man das Ereignis »Senden« auch unterbinden. Alle Ereignisse,die den Parameter Cancel beinhalten, können unterbrochen werden. Da Cancelnur das Absenden unterbindet, muss die Email noch weggeblendet werden.Das Schließen (Close) besitzt drei Konstanten: olDiscard, olPromptForSave undolSave. Mit der ersten wird das Speichern ohne Nachfragen unterbunden. Diesgeschieht mit folgenden Zeilen:
If InStr(Item.Body, strSchimpfwörter(i)) > 0 Then Cancel = True Item.Close (olDiscard) Exit SubEnd If
Das Ereignis Quit wird beim Verlassen aufgerufen. Dort können zur Laufzeitvorgenommene Änderungen wieder gelöscht werden. Beispielsweise Inhaltevon Objektvariablen:
Private Sub Application_Quit()Set olNS = NothingSet olFolders = NothingSet olExpl = NothingSet olinsp = NothingSet olExpl = NothingSet olInboxItems = NothingEnd Sub
Das Startup-Ereignis wird beim Starten von Outlook aufgerufen. Dort könnensich Initiationsroutinen befinden, wie beispielsweise das Erzeugen von Symbo-len:
330
Ereignisse in Outlook
Private Sub Application_Startup()Dim olCB As Office.CommandBarDim olCBB As Office.CommandBarControl
Set olCB = Application.ActiveExplorer. _ CommandBars("Standard")For Each olCBB In olCB.Controls If olCBB.TooltipText = "Formular Abwesenheitsnotiz" Then Exit Sub End IfNext
Set olCBB = olCB.Controls.Add(msoControlButton)With olCBB .TooltipText = "Formular Abwesenheitsnotiz" .Style = msoButtonIcon .FaceId = 1757 .OnAction = "Abwesenheitsnotiz"End With
End Sub
Nun muss sich nur noch ein Makro »Abwesenheitsnotiz« in einem Modul befin-den:
Sub Abwesenheitsnotiz()Dim olMsg As Outlook.MailItemDim olInsp As Outlook.InspectorSet olMsg = Application.CreateItemFromTemplate _ ("c:\Eigene Dateien\Abwesenheitsnotiz.oft")Set olInsp = olMsg.GetInspectorolMsg.DisplayolInsp.WindowState = olNormalWindowEnd Sub
Bevor die übrigen Ereignisse, die Outlook zur Verfügung stellt, verwendet wer-den können, müssen in einem Klassenmodul die entsprechenden Objektvariab-len mit WithEvent deklariert werden; beispielsweise so:
Option ExplicitPublic WithEvents appOL As Outlook.ApplicationPublic WithEvents olFolders As FoldersPublic WithEvents olMailItem As MailItemPublic WithEvents olNS As NameSpacePublic WithEvents olExpl As ExplorerPublic WithEvents olExpl As ExplorersPublic WithEvents olInsp As InspectorPublic WithEvents olInsps As Inspectors
331
16 Outlook
Public WithEvents olInboxItems As ItemsPublic WithEvents olPane As OutlookBarPane
Das Klassenmodul trägt den Namen »clsVBABuch«. Damit sie verwendet wer-den können, muss beim Start von Outlook auf sie referiert werden.
Dim O As New clsVBABuch
Private Sub Application_Startup()Set O.olInsps = Outlook.InspectorsSet O.olExpl = Outlook.ActiveExplorer[…]
Nun kann im Klassenmodul das zugehörige Ereignis gesteuert werden. So stelltder Explorer für das als Explorer deklarierte Objekt folgende Ereignisse zur Ver-fügung:
Private Sub olExpl_Activate()Private Sub olExpl_BeforeFolderSwitch _ (ByVal NewFolder As Object, Cancel As Boolean)Private Sub olExpl_BeforeViewSwitch _ (ByVal NewView As Variant, Cancel As Boolean)Private Sub olExpl_Close()Private Sub olExpl_Deactivate()Private Sub olExpl_FolderSwitch()Private Sub olExpl_SelectionChange()Private Sub olExpl_ViewSwitch()
Natürlich kann man über Ordnerberechtigungen Zugriffsmöglichkeiten steu-ern, es funktioniert allerdings auch per Programmierung. Wenn der Benutzer»René Martin« kein Zugriffsrecht auf den Ordner »Digital Dashboard« hat,dann kann dies wie folgt abgefangen werden:
Private Sub olExpl_BeforeFolderSwitch _ (ByVal NewFolder As Object, Cancel As Boolean)If NewFolder Is Nothing Then Exit Sub
If Application.GetNamespace("MAPI").CurrentUser.Name = _ "Rene Martin" Then If NewFolder.Name = "Digital Dashboard" Then MsgBox "Sie sind nicht berechtigt!" Cancel = True End IfEnd If
End Sub
Im nächsten Beispiel wird überprüft, ob eine der Emails in ihrem Text das Wort»Layout« haben. Diese werden angezeigt, sobald der Benutzer die nächsteEmail anschaut.
332
Ereignisse in Outlook
Private Sub olExpl_SelectionChange()Dim olMail As MailItemDim i As IntegerIf olExpl.CurrentFolder = "Posteingang" Then With olExpl.CurrentFolder For i = 1 To .Items.Count If InStr(.Items(i).Body, "Layout") > 0 Then .Items(i).Display End If NextEnd IfEnd Sub
Interessanter ist vielleicht das »Vorab-Lesen« der Email. Taucht beispielsweise inder nächsten Email ein bestimmtes Schlüsselwort (beispielsweise »Schwein«)auf, dann wird dies vorab angezeigt:
Private Sub olExpl_SelectionChange()Dim olExpl As Outlook.ExplorerDim olSel As Outlook.SelectionDim i As Integer
Set olExpl = Application.ActiveExplorerSet olSel = olExpl.SelectionFor i = 1 To olSel.Count If InStr(olSel.Item(i).Body, "Schwein") > 1 Then MsgBox "Achtung: in dieser Mail tauchen" _ & ""Schweine"" auf!" End IfNextEnd Sub
Abbildung 16.1: Der Inhalt einer Email kann über-prüft werden.
333
16 Outlook
Achtung beim Ereignis Deactivate! Wechselt der Benutzer in ein anderes Pro-gramm, dann wird dieses Ereignis ausgelöst. Wird dort beispielsweise ein Mel-dungsfenster angezeigt, dann muss der Benutzer auf eine der Schaltflächenklicken; damit ist er wieder in Outlook und das Spiel beginnt von vorne ...
Folgende Objekte stehen in Outlook zur Verfügung:
Tab. 16.4:Die Outlook-
Objekte
Objekt Ereignis
Application ItemSend
NewMail
OptionsPagesAdd
Quit
Reminder
StartUp
NameSpace OptionsPagesAdd
Explorers NewExplorer
Explorer Activate
BeforeFolderSwitch
BeforeViewSwitch
Close
Deactivate
FolderSwitch
SelectionChange
ViewSwitch
SyncObject OnError
Progress
SyncEnd
SyncStart
OutlookBarPane BeforeGroupSwitch
BeforeNavigate
OutlookBarGroup GroupAdd
BeforeGroupAdd
BeforeGroupRemove
OutlookBarShortcut ShortcutAdd
BeforeShortcutAdd
BeforeShortcutRemove
Folders FolderAdd
FolderChange
FolderRemove
334
Übung
Ein weiteres Beispiel: In jeder neuen Mail soll ein bestimmter Vorgabetext ste-hen. Im Objekt »DieseOutlookSitzung« wird deshalb deklariert:
Dim O As New clsVBABuch
Private Sub Application_Startup()Set O.olInsp = Outlook.ActiveInspector[...]
Und im Klassenmodul clsVBABuch findet sich folgende Anweisung:
Option ExplicitPublic WithEvents olInsp As Inspector
Private Sub olInsp_Activate() If olInsp.CurrentItem.Parent = "Posteingang" And _ olInsp.CurrentItem = "" Then olInsp.CurrentItem.Body = "Grüß Gott" End IfEnd Sub
Übung
In einem Onlinequiz im Internet hat der Benutzer die Möglichkeit, 16 Fragen zubeantworten. Die Antworten werden per E-Mail an den Ersteller versandt. InOutlook sollen nun diese Fragen auf Richtigkeit überprüft werden. Hat der Teil-nehmer einen oder mehrere Fehler, dann erhält er eine Email, in der die Num-mer der falsch beantworteten Frage steht. Hat er dagegen alle 16 Fragen be-antwortet, dann erhält er ein Lob und ein Zertifikat im Anhang. Dies soll inOutlook per Automatisation gelöst werden.
Die E-Mail enthält in der Betreff-Zeile den Text »Formular bereitgestellt von Mic-rosoft Internet Explorer.« oder »Form posted from Mozilla« beim Netscape Na-
Inspectors NewInspector
Inspector Activate
Close
Deactivate
Items ItemAdd
ItemChange
ItemRemove
Objekt Ereignis
16.6 Übung
335
16 Outlook
vigator. Im Anhang befindet sich eine Datei mit dem Namen POSTDATA.ATToder Form posted from Mozilla.dat. In dieser steht eine Textzeile, die etwa fol-gendermaßen aussieht:
A=A3&B=B3&C=C2&D=D4&E=E4&F=F1&G=G3&H=H1&I=I3&J=J2&K=K4&L=L2&M=M4&N=N4&O=O1&P=P1&Quiz=JavaQuiz01&T1=Hans+Castorp&Ab=Abschicken
Dies sind die 16 korrekten Antworten:
A3, B3, C2, D4, E4, F1, G3, H1, I3, J2, K4, L2, M4, N4, O1 und P1
Und so sieht das Quiz im Internet aus:
Lösung
In Outlook wird in einem Modul in einer Prozedur alle Dateien durchlaufen, undauf ihre Betreff-Zeile überprüft. Hat e ine E-Mail diese Zeile, so wird der AnhangPOSTDATA.ATT in einen Ordner gespeichert.
Dim olItem As MailItemDim strDateiName As String
Sub QuizLösung()Dim olNS As NameSpace
Abbildung 16.2:Das Quiz im
Internet
16.7 Lösung
336
Lösung
Dim olMAPIFolder As MAPIFolderDim i As Integer
Set olNS = Application.GetNamespace("MAPI")Set olMAPIFolder = olNS.GetDefaultFolder(olFolderInbox)
For Each olItem In olMAPIFolder.Items If olItem.Attachments.Count > 0 Then If Left(olItem.Subject, 23) = _ "Formular bereitgestellt" Then For i = 1 To olItem.Attachments.Count If olItem.Attachments.Item(i).DisplayName = _ "POSTDATA.ATT" Or _ olItem.Attachments.Item(i).DisplayName = _ "Form posted from Mozilla"Then strDateiName = "c:\Eigene Dateien\email\" & _ olItem.Attachments.Item(i).DisplayName olItem.Attachments.Item(i).SaveAsFile _ strDateiName
DateiMitAntwortZurück
End If Next End If End IfNext
End Sub
Die Befehlszeile DateiMitAntwortZurück bezieht sich auf ein zweites Makro,über welches aus der abgespeicherten Datei die Informationen ausgelesen wer-den. Sind sie alle korrekt, dann wird ein Anhang eingefügt und die Email ver-sendet, ist allerdings mindestens ein Fehler darin, dann erhält der Teilnehmereinen tröstenden Text als Antwort. Beachten Sie, dass die beiden Variablen ol-Item und strDateiName global deklariert werden. Das Auslesen des Inhalts desAnhangs geschieht über sequentielle Dateien. Es befindet sich nur eine Zeiledarin.
Diese Prozedur könnte wie folgt aussehen:
Sub DateiMitAntwortZurück()Dim intAnhang As IntegerDim intPos1 As IntegerDim intpos2 As IntegerDim strInhalt As StringDim strTeilnehmer As StringDim strAT As String
337
16 Outlook
Open strDateiName For Input As #1 Input #1, strInhaltClose #1
strAT = ""If InStr(strInhalt, "A3") = 0 ThenstrAT = "1. Frage wurde falsch beantwortet!"End IfIf InStr(strInhalt, "B3") = 0 ThenstrAT = strAT & vbCr & "2. Frage wurde falsch beantwortet!"End IfIf InStr(strInhalt, "C2") = 0 ThenstrAT = strAT & vbCr & "3. Frage wurde falsch beantwortet!"End IfIf InStr(strInhalt, "D4") = 0 ThenstrAT = strAT & vbCr & "4. Frage wurde falsch beantwortet!"End IfIf InStr(strInhalt, "E4") = 0 ThenstrAT = strAT & vbCr & "5. Frage wurde falsch beantwortet!"End IfIf InStr(strInhalt, "F1") = 0 ThenstrAT = strAT & vbCr & "6. Frage wurde falsch beantwortet!"End IfIf InStr(strInhalt, "G3") = 0 ThenstrAT = strAT & vbCr & "7. Frage wurde falsch beantwortet!"End IfIf InStr(strInhalt, "H1") = 0 ThenstrAT = strAT & vbCr & "8. Frage wurde falsch beantwortet!"End IfIf InStr(strInhalt, "I3") = 0 ThenstrAT = strAT & vbCr & "9. Frage wurde falsch beantwortet!"End IfIf InStr(strInhalt, "J2") = 0 ThenstrAT = strAT & vbCr & "10. Frage wurde falsch beantwortet!"End IfIf InStr(strInhalt, "K4") = 0 ThenstrAT = strAT & vbCr & "11. Frage wurde falsch beantwortet!"End IfIf InStr(strInhalt, "L2") = 0 ThenstrAT = strAT & vbCr & "12. Frage wurde falsch beantwortet!"End IfIf InStr(strInhalt, "M4") = 0 ThenstrAT = strAT & vbCr & "13. Frage wurde falsch beantwortet!"End IfIf InStr(strInhalt, "N4") = 0 ThenstrAT = strAT & vbCr & "14. Frage wurde falsch beantwortet!"End If
338
Lösung
If InStr(strInhalt, "O1") = 0 ThenstrAT = strAT & vbCr & "15. Frage wurde falsch beantwortet!"End IfIf InStr(strInhalt, "P1") = 0 ThenstrAT = strAT & vbCr & "16. Frage wurde falsch beantwortet!"End If
intPos1 = InStr(strInhalt, "&T1=")strTeilnehmer = Mid(strInhalt, intPos1 + 4)intpos2 = InStr(strTeilnehmer, "&")strTeilnehmer = Left(strTeilnehmer, intpos2 – 1)
MsgBox strTeilnehmer
For intAnhang = 1 To olItem.Attachments.Count olItem.Attachments.Remove (intAnhang)Next
If strAT = "" ThenolItem.Attachments.Add _ "c:\Eigene Dateien\email\Zertifikat.doc"olItem.Body = "Herzlichen Glückwunsch " & strTeilnehmer & _ "," & vbCr & "Sie haben alle Fragen richtig " & vbCr & _ "beantwortet." & vbCr & "Als Belohnung erhalten Sie " & _ "das Rene-Martin-Zertifikat." _ & "Sie finden es im Anhang." & vbCr & _ "Vielen Dank fürs Mitmachen."ElseolItem.Body = "Schade " & strTeilnehmer & _ vbCr & strAT & vbCr & _ "Dennoch: vielen Dank fürs Mitmachen."End IfolItem.DeleteolItem.Send
End Sub
Dieses Makro kann nun entweder an ein Symbol gebunden werden. Dazu wirdim Ordner Microsoft Outlook-Order / DieseOutlookSitzung an das EreignisApplication_Startup folgende Prozedur gebunden:
Private Sub Application_Startup()Dim olCB As Office.CommandBarDim olCBB As Office.CommandBarControl
Set olNS = Application.GetNamespace("MAPI")Set olCB = _ Application.ActiveExplorer.CommandBars("Standard")
339
16 Outlook
For Each olCBB In olCB.Controls If olCBB.TooltipText = "Quiz" Then Exit Sub End IfNext
Set olCBB = olCB.Controls.Add(msoControlButton)With olCBB .TooltipText = "Quiz" .Style = msoButtonIcon .FaceId = 1757 .OnAction = "QuizLösung"End With
End Sub
Alternativ könnte man es auch an das Ereignis beim Markieren der E-Mails hän-gen. Das heißt, das Makro startet in dem Moment, in dem der Quiz-Ersteller mitder Pfeiltaste über die Mails fährt oder den Mauszeiger auf eine Mail setzt.Dazu wird in einem Klassenmodul folgendes Ereignis definiert:
Public WithEvents olExpl As Explorer
Private Sub olExpl_SelectionChange()Dim olExpl As Outlook.ExplorerDim olSel As Outlook.SelectionDim i As Integer
Set olExpl = Application.ActiveExplorerSet olSel = olExpl.SelectionQuizLösungSet olExpl = NothingSet olSel = Nothing
End Sub
Dies muss natürlich im Ereignis Application_StartUp initiiert werden:
Dim O As New clsVBABuch
Private Sub Application_Startup()Set O.olExpl = Outlook.ActiveExplorer[…]End Sub
340
Auf Variablen können nicht nur Zahlen und Texte, sondern auch Objekte gelegtwerden. Die Deklaration ist die gleiche wie bei den übrigen Variablen; lediglichder Einsatz unterscheidet sich: Sie werden mit dem Schlüsselwort Set belegt.Objektvariablen sollten am Ende eines Programms wieder mit Nothing geleertwerden. Auch auf ganze Anwendungen können Objektvariablen verweisen.
17.1 Ein Programm aus einem anderen starten
Wenig Schwierigkeiten bereitet der Start eines Programms aus einem anderenheraus: Hierzu stellt VBA das Schlüsselwort
shell
zur Verfügung. Dabei werden der Name der Datei und der WINDOWSTYLE ver-langt. Über diese Option kann eingegeben werden, wie das Programm geöffnetwird:
Tab. 17.1: Die verschiedenen Varianten ein Pro-gramm zu öffnen
Beispiel: Aus Word heraus soll Paint geöffnet werden:
Sub PaintAuf()Shell "c:\Programme\Zubehör\Mspaint.exe", vbMaximizedFocusEnd Sub
Nun könnte man mit der Anweisung SendKeys Tastenbefehle an Paint schicken,die dort weiter verarbeitet werden. Dabei wird jede Taste durch mindestens einZeichen repräsentiert. Ein einzelnes Zeichen auf der Tastatur kann mit demZeichen selbst angegeben werden. "A" für das Argument string repräsentiertbeispielsweise den Buchstaben A. Sie geben mehrere Zeichen an, indem Sie die
17 Austausch zwischen den Programmen
Konstante Wert Bedeutung
vbHide 0 Das Fenster ist ausgeblendet und erhält den Fokus.
vbNormalFocus 1 Das Fenster hat die ursprüngliche Größe.
vbMinimizedFocus 2 Das Fenster wird als Symbol mit Fokus angezeigt.
vbMaximizedFocus 3 Das Fenster wird maximiert mit Fokus.
vbNormalNoFocus 4 Die zuletzt verwendete Größe wird wiederhergestellt, der Fokus bleibt auf dem aktiven Programm.
vbMinimizedNo-Focus
5 Das Fenster wird als Symbol geöffnet und erhält nicht den Fokus.
341
17 Austausch zwischen den Programmen
Zeichen aneinanderhängen. "ABC" für string repräsentiert zum Beispiel dieBuchstaben A, B und C.
Das Pluszeichen (+), Caret-Zeichen (^), Prozentzeichen (%), die Tilde (~) und dieKlammern ( ) haben bei der SendKeys-Anweisung eine spezielle Bedeutung. Siemüssen jedes dieser Zeichen in geschweifte Klammern einschließen ({}), um esverwenden zu können. Für das Pluszeichen geben Sie beispielsweise {+}an.Eckige Klammern ([ ]) haben bei der SendKeys-Anweisung zwar keine spezielleBedeutung, müssen aber auch in geschweifte Klammern eingeschlossen wer-den, da sie in anderen Anwendungen eine spezielle Bedeutung haben, insbe-sondere im Zusammenhang mit dynamischem Datenaustausch (DDE). Die Zei-chen für die geschweiften Klammern legen Sie unter Verwendung von {{} und{}} fest.
Für Zeichen, die beim Drücken einer Taste nicht angezeigt werden (z.B. die (¢)
oder (ÿ)-TASTE) und für bestimmte Aktionstasten können Sie die folgendenCodes verwenden:
Tab. 17.2:Die Tasten für
SendKeys
Taste Code
(æ_) {BACKSPACE}, {BS} oder {BKSP}
(PAUSE) {BREAK}
(º) {CAPSLOCK}
(Entf) {DELETE} oder {DEL}
(¼) {DOWN}
(Ende) {END}
(¢) {ENTER}oder ~
(Esc) {ESC}
(Hilfe) {HELP}
(Pos1) {HOME}
(Einfg) {INSERT} oder {INS}
(æ) {LEFT}
(Num) {NUMLOCK}
(Bild¼) {PGDN}
(Bild½) {PGUP}
(Druck) {PRTSC}
(Æ) {RIGHT}
(Rollen) {SCROLLLOCK}
(ÿ) {TAB}
(½) {UP}
342
Zugriff auf Office-Programme
Sie können Tastenkombinationen mit der (ª), (Strg)-TASTE oder (Alt)-TASTEangeben, indem Sie vor dem normalen Tasten-Code einen oder mehrere derfolgenden Codes angeben:
Tab. 17.3: Die Sondertasten
17.2 Zugriff auf Office-ProgrammeSoll dagegen ein Programm direkt per Automatisation angesteuert werden,dann stehen Ihnen die beiden Befehle
CreateObject und
GetObject
zur Verfügung. CreateObject ist dann sinnvoll, wenn man nicht weiß, ob dieAnwendung, die angesteuert wird, überhaupt auf dem Computer existiert. Dieskönnte mit der Fehlernummer 429 angefangen werden.
(F1) {F1}
(F2) {F2}
(F3) {F3}
(F4) {F4}
(F5) {F5}
(F6) {F6}
(F7) {F7}
(F8) {F8}
(F9) {F9}
(F10) {F10}
(F11) {F11}
(F12) {F12}
(F13) {F13}
(F14) {F14}
(F15) {F15}
(F16) {F16}
Taste Code
Taste Code
(ª) +
(Strg) ^
(Alt) %
343
17 Austausch zwischen den Programmen
[...]On Error Resume NextSet objApp = CreateObject("Access.Application.9")If Err = 429 Then MsgBox "Access ist nicht installiert"[...]
Dagegen wird mit GetObject auf ein schon laufendes Programm zugegriffen.Mit diesem Befehl kann überprüft werden, ob das Programm schon läuft. Bei-spielsweise so:
[...]On Error Resume NextSet objApp = GetObject(, "Access.Application.9")If Err = 429 Then MsgBox "Access läuft noch nicht! Bitte starten!"[...]
Das folgende Beispiel setzt auf die Variable XLProg das Programm Excel, weistdiesem Objekt die Methode Open von Excel zu und zeigt einen Zellinhalt an,ohne dass Excel sichtbar in der Taskleiste erscheint. Damit die ObjektvariablexlProg nicht gefüllt bleibt, wird XLProg auf nothing gesetzt:
Sub Excel_Auf_Und_Zeige_WasDim XlProg As ObjectDim Xl1 As ObjectSet XlProg = CreateObject("Excel.Application.8")Set XL1 = xlprog.Application.Workbooks.Open _ ("C:\Eigene Dateien\Uebungsdateien\Kalender.xls") MsgBox XL1.worksheets(1).Range("A1").Value XlProg.Quit
Set XL1 = NothingSet XLProg = NothingEnd Sub
Es geht auch mit der Funktion GetObject:
Sub Excel_Auf_Und_Zeige_WasSet XL1 = _ GetObject("C:\Eigene Dateien\Uebungsdateien\Kalender.xls")MsgBox XL1.worksheets(1).Range("A1").ValueSet XL1 = NothingEnd Sub
In der Regel wird eine lokale Variable »zerstört«, wenn die Prozedur, in der siedeklariert wurde, nicht mehr ausgeführt wird. Allerdings zeigt die Praxis, dassdennoch in einigen Fällen der Arbeitsspeicher belastet bleibt. Deshalb solltenSie alle Objektvariablen am Ende des Programms auf Nothing setzen, da sonstmöglicherweise die Variable gefüllt bleibt und den Arbeitsspeicher belastet!
344
Zugriff auf Office-Programme
Wenn Sie möchten, dass das Programm sichtbar wird, so können Sie seine Ei-genschaft Visible auf True setzen, wie in obigem Beispiel:
xl1.Visible = True
Sollen nun Daten aus einer Excel-Tabelle herausgelesen werden, so sind hierfürdie Excel-Befehle zu verwenden, die auf das Objekt angewendet werden. Dasfolgende Beispiel, das von Word aus aufgerufen wird, startet eine Excel-Dateiund liest alle Namen in ein Meldungsfenster aus:
Sub Excel_Auf_Und_Zeige_Was1()Dim XL1 As ObjectDim xlBereich As ObjectDim strText As StringDim i As IntegerOn Error Resume Next
Set XL1 = _ GetObject("C:\Eigene Dateien\Sonstiges\Test.xls")
With XL1 Set xlBereich = .Worksheets(1).[A1].CurrentRegion For i = 1 To xlBereich.Rows.Count strText = strText & .Worksheets(1).Cells(i, 1) & ", " NextEnd With
MsgBox strText
Set XL1 = Nothing
End Sub
Die Befehle GetObject und CreateObject sind nur dann nötig, wenn kein Ver-weis auf das fremde Programm vorliegt. Man kann die Programmbibliothek vonExcel über das Menü EXTRAS / VERWEISE einbinden. Dann funktioniert das Pro-gramm etwas eleganter:
Sub Excel_Auf_Und_Zeige_Was2()Dim xlDatei As Excel.WorkbookDim xlBereich As Excel.RangeDim i As IntegerDim strText As StringOn Error Resume Next
Set xlDatei = _ GetObject("C:\Eigene Dateien\Sonstiges\Test.xls")
With xlDatei
345
17 Austausch zwischen den Programmen
Set xlBereich = .Worksheets(1).[A1].CurrentRegion For i = 1 To xlBereich.Rows.Count strText = strText & .Worksheets(1).Cells(i, 1) & ", " NextEnd With
MsgBox strTextxlDatei.CloseSet xlBereich = NothingSet xlDatei = Nothing
End Sub
Abbildung 17.1:Ein Verweis auf die
Excel-Bibliothekwird eingefügt
346
Übungen zum Programmaustausch Word nach Excel
Übung 1
Lassen Sie sich in Word in einem Listenfeld eines Dialogs alle Namen anzeigen,die in einer Excel-Liste in einer Spalte stehen.
Übung 2
Ein Klick auf die Ok-Schaltfläche fügt in Word nicht nur den ausgewählten Na-men ein, sondern auch die zugehörige Straße, Postleitzahl und den Wohnort.
Übung 3
Schreiben Sie einen Dialog für Rechnungen, der in Word geöffnet wird. Mit sei-ner Hilfe wird eine Rechnung in Word erstellt und das Ergebnis in eine Excel-Ta-belle geschrieben.
Übung 4
Aus Word wird eine Excel-Datei geöffnet. In dieser befindet sich ein Makro. Die-ses wird beim Öffnen gestartet.
Lösung 1
Private Sub UserForm_Activate()
On Error Resume Next
Set xlApp = _ GetObject("C:\Eigene Dateien\Sonstiges\Verlage.xls")
Me.lstVerlage.Clear
With xlApp Set Bereich = .worksheets(1).[A1].CurrentRegion For i = 2 To Bereich.Rows.Count
Me.lstVerlage.AddItem .worksheets(1). _ Cells(i, 1).Value
17.3 Übungen zum Programmaustausch Word nach Excel
17.4 Lösungen
347
17 Austausch zwischen den Programmen
NextMe.lstVerlage.Value = Me.lstVerlage.List(0)End With
Me.lstVerlage.Value = 1
End Sub
Lösung 2
Dazu muss die Variable XLApp und xlMappe global deklariert werden:
Public xlApp As Excel.ApplicationPublic xlmappe As Excel.Workbook
und darf nicht beim Füllen der Box auf Nothing gesetzt werden.
Die Prozedur der OK-Schaltfläche lautet folglich:
Private Sub cmdOk_Click()On Error Resume Nexti = Me.lstVerlage.ListIndex + 2If Application.ActiveDocument.AttachedTemplate = _ "Standardbrief.dot" Then
Selection.GoTo What:=wdGoToBookmark, Name:="Adresse"Selection.TypeText Text:=xlmappe.worksheets(1).Cells _ (i, 1).Value' zuerst der VerlagsnameSelection.GoTo What:=wdGoToBookmark, Name:="Ansprechpartner"Selection.TypeText Text:=xlmappe.worksheets(1).Cells _ (i, 2).Value'Dann der Ansprechpartner
Selection.GoTo What:=wdGoToBookmark, Name:="Straße"Selection.TypeText Text:=xlmappe.worksheets(1).Cells _ (i, 3).ValueSelection.GoTo What:=wdGoToBookmark, Name:="Ort"Selection.TypeText Text:=xlmappe.worksheets(1).Cells _ (i, 4).Value & _ " " & xlmappe.worksheets(1).Cells(i, 5).Value'und schließlich Straße, Plz und OrtEnd If
Unload MeEnd Sub
348
Lösungen
Vergessen Sie nicht folgende Prozedur:
Private Sub UserForm_Deactivate()Set xlmappe = NothingSet xlApp = NothingEnd Sub
und selbstverständlich nicht die modulweite Deklaration von XL1!
Lösung 3
Sub Rechnung_Erstellen()Dim xlsApp As Excel.ApplicationDim xlsDatei As Excel.WorkbookDim xlsTabelle As Excel.WorksheetDim xlsZelle As Excel.RangeDim iZeilenanzahl As Integer'Deklarationen für Excel[...]
Dann werden die Excelobjekte gefüllt:
Set xlsApp = Excel.ApplicationSet xlsDatei = _GetObject("C:\Eigene Dateien \VBABuch\officeVBA\Bilanz.xls")Set xlsTabelle = xlsDatei.Sheets(Trim(Str(Year(Date))))Set xlsZelle = xlsTabelle.Range("A1")iZeilenanzahl = xlsZelle.CurrentRegion.Rows.Count
Schließlich können die gewünschten Informationen (Programmname, Preis undRechnungsnummer) in die richtigen Zellen geschrieben werden. Dabei bestehtwenig Unterschied zum »reinen« Excel-Programmieren.
[...]If xlsZelle.Offset(iZeilenanzahl – 1, 0).Value + 1 <> _ .txtRechnungsnummer.Text Then If MsgBox("Bitte gib die korrekte Nummer ein." & vbCr & _ "Die nächste fortlaufende Rechnungsnummer wäre: " & _ Format(Date, "yy") & iZeilenanzahl & vbCr & vbCr & _ "Soll sie verwendet werden? ", _ vbYesNo + vbInformation, "Achtung") = vbYes Then xlsZelle.Offset(iZeilenanzahl, 0).Value = _ xlsZelle.Offset(iZeilenanzahl – 1, 0).Value + 1 Else xlsZelle.Offset(iZeilenanzahl, 0).Value = _ .txtRechnungsnummer.Text End IfElse xlsZelle.Offset(iZeilenanzahl, 0).Value = _ .txtRechnungsnummer.Text
349
17 Austausch zwischen den Programmen
End If
xlsZelle.Offset(iZeilenanzahl, 2).Value = iSchulungstage
xlsZelle.Offset(iZeilenanzahl, 3).Value = dblPreis
xlsDatei.Save
Set xlsApp = NothingSet xlsDatei = NothingSet xlsTabelle = NothingSet xlsZelle = Nothing
End With
Unload frmSchulungEnd Sub
Lösung 4
Sub ExcelMakroStart()Dim xlapp As Excel.ApplicationSet xlapp = Excel.ApplicationWith xlapp .Workbooks.Open _ "c:\Eigene Dateien\Uebungsdateien\Excel\Test.xls" .Run "Test.xls!Versuch" .Workbooks("Test.xls").CloseEnd With
End Sub
Übung 1
In einer Excel-Adressdatenbank stehen Name, Straße und Wohnort von ver-schiedenen Personen. Befindet sich der Cursor in einer bestimmten Zeile, dannruft ein Makro eine Worddokumentvorlage auf und trägt die Daten ein.
Übung 2
Aus einer Notenliste, die für eine Schulklasse in Excel generiert wurde, werdendie Noten ausgelesen und damit Zeugnisse in Word erstellt.
17.5 Übungen zum Programmaustausch Excel nach Word
350
Lösungen
Übung 3
Da der Befehl PrivateProfileString nicht in Excel zur Verfügung steht, mussauf Word zugegriffen werden, um ihn verwenden zu können. Schreiben Sie einMakro, das für eine Excel-Vorlage eine neue Rechnungsnummer generiert, in-dem auf eine ini-Datei zugegriffen wird.
Übung 4
In Kapitel 13.11 in Übung 1 – 5 wird ein Diagramm erstellt. Mit welchen zusätz-lichen Befehlen kann man es nach Word kopieren?
Lösung 1
Die Worddokumentvorlage heißt »Rechnungsformular«. In ihr sind drei Text-marken definiert: »Adresse«, »Straße« und »Ort«. Die Exceltabelle ist wie folgtaufgebaut:
Sub ExcelDatenNachWord()Dim wdapp As Word.ApplicationDim wdDok As Word.DocumentDim xlZelle As RangeDim intZeile As Integer
Set xlZelle = ActiveCellintZeile = xlZelle.Row
17.6 Lösungen
Abbildung 17.2: Die Excel-Tabelle mit den Namen
351
17 Austausch zwischen den Programmen
If Cells(intZeile, 1).Value = "" Then MsgBox "Der Cursor wurde nicht richtig platziert!" Exit SubEnd If
Set wdapp = Word.ApplicationSet wdDok = wdapp.Documents.Add("Rechnungsformular")
With wdapp With .Selection .GoTo what:=wdGoToBookmark, Name:="Adresse" If Cells(intZeile, 2).Value = 10 Then .TypeText Text:="Frau" Else .TypeText Text:="Herrn" End If .TypeParagraph .TypeText Text:=Cells(intZeile, 3).Value .TypeParagraph .TypeText Text:=Cells(intZeile, 4).Value .TypeText Text:=" " .TypeText Text:=Cells(intZeile, 5).Value .GoTo what:=wdGoToBookmark, Name:="Straße" .TypeText Text:=Cells(intZeile, 6).Value .GoTo what:=wdGoToBookmark, Name:="Ort" .TypeText Text:=Cells(intZeile, 7).Value .TypeText Text:=" " .TypeText Text:=Cells(intZeile, 8).Value End WithEnd With
Set wdapp = NothingSet wdDok = NothingSet xlZelle = Nothing
End Sub
Das Makro überprüft zuerst, ob sich der Cursor innerhalb des Datenbereichsbefindet. Falls ja, so wird Word gestartet, die Dokumentvorlage geöffnet undan den entsprechenden Textmarken die Inhalte der Zeile intZeile der entspre-chenden Spalten eingefügt.
Lösung 2
In einer Excel-Tabelle stehen in einer Spalte die Namen der Schüler. Daneben be-finden sich – nach Fächern geordnet – ihre Noten.
352
Lösungen
Diese Daten werden über eine Funktion in »Noten-Text« umgewandelt:
Function Notentext(strNote As String) As StringSelect Case strNote Case 1: Notentext = "sehr gut" Case 2: Notentext = "gut" Case 3: Notentext = "befriedigend" Case 4: Notentext = "ausreichend" Case 5: Notentext = "mangelhaft" Case 6: Notentext = "ungenügend" Case Else: Notentext = "" End SelectEnd Function
Das eigentliche Programm ermittelt nun die einzelnen Noten der Schüler undträgt den »formatierten« Text an den entsprechenden Textfeldern der Word-Datei ein:
Sub ZeugnisErstellen()Dim wdapp As Word.ApplicationDim wdDatei As Word.DocumentDim intZeilen As IntegerDim intZähler As IntegerDim xlZelle As Range
Set xlZelle = _ Application.ActiveWorkbook.ActiveSheet.Range("A1")intZeilen = xlZelle.CurrentRegion.Rows.Count
Set wdapp = Word.Application
Abbildung 17.3: Die fiktiven Noten der fiktiven Klasse
353
17 Austausch zwischen den Programmen
For intZähler = 1 To intZeilenSet wdDatei = Word.Documents.Add("Zeugnis")With wdapp With .Selection .GoTo what:=wdGoToBookmark, Name:="Name" .TypeText Text:=xlZelle.Cells(intZähler, 1).Value .GoTo what:=wdGoToBookmark, Name:="Klasse" .TypeText Text:=ActiveSheet.Name .GoTo what:=wdGoToBookmark, Name:="Schuljahr" .TypeText Text:=Format(Year(Date) – 1, "yyyy") & _ "/" & Format(Year(Date), "yyyy") .GoTo what:=wdGoToBookmark, Name:="Deutsch" .TypeText Notentext(xlZelle.Cells(intZähler, 2).Value) .GoTo what:=wdGoToBookmark, Name:="Englisch" .TypeText Notentext(xlZelle.Cells(intZähler, 3).Value) .GoTo what:=wdGoToBookmark, Name:="Mathematik" .TypeText Notentext(xlZelle.Cells(intZähler, 4).Value) .GoTo what:=wdGoToBookmark, Name:="Physik" .TypeText Notentext(xlZelle.Cells(intZähler, 5).Value) .GoTo what:=wdGoToBookmark, Name:="Erdkunde" .TypeText Notentext(xlZelle.Cells(intZähler, 6).Value) .GoTo what:=wdGoToBookmark, Name:="Geschichte" .TypeText Notentext(xlZelle.Cells(intZähler, 7).Value) .GoTo what:=wdGoToBookmark, Name:="Musik" .TypeText Notentext(xlZelle.Cells(intZähler, 8).Value) .GoTo what:=wdGoToBookmark, Name:="Kunst" .TypeText Notentext(xlZelle.Cells(intZähler, 9).Value) End WithEnd WithNext
Set wdapp = NothingSet wdDatei = NothingSet xlZelle = NothingEnd Sub
Lösung 3
In der Excel-Mustervorlage befindet sich im Ereignis Workbook_Open folgenderCode:
Private Sub Workbook_Open()Dim wdapp As Word.Application
Set wdapp = Word.ApplicationdblRe = wdapp.System.PrivateProfileString _ ("c:\Rechnungsnummer.ini", _ "Rechnungsnummer", "Re")
354
Übung zum Programmaustausch Outlook nach Word und Excel
wdapp.System.PrivateProfileString _ ("c:\Rechnungsnummer.ini", _ "Rechnungsnummer", "Re") = dblRe + 1Application.ActiveWorkbook.Sheets(1) _ .Range("E7").Value = dblReSet wdapp = Nothing
End Sub
Lösung 4
Sub DiagrammNachWord(xlchart As ChartObject)Dim wdapp As Word.ApplicationDim wdDokument As Word.DocumentWith xlDia.ChartObjects(1).Activate ActiveChart.ChartArea.Select ActiveChart.ChartArea.CopyEnd WithSet wdapp = Word.Applicationwdapp.Visible = TrueSet wdDokument = wdapp.Documents.AddwdDokument.Paragraphs(1).Range.Paste
Set wdDokument = NothingSet wdapp = Nothing
End Sub
Dieses Programm wird von dem Programm, welches das Diagramm erzeugt,aufgerufen:
[...]DiagrammNachWord xlchart[...]
wenn xlChart wie folgt deklariert wurde:
Dim xlchart As ChartObject
Übung
Lassen Sie sich in einem Word-Dokument und einer Excel-Datei alle Outlook-Adressen auflisten.
17.7 Übung zum Programmaustausch Outlook nach Word und Excel
355
17 Austausch zwischen den Programmen
Lösung
Sub KontakteAuflistenUndNachExcel()Dim olNS As NameSpaceDim olMAPIFolder As MAPIFolderDim olItems As ItemsDim olKontakt As ContactItemDim xlapp As Excel.ApplicationDim xlDatei As WorkbookDim xlZelle As Excel.Range
Set olNS = Application.GetNamespace("MAPI")Set olMAPIFolder = olNS.GetDefaultFolder(olFolderContacts)Set olItems = olMAPIFolder.Items
Set xlapp = Excel.ApplicationSet xlDatei = xlapp.Workbooks.Addxlapp.Visible = TrueSet xlZelle = xlDatei.Worksheets(1).Range("A1")For Each olKontakt In olItems xlZelle.Value = olKontakt.FullName xlZelle.Offset(0, 1).Value = olKontakt.Email1Address Set xlZelle = xlZelle.Offset(1, 0)Next
Set olNS = NothingSet olMAPIFolder = NothingSet olItems = Nothing
End Sub
Der Code muss für Word nur wenig verändert werden:
Sub KontakteAuflistenUndNachWord()Dim olNS As NameSpaceDim olMAPIFolder As MAPIFolderDim olItems As ItemsDim olKontakt As ContactItemDim wdapp As Word.ApplicationDim wdDatei As Word.DocumentDim wdTabelle As Word.Table
Set olNS = Application.GetNamespace("MAPI")Set olMAPIFolder = olNS.GetDefaultFolder(olFolderContacts)Set olItems = olMAPIFolder.Items
17.8 Lösung
356
Übung zum Programmaustausch Visio nach Excel
Set wdapp = Word.ApplicationWith wdapp Set wdDatei = .Documents.Add _ (DocumentType:=wdNewBlankDocument) .Visible = True
wdDatei.Tables.Add Range:=.Selection.Range, _ NumRows:=1, NumColumns:=2
For Each olKontakt In olItems .Selection.TypeText Text:=olKontakt.FullName .Selection.MoveRight Unit:=wdCell .Selection.TypeText Text:=olKontakt.Email1Address .Selection.MoveRight Unit:=wdCell NextEnd WithSet olNS = NothingSet olMAPIFolder = NothingSet olItems = Nothing
End Sub
Übung
In Visio wird ein Auswahldialog erstellt, mit dessen Hilfe der Benutzer alleShapenamen in einer Exceltabelle eintragen lassen kann. Dabei hat der Benut-zer die Möglichkeit, zwischen den Namen aller Shapes des Zeichenblattes, denNamen der markierten Shapes und den Namen der Shapes eines Layers zu wäh-len.
Lösung
Gestartet wird der Dialog, indem alle vorhandenen Layer in einer Comboboxaufgelistet werden:
17.9 Übung zum Programmaustausch Visio nach Excel
17.10 Lösung
357
17 Austausch zwischen den Programmen
Private Sub UserForm_Initialize()Dim layLayer As LayerFor Each layLayer In ActivePage.Layers cmbLayer.AddItem layLayer.NameNextcmbLayer.Text = cmbLayer.List(0)End Sub
Klickt nun der Benutzer auf Ok, dann wird Excel geöffnet und in einer neuenTabelle werden alle Shapenamen eingetragen. Analog könnte man auchbestimmte Datenfelder, Beschriftungen oder Ähnliches speichern:
Private Sub cmdOk_Click()Dim appExcel As Excel.ApplicationDim xlsDatei As Excel.WorkbookDim xlsTabelle As Excel.WorksheetDim xlsZelle As Excel.RangeDim intZähler As Integer, intLayer As IntegerDim intZeiger As Integer
Set appExcel = CreateObject("Excel.application.9")appExcel.Visible = TrueSet xlsDatei = appExcel.Workbooks.AddSet xlsTabelle = xlsDatei.Sheets(1)Set xlsZelle = xlsTabelle.Range("A1")
xlsZelle.Value = "Shape-Liste:"If Me.optAlle.Value = True ThenFor intZähler = 1 To ActivePage.Shapes.Count xlsZelle.Offset(intZähler, 0).Value = _ ActivePage.Shapes(intZähler).NameNextElseIf Me.optMarkierung.Value = True ThenFor intZähler = 1 To ActiveWindow.Selection.Count xlsZelle.Offset(intZähler, 0).Value = _
Abbildung 17.4:Der Auswahldialog
358
Lösung
ActiveWindow.Selection(intZähler).NameNextElseintZeiger = 1For intZähler = 1 To ActivePage.Shapes.Count For intLayer = 1 To _ ActivePage.Shapes(intZähler).LayerCount If ActivePage.Shapes(intZähler).Layer(intLayer).Name _ = Me.cmbLayer.Text Then xlsZelle.Offset(intZeiger, 0).Value = _ ActivePage.Shapes(intZähler).Name intZeiger = intZeiger + 1 End If NextNextEnd If
Set xlsDatei = NothingSet xlsTabelle = NothingSet xlsZelle = NothingUnload MeEnd Sub
359
17 Austausch zwischen den Programmen
Abbildung 17.5:Die Zeichnung
und das Ergebnis(für einen Layer)
360
Stichwortverzeichnis
!! 16# 17$ 17% 16& 16@ 17
AAbs 34Accelerator 119Access 11Achsen 249Activate 118, 233, 263ActiveCell 236ActiveControl 135ActiveDocument 199, 284ActiveDocument.PrintOut 200ActivePage 289, 305ActivePrinter 199ActiveWindow 197, 199, 218ActiveWorkbook 231Add 154, 233, 270, 284, 286, 309AddAdvice 309AddControl 118AddIns 231AddLabel 274Add-On 307AddPicture 273AddSection 297Adressdatenbank 350AlternativeText 278AND 23Anfangskapital 61Anzeige 115, 124API 111Append 83Application 197, 231, 269, 282, 283, 319Application.Caption 220, 231, 269Application.ListCommands 220Application.System 221Application-Objekt 179
Arbeitsbeginn 45Arbeitslohn 45Array 18Asc 36, 160Ascii 127, 160, 227, 228ASCII-Code 36Assistent 183Asymptote 250Atn 33AutoCAD 11Automatisation 343
BBackground 271, 286BackPage 287Balloon-Objekt 183Bedingungsschleife 60Befehlsschaltfläche 115, 118BeforeDragOver 118BeforeDropAndPaste 118Beschriftungsfeld 115, 124Bibliothek 346Bildlaufleiste 115, 159Boolean 16BringToFront 291BuiltIn 316BuiltInDocumentProperties 222ByRef 54Byte 16ByVal 54
CCall 53Call by Reference 54Call by Value 54Caption 127Cbool 42Cbyte 42Ccur 42Cdate 42CDbl 42CDec 42
361
Stichwortverzeichnis
Cells 239, 301Characters 241ChartObject 252ChDir 78ChDrive 78Checkbox 115, 134, 214Choose 25Chr 36, 160CInt 42Clear 154, 236Click 118Clippit.act 184CLng 42Close 199, 232, 269, 285Codefarbe 16Collatz'sches Problem 66Collection 307Columns 239Combine 291Combobox 152Commandbar 115CommandBars 186Commandbutton 118Connect 304ConnectionsAdded 304, 305ConnectionsDeleted 305Const 17Controls 186ControlTipText 118Copy 271, 291Corel Draw 11Cos 33CreateItem 319CreateObject 343CSng 42CStr 43CurDir 78Currency 17CurrentRegion 249CustomDictionaries 222CustomDocumentProperties 223Cut 271Cvar 43
Ddas Page-Objekt 286Date 17, 37
DateAdd 37DateDiff 37Dateimanager 179Dateipfad 44Dateizugriff 197Datenfeld 18DatePart 38DateSerial 37DateValue 37Day 38DblClick 118Deactivate 118Debuggen 104Dechiffrieren 230Declare 111Default 119Delete 233, 271, 286, 291DeleteSection 298DerText 301DeselectAll 291Determinante 89Developer-Version 111Diagramm 249, 281Diagramm-Assistent 249Dialog 219Dialogbox 115Dialogs 219, 223DieDaten 301Digital Dashboard 332Dir 78DLL 111Do Loop ... Until 245Document 225Document_Close 216Document_New 216Document_Open 216DocumentOpened 302, 305Documents.Add 197Documents.Open 198Dokumentenvariable 226Double 17DrawBezier 292DrawNURBS 292DrawOval 292DrawPolyline 292DrawRectangle 292
362
Stichwortverzeichnis
DrawSpline 292Drehfeld 115, 159DropDown 214Dropdownfelder 213Duplicate 271, 291duplizieren 291
EEigenschaften 89, 115Einfügeereignis 301Einzelschritt 104Email 332End Sub 15Endlosschleife 59Endquersumme 66Entschlüsseln 229EQV 23Ereignis 328EreignisDpplKlck 301Ereignisse 115, 263, 301EreignisXFMod 301Err 105Error 118Eulersche Zahl 85Evaluate 238eventCode 310EventID 310Exit Sub 15Exp 33Explorer 319
FFehlernummer 106Feldfunktionen 225Fenster 283Fermat'sche These 66Fibonacci, Leonardo 66Fields 226FileCopy 78FileDateTime 77FileLen 77FileName 198FileSearch-Objekt 179Fill 271Filter 36finanzmathematische Funktionen 34Find 323
FirstDayOfWeek 37Fix 34FlipHorizontal 291FlipVertical 291Flowcharter 11Font 236For ... Next 59For Each ... Next 59Format 39Formula 239, 295FormulaForce 295FormulaForceU 295Formular 115, 335FormulaR1C1 239Formularfelder 213FormulaU 295Frame 115Frontpage 11FüllVGrund 298Funktion 249
Gganzrationale Funktionen 260Gauß, Carl Friedrich 43Geburtsdatum 44GetAttr 77GetDefaultFolder 320GetNames 288GetNamespace 321GetObject 343GetSystemMetrics 113Gitternetzlinien 249Globale Variable 53GlueTo 299GlueToPos 300Graph 249, 250Gregory Reddick & Associates 17Großbuchstaben 36Group 291
HHaltepunkt 104Hour 38
IID 191If 25
363
Stichwortverzeichnis
If ... Then ... Else 25IIf 25Image 115ImageList 177IMP 23Information 206Infos 277ini-Dateien 80Initialize 118Input 83Inspector-Objekt 319InStr 35InStrRev 36Int 34Integer 16IS 23IsArray 26IsDate 26IsEmpty 26IsError 26IsMissing 26IsNull 26IsNumeric 26IsObject 26Item 322ItemSend 329
JJoin 36, 47
KKalenderwoche 38KeyDown 118KeyPress 118, 127KeyUp 118Kill 78KillTimer 114Klassen 89Klassenmodul 89, 307Kleinbuchstaben 36Kombinationsfeld 115, 152Kommentar 16Konjunktor 28Konstante 17Kontrollkästchen 115, 134, 213kopieren 291Kryptographie 228
LLabel 115, 125Languages 222LargeChange 159Layer 357Lcase 36Leerzeichen 35Left 35Legende 249Len 35LIKE 23Listbox 115, 152Listenfeld 115, 152ListIndex 155ListView 177Log 34Lokalfenster 104Long 16Loop 60Ltrim 35
MMailItem 319Makrorekorder 197MAPI 320MAPIFolder 328Markieren 201Mastershape 287Matrix 89Max 159Meldungsfenster 20MenuBar 186Menüpunkte 179Menüs 312MenuItems 312, 314MenuSet 312MenuSets 314Methoden 89, 115Microsoft 11Microsoft Internet Explorer 335Microsoft Systeminfo 221Mid 35Min 159Minute 38MkDir 78Mod 23Month 38
364
Stichwortverzeichnis
MouseDown 118MouseMove 118MouseUp 118Move 203Mozilla 335MsgBox 20Multipage 115Multiseiten 115, 164MultiSelect 153Multithreading 11
NName 78, 117, 127Namespace-Objekts 320Netscape Navigator 336Normal.dot 219NOT 23Notenliste 350Nothing 341, 344Now 37
OObject 17Objektkatalog 33Objektmodell 282, 319Offset 239olContactItem 319olDistributionListItem 319olJournalItem 319olMailItem 320olNoteItem 320olPostItem 320olTaskItem 320On Error GoTo 0 104On Error GoTo Sprungmarke 105On Error Resume Next 104OnKey 264OnTime 216, 264OnUndo 264Open 83, 198, 232, 269, 284Option Compare Binary 24Option Compare Text 24Option Explicit 20, 103Optionbutton 115, 134Options 222Optionsfeld 115, 134OR 23
Ostersonntag 43Outlook 11OutlookBarGroups 327OutlookBarPane 327Output 83
PPages 286Panes-Auflistung 327ParamArray 55Passwort 229Paste 271Path 231, 282Polymorphismus 11Position bestimmen 201Presentations 269Preserve 20Primzahl 65Print 285Print-Eigenschaft 285PrintOut 200, 232Private 15PrivateProfileString 351ProgressBar 177Project 11Property Get 89Property Let 89Property Set 89Public 15
QQuadratische Gleichung 27Quersumme 66QueryClose 118Quit 285
RRahmen 115, 134Randomize 34Range 206, 210, 225, 235rationale Funktionen 260Read-Only 285RecentFiles 222rechtwinkliges Dreieck 27Reddick 17ReDim 20RefEdit 126
365
Stichwortverzeichnis
Register 115, 164Registry 82, 111Rekursion 63rem 16remark 16RemoveControl 118RemoveItem 154Resize 118Restrict 325Result 295ResultForce 295ResultFromInt 295ResultFromIntForce 295ResultInt 295ResultIU 295ResultIUForce 295ResultStr 295RGB 160Right 35RmDir 78Rnd 34Round 34Row 298Rows 239Rtrim 35Rubrikenachse 249, 250Run 266RUNADDON 301RunAutoMacro 219RunModeEntered 305, 309
SSave 199, 232, 270, 284SaveAs 232, 285SaveAsCopy 270SaveChanges 199SaveCopyAs 232Saved 232Schablone 285Schaltjahr 28Schnecke 65Scroll 118Scrollbar 115, 159Second 38Section 298Select 289
Select Case 25Selection 201, 225, 273, 291Selection.GoTo 205SendKeys 266, 341SendToBack 291Sequentielle Dateien 83SetAttr 77SetFocus 119SetTimer 114Sgn 34Shape 357ShapeAdded 302, 303, 308Shape-Aktionen 291ShapeChanged 306Shapes markieren 289Shapes verbinden 299Shape-Zugriff 287Sheet 232shell 341ShowCursor 114Sin 33Single 16Sink-Objekt 307Skalierung 250Slider 177SlideRange 273Slides 270SmallChange 159SourceObj 310Space 36SpatialNeighbors 303Spinbutton 115, 159Split 36Sqr 33Static 15StatusBar 177Steuerelement 115, 277Str$ 36StrComp 36StrConv 36String 17, 35, 36Sub 15Symbol 330Symbole 179, 312Systemdatum 37Systemzeit 37
366
Stichwortverzeichnis
TTabelle 210TabOrientation 164Tabstrip 115Tan 33Tasks 221Tastenkombinationen 179, 312Terminate 118Text 293Textbox 115Textfeld 115, 124Textfelder 213TextInput 214Textmarke 205ThePage 304, 305ThisDocument 284, 301ThisWorkbook 231Time 37TimeSerial 37TimeValue 37Titel 249ToCell 304Toggelbar 115Togglebutton 134ToolBar 177Toolbarsets 312ToolTip-Text 191TreeView 177Trim 35TypeParagraph 201TypeText 201
UUcase 36Übergabe 54Überwachungsfenster 104UIObject 312, 314Umschaltfeld 115, 134Ungroup 291Unterstrich 16Until 60Update 226Ursprung 292Userform 115
VVal 36Value 127, 236Variable 16Variablenname 103Variablentyp 16Variables 226Variant 17vbCr 237VbFirstFourDays 38VbFirstFullWeek 38VbFirstJan1 38vbFriday 38VbMonday 38vbMonday 38vbSaturday 38vbSunday 38vbTab 237vbThursday 38vbTuesday 38VbUseSystem 38vbWednesday 38Vererbung 11verschlüsseln 228Verweis 346View 197, 218, 222Visible 118, 233, 345Visio 11Visio-Ereignisse 301visSectionAction 297VisSectionIndices 297visSectionInval 298visSectionUser 298visSelect 289
WwdGoToBookmark 205Weekday 38While 60WholeStory 204Window-Objekt 289Windows 283With ... End With 103WithEvent 331WithEvents 216, 304, 307Workbook 231, 232
367
Stichwortverzeichnis
WorkSheet 232Worksheet Menu Bar 186
XXOR 23Xor 139, 228
YYear 38
ZZählerschleife 59Zelle 235Zoom 118
368