André Minhorst, Duisburg
VBA wird im Allgemeinen die Eigenschaft abgesprochen, eine objektorientierte Programmiersprache zu sein. Um diese Aussage zu untersuchen, müsste man erst einmal festlegen, ab wann eine Sprache objektorientiert ist und welche Eigenschaften für diese Bezeichnung vorhanden sein müssen. Lässt man einmal außen vor, dass Vererbung und Polymorphismus im VBA-Sprachgebrauch Fremdwörter sind, kann man VBA sicher als objektorientierte Sprache auffassen. Wie auch immer – im vorliegenden Beitrag erfahren Sie, wie Sie sich die objektorientierten Eigenschaften von VBA zu Nutze machen.
Wer mit Access arbeitet und dabei VBA für die Entwicklung von Datenbankanwendungen verwendet, kann vermutlich mit Objekten verschiedenen Typs umgehen – wenn er auch vielleicht noch nie einen eigenen Objekttyp erstellt hat.
Sicher hat jeder schon einmal ein Recordset via VBA geöffnet und auf die darin enthaltenen Methoden wie Open, MoveNext, AddNew, Update oder Close zugegriffen oder Informationen aus Eigenschaften wie RecordCount, EOF oder Filter verwendet. Beispiele dafür zeigt die Routine aus Quellcode 1, die eine auf der Tabelle tblKontakte basierende Datensatzgruppe öffnet und den Inhalt der einzelnen Datensätze ausgibt. Mit diesem Code erzeugt man unter anderem eine Instanz des Objekttyps Recordset, legt einige seiner Eigenschaften wie beispielsweise die Datenherkunft und die zugrunde liegende Verbindung fest und greift anschließend auf die so verfügbar gemachten Daten zu.
Public Sub OpenRecordset() Dim cnn As ADODB.Connection Dim rst As ADODB.Recordset Set cnn = CurrentProject.Connection Set rst = New ADODB.Recordset rst.Open "tblKontakte", cnn, adOpenKeyset, _ adLockPessimistic Do While Not rst.EOF Debug.Print rst!KontaktID, rst!Vorname, _ rst!Nachname rst.MoveNext Loop rst.Close Set rst = Nothing Set cnn = Nothing End Sub
Quellcode 1
Eine weitere, ganz offensichtliche Objektart ist beispielsweise ein Formular – wie für ein Objekt üblich, verfügt es über Methoden, Eigenschaften und Ereignisse. Ein Formularobjekt kann wiederum Steuerelemente enthalten, die ebenfalls Objekttypen repräsentieren.
Mit den in Access vorhandenen Objekttypen lässt sich jede Menge nützlicher Dinge anstellen. Ein wichtiger Aspekt dabei ist, dass die unterschiedlichen Objekttypen bestimmte Methoden, Eigenschaften und Ereignisse enthalten. Ein Objekt des Typs Recordset fasst beispielsweise eine Menge Funktionalität zusammen. Und das Beste daran ist, dass man sich gar nicht darum kümmern muss, was im Innern dieses Objekts passiert – es reicht völlig aus, dass man die Methoden, Eigenschaften und Ereignisse kennt. Wen interessiert denn schon, was intern alles abläuft, wenn man die Methode AddNew eines Recordset-Objekts aufruft Wichtig ist allein das Kennen der Schnittstelle und dass das Objekt die gewünschten Reaktionen und Ergebnisse auf die getätigten Eingaben liefert.
Hinweis
Um keine Verwirrung bezüglich der hier verwendeten Begriffe aufkommen zu lassen, sollen folgende Definitionen gelten: Der Inhalt eines Klassenmoduls definiert eine Klasse. Eine Klasse wird auch Objekttyp genannt. Das Instanzieren einer Klasse beziehungsweise eines Objekttyps erzeugt ein Objekt. Auf das Objekt kann man in der Folge über die Objektvariable zugreifen. Das Klassenmodul enthält also einen Entwurf dessen, wie das Objekt sich verhalten soll. Dieser Entwurf besteht aus der Definition geeigneter Eigenschaften, Methoden und Ereignisse sowie der dahinter liegenden Funktionen.
Nun bietet Access nur eine begrenzte Menge Objekttypen, die allerdings bereits viele Anforderungen abdecken. Genau genommen sind Art und Menge der Objekttypen gerade so bemessen, dass sie als vernünftige Grundlage für den Aufbau der jeweils individuell abzubildenden Geschäftsprozesse einer Anwendung dienen.
Damit gibt es bereits einige gute Gründe, um eigene Objekttypen zu schaffen:
Wie bereits oben erwähnt, ist einer der Vorteile der Verwendung von Objekttypen, dass man reelle Objekte und deren Eigenschaften in einer Einheit zusammenfassen kann, deren Methoden, Eigenschaften und Ereignisse über eine entsprechende Schnittstelle erreichbar sind. Unter VBA spricht man in diesem Zusammenhang von einem Klassenmodul.
Als Beispiel für die Erläuterung des Aufbaus und der Verwendung von Objekttypen dient ein Kontakt. Er enthält bestimmte Informationen zu einer Person wie Vorname, Nachname, Geschlecht und Adressdaten. Um nicht nur die Verwendung von Eigenschaften, sondern auch den Einsatz von Methoden vorzustellen, erhält die Beispielobjektklasse zusätzlich eine Routine zur Ausgabe der Adressdaten in Form einer Anschrift.
Hinweis
Die zu den nachfolgenden Beispielen gehörenden Objekte und Codes finden Sie in der Beispieldatenbank OOMitAccess.mdb für Access 2000 und höher auf der beiliegenden CD.
Erstellen eines Klassenmoduls
Access stellt drei unterschiedliche Modularten zur Verfügung: die Klassenmodule von Formularen und Berichten, Standardmodule sowie Klassenmodule, die nicht an ein bestimmtes Objekt wie ein Formular oder einen Bericht gebunden sind. Die Klassenmodule von Formularen und Berichten sind prinzipiell mit den im Anschluss vorgestellten Klassenmodulen identisch; der einzige Unterschied ist, dass Letztere keine Oberfläche in Form eines Formulars oder Berichts enthalten.
Um ein solches Klassenmodul zu erstellen, wählen Sie im VBA-Editor von Access den Menüeintrag Einfügen/Klassenmodul aus. Daraufhin öffnet Access ein fast leeres neues Klassenmodul, das Sie am besten direkt unter dem gewünschten Namen speichern – beispielsweise clsKontakt. Wählen Sie den Namen eines Klassenmoduls immer so, dass er auch verrät, welches Objekt sich dahinter verbirgt – später werden Sie über diesen Namen auf diese Klasse zugreifen.
Praxis-Tipp
Damit der Debugger sich meldet, wenn eine Variable nicht ordnungsgemäß deklariert ist, sollten Sie im Prozedurkopf die Anweisung Option Explicit hinzufügen.
Schreib- und lesbare Variablen
Die Eigenschaften eines Objekttyps speichert man in herkömmlicher Weise in Variablen. Die Zugriffsmöglichkeiten auf diese Variablen kann man allerdings wesentlich flexibler gestalten als in Prozeduren in Standardmodulen.
Sie können eine Variable innerhalb eines Klassenmoduls natürlich als öffentlich zugänglich deklarieren, indem Sie etwa folgende Anweisung verwenden:
Public Vorname As String
Damit können Sie den Wert dieser Variablen von außen lesen und auch ändern, haben aber keinerlei Vorteile der in Klassenmodulen üblichen Art der Deklaration.
Dort gibt es nämlich so genannte Property-Funktionen, über die man von außen den Wert einer Variablen lesen und ändern kann. Daher deklariert man Variablen in Klassenmodulen niemals als öffentlich, sondern immer als privat. Die Property-Funktionen erlauben nicht nur den schreibenden und lesenden Zugriff auf die privaten Variablen (wobei es für jede Zugriffsart eine eigene Funktion gibt), sondern man kann dort beliebige weitere Anweisungen unterbringen. Auf diese Weise lässt sich beispielsweise ein Zeiger setzen, der Informationen darüber enthält, ob sich eine Variable seit Erstellung der Objektinstanz geändert hat.
Namenskonventionen
Die Variablen, die über Property-Funktionen für die Außenwelt erreichbar sein sollen, kennzeichnet man durch Voranstellen eines weiteren Buchstabens zum eigentlichen Variablennamen. Genau genommen wählt man einen Namen aus, unter dem die Variable nach außen erscheinen soll, wie beispielsweise Vorname, und nennt die Variable intern mVorname.
Hinzufügen einer Variablen
Um eine bessere Vorstellung davon zu bekommen, was es mit diesen Property-Funktionen auf sich hat, fügen Sie der Klasse einfach eine Variable hinzu und erstellen zwei passende Property-Funktionen:
Dim mVorname As String Public Property Get Vorname() As String Vorname = mVorname End Property Public Property Let Vorname(strVorname _ As String) mVorname = strVorname End Property
Testen der Variablen
Zum Testen der Funktionsweise verwenden Sie eine Prozedur namens BeispielKontakt in einem beliebigen Standardmodul. Um die Klasse verfügbar zu machen, deklarieren Sie zunächst eine entsprechende Objektvariable:
Public Sub KontaktBeispiel() Dim objKontakt As clsKontakt ''... weitere Anweisungen End Sub
Nach der Eingabe des Schlüsselwortes As erscheint die Liste aller verfügbaren Objekttypen, unter denen sich nun auch die neu erstellte Klasse befindet – wenn Sie also später mal eine ganze Menge eigener Objekttypen verwenden, müssen Sie sich noch nicht einmal mehr deren Namen genau merken.
Anschließend erzeugen Sie eine Instanz dieses Objekttyps, die Sie in der Prozedur verwenden möchten:
Set objKontakt = New clsKontakt
Sie könnten die ersten beiden Anweisungen auch zu einer einzigen Anweisung zusammenfassen:
Dim objKontakt As New clsKontakt
Dadurch sparen Sie zwar eine Zeile, aber wenn Sie die Objektinstanz möglicherweise erst später benötigen oder es sich erst im Verlaufe der Prozedur herausstellt, ob Sie diese überhaupt brauchen, verschwenden Sie unter Umständen wertvolle Ressourcen.
Damit auch alles seine Ordnung hat und Objekte nicht unnötig Speicherplatz belegen, obwohl sie nicht mehr benötigt werden, legen Sie vorsichtshalber jetzt schon die Anweisung zum Zerstören des Objektes an:
Set objKontakt = Nothing
Das ist zwar im vorliegenden Fall nicht unbedingt erforderlich, da das Objekt ohnehin nach Beenden der Prozedur zerstört wird, aber es ist programmiertechnisch sauberer. Die folgenden Beispielanweisungen fügen Sie natürlich vor dieser Anweisung ein, da sie sich sonst auf ein nicht mehr vorhandenes Objekt bezögen.
Und nun geht”s an die Variable mVorname und deren Property-Prozeduren, die zusammen die les- und schreibbare Eigenschaft Vorname ergeben. Die folgende Anweisung setzt den Wert dieser Variablen auf den Wert Heinz:
objKontakt.Vorname = "Heinz"