vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der...

368

Transcript of vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der...

Page 1: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass
Page 2: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

Workshop VBA

Page 3: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

René Martin

Workshop VBA

An imprint of Pearson EducationMünchen • Boston • San Francisco • Harlow, England

Don Mills, Ontario • Sydney • Mexico CityMadrid • Amsterdam

Page 4: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 5: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 6: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 7: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 8: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 9: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 10: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 11: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 12: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 13: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 14: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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:

[email protected]

14

Page 15: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 16: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 17: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 18: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 19: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 20: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 21: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 22: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 23: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 24: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 25: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 26: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 27: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

Ü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

Page 28: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 29: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 30: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 31: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 32: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass
Page 33: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 34: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 35: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 36: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 37: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 38: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 39: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 40: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 41: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 42: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 43: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 44: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 45: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 46: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 47: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 48: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 49: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 50: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 51: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 52: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 53: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 54: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 55: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

Ü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

Page 56: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 57: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

Ü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

Page 58: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 59: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 60: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 61: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 62: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 63: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 64: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 65: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 66: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 67: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 68: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 69: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 70: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 71: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 72: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 73: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 74: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 75: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 76: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 77: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 78: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 79: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

Ü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

Page 80: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 81: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

Ü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

Page 82: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 83: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 84: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 85: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

Ü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

Page 86: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 87: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 88: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 89: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 90: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 91: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 92: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 93: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 94: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 95: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 96: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 97: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 98: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 99: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 100: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 101: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 102: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 103: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 104: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 105: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 106: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 107: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 108: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 109: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 110: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 111: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 112: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 113: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 114: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 115: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 116: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 117: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 118: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 119: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 120: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 121: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 122: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 123: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 124: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 125: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 126: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 127: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 128: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 129: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 130: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 131: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 132: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 133: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 134: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 135: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

Ü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

Page 136: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 137: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

Ü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

Page 138: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 139: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 140: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 141: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 142: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 143: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 144: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 145: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 146: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 147: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 148: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 149: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 150: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 151: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 152: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 153: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 154: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 155: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 156: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 157: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 158: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 159: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 160: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 161: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 162: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 163: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 164: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 165: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

Ü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

Page 166: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 167: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 168: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 169: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 170: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 171: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 172: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 173: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 174: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 175: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 176: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 177: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 178: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass
Page 179: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 180: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 181: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 182: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 183: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

Ü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

Page 184: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 185: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 186: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 187: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 188: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 189: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 190: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 191: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

Ü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

Page 192: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 193: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 194: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 195: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 196: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 197: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 198: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 199: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 200: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 201: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 202: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 203: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 204: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 205: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 206: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 207: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 208: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 209: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 210: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 211: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

Ü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

Page 212: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 213: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 214: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 215: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 216: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 217: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 218: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 219: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 220: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 221: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 222: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 223: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 224: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 225: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 226: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 227: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 228: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 229: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 230: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 231: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 232: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 233: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

Ü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

Page 234: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 235: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 236: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 237: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 238: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 239: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 240: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 241: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 242: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 243: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 244: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 245: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 246: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 247: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 248: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 249: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 250: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 251: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 252: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 253: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 254: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 255: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 256: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 257: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 258: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 259: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 260: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 261: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 262: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 263: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 264: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 265: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 266: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 267: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 268: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 269: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 270: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 271: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 272: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 273: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 274: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 275: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 276: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 277: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 278: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 279: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 280: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 281: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 282: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 283: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 284: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 285: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 286: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 287: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 288: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 289: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 290: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 291: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 292: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 293: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 294: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 295: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 296: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 297: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 298: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 299: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 300: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 301: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 302: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 303: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 304: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 305: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 306: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 307: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 308: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 309: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 310: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 311: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 312: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 313: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 314: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 315: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 316: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 317: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 318: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 319: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 320: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 321: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 322: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 323: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 324: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 325: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 326: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 327: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 328: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 329: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 330: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 331: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 332: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 333: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 334: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 335: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

Ü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

Page 336: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 337: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 338: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 339: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 340: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 341: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 342: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 343: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 344: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 345: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 346: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 347: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

Ü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

Page 348: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 349: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 350: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 351: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 352: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 353: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 354: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 355: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

Ü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

Page 356: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 357: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

Ü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

Page 358: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 359: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 360: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

17 Austausch zwischen den Programmen

Abbildung 17.5:Die Zeichnung

und das Ergebnis(für einen Layer)

360

Page 361: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 362: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 363: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 364: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 365: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 366: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 367: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

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

Page 368: vba - gaddo.de · PDF fileDafür habe ich den »Spitzenreitern« der VBA-Programmierung – Word und Excel – den größten Platz eingeräumt. Da ich der Meinung bin, dass

Stichwortverzeichnis

WorkSheet 232Worksheet Menu Bar 186

XXOR 23Xor 139, 228

YYear 38

ZZählerschleife 59Zelle 235Zoom 118

368