Lies in den Artikel rein und unten bekommst Du ein unschlagbares Angebot!
Wer die Office-Anwendungen Access, Excel, Outlook, PowerPoint oder Word mit VBA programmiert, kann eine Menge erreichen, ohne jemals eine eigene Klasse zu programmieren. Wer sich die gesamten Möglichkeiten eröffnen will, kommt jedoch irgendwann nicht mehr um die Programmierung benutzerdefinierter Klassen herum. Dieser Artikel zeigt verschiedene Szenarien auf, wann man benutzerdefinierte Klassen programmieren und darauf basierende Objekte instanziieren kann und soll. Dabei geht es um Begriffe wie Eigenschaften, Methoden, Ereignisse und darum, wo und wie man Klassen einsetzt.
Wer in den VBA-Projekten von Outlook oder von Dokumenten auf Basis von Access, Excel, PowerPoint oder Word programmiert, ahnt es vielleicht manchmal nicht, aber tatsächlich programmiert man fast zwangsläufig innerhalb von Klassenmodulen. Das Modul Projekt1, das angezeigt wird, wenn man das VBA-Projekt von Outlook öffnet, das Modul ThisDocument in Word, die Module DieseArbeitsmappe oder Tabelle1 in Excel oder auch die Module, die man in Access beim Anlegen von Ereignisprozeduren für Formulare, Steuerelemente oder Berichte verwendet, sind allesamt Klassenmodule.
Diese sind jedoch mit der jeweiligen Anwendung (Outlook) beziehungsweise mit dem jeweiligen Dokument oder dem Element verknüpft, in deren Kontext sie geöffnet werden. Dadurch ergeben sich einige Vorteil: Wir können nämlich in diesen direkt auf einige Elemente des jeweiligen Objekts zugreifen. Im Klassenmodul ThisOutlookSession von Outlook greifen wir beispielsweise direkt auf die Eigenschaften, Methoden und Ereignisse des Application-Objekts zu.
Im Klassenmodul eines Access-Formulars greifen wir direkt auf die Eigenschaften, Methoden und Ereignisse des jeweiligen Formulars und der enthaltenen Steuerelemente zu. Im Klassenmodul ThisDocument eines Word-Dokuments stehen die entsprechenden Elemente des Document-Objekts zur Verfügung und in Excel können wir in der Klasse DieseArbeitsmappe über die Variable Workbook auf die enthaltenen Eigenschaften, Methoden und Ereignisse zugreifen sowie in den Klassen für die einzelnen Tabellen auf das jeweilige Worksheet-Element.
Wenn wir bereits eine solche Vielfalt von eingebauten Elementen haben, warum sollten wir noch benutzerdefinierte Klassen entwickeln? Dazu gibt es verschiedene Gründe, die wir in den folgenden Abschnitten beschreiben. Außerdem sehen wir uns an, warum es in diesem Fällen ein Klassenmodul sein muss und warum es nicht reicht, ein Standardmodul zu verwenden.
Grund für Klassen: Eigenschaften, Methoden und Ereignisse zusammenfassen
Ein wichtiger Anwendungszweck für Klassen ist schlicht und einfach das Zusammenfassen von Elementen in einer Code-Einheit. Wann immer wir im Code allein Informationen zusammenstellen, die zusammengehören, können wir dies mit einer Klasse erledigen.
Für diese legen wir dann Eigenschaften fest, mit denen wir die Informationen erfassen können. Sobald wir ein Objekt auf Basis der Klasse erstellt haben, können wir diesem Informationen über die Eigenschaften zuweisen und die Eigenschaften wieder auslesen. Wir können auch dafür sorgen, dass das Objekt seine Eigenschaften selbst füllt – beispielsweise durch das Einlesen eines Datensatzes einer Access-Tabelle, der Daten einer E-Mail oder der Absätze eines Word-Dokuments.
Auf Basis dieser Eigenschaften können wir nun Methoden bereitstellen, welche die Inhalte der Eigenschaften verarbeiten – beispielsweise, um aus Daten wie Absender, Empfänger, Betreff und Inhalt eine Outlook-E-Mail zu erstellen und diese abzusenden. Oder wir bieten Funktionen an, welche die eingegebenen Eigenschaften in unterschiedlichen Arten verarbeiten.
So können wir beispielsweise einer Klasse, die eine Adresse in Form der Eigenschaften Firma, Anrede, Vorname, Nachname, Straße, PLZ, Ort und Land aufnimmt, eine Funktion hinzufügen, welche aus diesen Informationen einen Adressblock erstellt, den wir in einem Access-Bericht oder in einem Word-Dokument ausgeben können.
Ein Beispiel hierfür stellen wir im Artikel Klassen programmieren unter VBA (www.vbentwickler.de/423) vor.
Grund für Klassen: Ereignisse bereitstellen
Wenn Du selbst Ereignisse bereitstellen möchtest, die ausgelöst werden, wenn bestimmte Dinge in Deinem Code geschehen, sind Klassenmodule die einzige Möglichkeit. Über ein solches Ereignis kannst Du eine Ereignisprozedur implementieren, also eine Prozedur, die mit dem Feuern des Ereignisses gestartet wird und Deinen benutzerdefinierten Code ausführt.
Nun stellst Du Dir vielleicht die Frage, warum Du nicht direkt dort den auszuführenden Code unterbringen sollst, wo die auslösende Aktion in Deinem Code geschieht. Der Grund ist, dass Du in einer Klasse allgemeine Elemente und Methoden unterbringst, die für jeden Anwendungsfall gleich sein sollen. Es gibt jedoch auch Anteile, die je nach Anwendungsfall unterschiedlich behandelt werden sollen.
Ein gutes Beispiel dafür ist eine Schaltfläche. Diese erledigt beim Anklicken bereits automatisch Aufgaben – zum Beispiel ändert sie ihre Ansicht in den gedrückten Zustand. Du möchtest aber für jede Schaltfläche individuelle Funktionen programmieren. So soll zum Beispiel eine OK-Schaltfläche in einem Formular andere Aktionen ausführen als beispielsweise eine Abbrechen-Schaltfläche. Deshalb stellt die Schaltflächen-Klasse für jede einzelne Instanz einer Schaltfläche eine eigene Ereignisprozedur bereit, in der Du die jeweiligen Anweisungen unterbringen kannst.
Wenn Du selbst eine Klasse programmierst, wird es für Ereignisse ebenfalls zwei Arten von Aktionen geben:
- solche, die immer ausgeführt werden sollen und
- solche, die individuell implementiert werden sollen, um die Klasse an den jeweiligen Anwendungsfall anzupassen.
Beispiel: Klasse zum Einlesen von XML-Dokumenten
Nehmen wir an, Du hast eine Klasse programmiert, die das Einlesen von XML-Dateien erledigt. Die Klasse nimmt mit einer Eigenschaft namens Pfad den Pfad der einzulesenden XML-Datei entgegen. Eine Methode namens Einlesen führt den Einlesevorgang der XML-Datei in ein Objekt des Typs DOMDocument durch. Der Inhalt des XML-Dokuments wird dann durch die Eigenschaft XML nach außen bereitgestellt. Beim Einlesen kann es vorkommen, dass ein Fehler ausgelöst wird – beispielsweise, weil das Dokument einen Syntaxfehler enthält. Du könntest nun in der Methode Einlesen für den Fall eines Fehlers einfach eine Meldung ausgeben. Wenn Du diese Klasse dann in einem anderen Kontext nutzt, wo Du vielleicht keine Meldung erhalten möchtest, sondern den Fehler in einer Protokolldatei erfassen willst, musst Du den Code der Klasse ändern. Damit hast Du dann verschiedene Versionen einer Klasse in Deinen Anwendungen.
Besser wäre es, wenn Du in der XML-Klasse eine Schnittstelle anbieten würdest, mit der das aufrufende Element abfragen könnte, ob und wann ein Fehler auftritt. Dazu gibt es zwei Möglichkeiten: Du könntest einen eventuellen Fehler mit einem Parameter der Methode Einlesen zurückgeben. Wir könnten aber auch ein Ereignis beispielsweise namens Fehler in der XML-Klasse definieren, das beim Eintreten eines Fehlers ausgelöst wird und das die Fehlermeldung als Parameter bereitstellt. Auf die Ausgabe einer Meldung beim Auftreten eines Fehlers innerhalb der XML-Klasse verzichten wir nun natürlich.
Damit könntest Du nun im aufrufenden Element, also beispielsweise im Klassenmodul eines Access-Formulars, das Ereignis implementieren, das beim Einlesefehler ausgelöst wird. Und egal, von wo Du die Klasse nutzt – Du kannst in der Ereignisprozedur immer auf die gewünschte Weise auf den aufgetretenen Fehler reagieren.
Auf die Programmierung von Ereignissen in Klassen gehen wir im Artikel Ereignisse in Klassen programmieren (www.vbentwickler.de/425) genauer ein.
Grund für Klassen: Mehrere Instanzen möglich