Zur Hauptseite ... Zum Onlinearchiv ... Zum Abonnement ... Zum Newsletter ... Zu den Tools ... Zum Impressum ... Zum Login ...

Achtung: Dies ist nicht der vollständige Artikel, sondern nur ein paar Seiten davon. Wenn Sie hier nicht erfahren, was Sie wissen möchten, finden Sie am Ende Informationen darüber, wie Sie den ganzen Artikel lesen können.

Kompletten Artikel lesen?

Einfach für den Newsletter anmelden, dann lesen Sie schon in einer Minute den kompletten Artikel und erhalten die Beispieldatenbanken.

E-Mail:

Gedrucktes Heft

Diesen Beitrag finden Sie in Ausgabe 5/2004.

Unser Angebot für Sie!

Lesen Sie diesen Beitrag und 500 andere sofort im Onlinearchiv, und erhalten Sie alle zwei Monate brandheißes Access-Know-how auf 72 gedruckten Seiten! Plus attraktive Präsente, zum Beispiel das bald erscheinende Buch 'Access 2010 - Das Grundlagenbuch für Entwickler'!

Diesen Beitrag twittern

Objektorientiert programmieren mit Access

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.

Eingebaute Objekttypen in
Access

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.

Eigene Objekttypen - warum?

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:

  • Objekttypen enthalten Methoden, Eigenschaften und Ereignisse und machen diese über eine leicht zugängliche Schnittstelle verfügbar.
  • Affinität: Mit der Definition eines Objekttyps macht man Softwareentwicklung wesentlich greifbarer, denn reelle Objekte wie beispielsweise der nachfolgend vorgestellte Kontakt können über realitätsnahe Attribute angesprochen werden.
  • Komplexität verbergen: Objekttypen verbergen mitunter komplexe Vorgänge, um die man sich, wenn sie einmal gestestet und praxiserprobt sind, keine Gedanken mehr machen muss. Der ansonsten offen liegende Code verschwindet in einer Black Box; nicht mehr die darin enthaltenen Techniken interessieren, sondern allein die Schnittstelle.
  • Wiederverwendbarkeit: Auf den Funktionsumfang eines Objekts kann man von der ganzen Anwendung aus zugreifen; unter Umständen können Objekttypen sogar in weiteren Anwendungen zum Einsatz kommen - beispielsweise, wenn die Klassen nicht an eine bestimmte Datenherkunft gebunden sind.
  • Weitergabe: Objekttypen können in Form von Klassenmodulen leicht weitergegeben werden; eine funktionierende Schnittstelle und eine brauchbare Dokumentation vorausgesetzt, können andere Entwickler diese leicht weiterverwenden.
  • Klassenmodule

    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"

    Dank Intellisense erscheint der Eigenschaftsname direkt nach der Eingabe des Punktes hinter objKontakt in der Liste der verfügbaren Eigenschaften, Methoden und Ereignisse dieses Objekts - bisher also allein auf weiter Flur (s. Abb. 1).

    Abb. 1: Intellisense vereinfacht den Zugriff auf Objekt
    eigenschaften.

    Um zu überprüfen, ob die Zuweisung funktioniert, geben Sie mit nachfolgender Anweisung den Inhalt der Eigenschaft im Testfenster aus:

    Debug.Print objKontakt.Vorname

    Was ist passiert?

    Über die Zuweisung der Zeichenkette an objKontakt.Vorname haben Sie die Property Let-Methode aufgerufen. Diese nimmt den übergebenen Wert über den Parameter strVorname entgegen und weist ihn der privaten Variablen mVorname zu.

    Bei der nachfolgenden Ausgabe läuft es umgekehrt: Die Propery Get-Prozedur ermittelt den Wert der Variablen mVorname und schickt ihn über die Eigenschaft Vorname zur Ausgabe.

    Hinweis

    Vielleicht haben Sie den großen Vorteil dieser Vorgehensweise schon erkannt: Sie können mit Hilfe von Get- und Let-Prozeduren für eine Property festlegen, ob diese zum Lesen, Schreiben oder gar für beide Zugriffsarten verfügbar sein soll. (

    Im Gleichschritt: Marsch!

    Nachdem Sie sich von der Funktionsweise der Eigenschaft Vorname überzeugt haben, können Sie nun die Variablen für die weiteren Eigenschaften des Kontakts wie Nachname, Strasse, PLZ, Ort, Land und Unternehmen sowie die entsprechenden Property Let und Property Get-Prozeduren anlegen. Damit hätten Sie eine Klasse erzeugt, die wichtige Eigenschaften eines Kontaktes erhalten und wieder ausgeben kann.

    Die Ereignisse Initialize und
    Terminate

    Klassenmodule stellen zwei eingebaute Ereigniseigenschaften zur Verfügung, die beim Erzeugen und beim Zerstören einer Objektinstanz ausgelöst werden.

    Um die entsprechenden Ereigniseigenschaften zu erzeugen, wählen Sie einfach im VBA-Editor im linken Kombinationsfeld den Eintrag Class und im rechten den Namen der gewünschten Ereignisprozedur aus (s. Abb. 2).

    Abb. 2: Erzeugen einer Ereignisprozedur einer Klasse

    Diese Eigenschaften können Sie beispielsweise verwenden, um beim Erzeugen der Objektinstanz Variablen auf bestimmte Startwerte oder Verweise auf andere Objekte zu setzen. Beim Zerstören einer Objektinstanz erledigt man mit der entsprechenden Ereignisprozedur notwendige Aufräumarbeiten.

    Verwenden von Enumerationen

    Sicher kennen Sie die Möglichkeit, per Intellisense eine vordefinierte Konstante für einen Parameter auszuwählen. Das Gleiche ist auch mit den Eigenschaften einer Objektinstanz möglich. Um bei unserem Beispiel mit den Kontaktdaten zu bleiben, fügen wir diesem noch eine Eigenschaft namens Geschlecht hinzu. Dafür gibt es unter normalen Umständen nur zwei mögliche Einträge, deren Auswahl man dem Benutzer gerne abnimmt. Die passende Enumeration sieht folgendermaßen aus:

    Public Enum enumGeschlecht

        männlich

        weiblich

    End Enum

    Die Definition der entsprechenden Variablen sowie der Property Let- und Get-Prozeduren sieht wie folgt aus:

    Dim mGeschlecht As enumGeschlecht

    Public Property Get Geschlecht() As enumGeschlecht

        Geschlecht = mGeschlecht

    End Property

    Public Property Let Geschlecht(lngGeschlecht As enumGeschlecht)

        mGeschlecht = lngGeschlecht

    End Property

    Es gibt also prinzipiell keine Unterschiede zu herkömmlichen Datentypen, mit der Ausnahme, dass der Datentyp als Enumeration definiert wird.

    Hier sind zwei Dinge zu beachten: Beim Zugriff auf diese Objekteigenschaft stehen zwar die beiden Konstanten zur Verfügung (s. Abb. 3). Wenn man sich den ausgewählten Wert nachher ausgeben lässt, erhält man aber nicht den ausgewählten Ausdruck, sondern die dahinter stehende Konstante.

    Public Function Anschrift() As String

        Dim strAnschrift As String

        Dim strAnrede As String

        If mGeschlecht = männlich Then

            strAnrede = "Herrn "

        Else

            strAnrede = "Frau "

        End If

        If Not mUnternehmen = "" Then

            strAnschrift = strAnschrift & mUnternehmen & vbCrLf

            strAnschrift = strAnschrift & strAnrede & mVorname & " " & mNachname & vbCrLf

        Else

            strAnschrift = strAnschrift & strAnrede & vbCrLf

            strAnschrift = strAnschrift & mVorname & " " & strNachname & vbCrLf

        End If

        strAnschrift = strAnschrift & mStrasse & vbCrLf

        strAnschrift = strAnschrift & mPLZ & " " & mOrt & vbCrLf

        strAnschrift = strAnschrift & mLand

        Anschrift = strAnschrift

    End Function

    Quellcode 1

    Womit wir direkt beim zweiten Punkt wären: Man kann den einzelnen Teilen der Enumeration direkt entsprechende Zahlenwerte mitgeben oder diese wie in obigem Beispiel weglassen. In dem Fall nummeriert Access die Werte hinter den Einträgen bei 0 beginnend durch. Für ein wenig mehr Kontrolle sollten Sie also selbst entsprechende Werte vergeben, also etwa folgendermaßen:

    Public Enum enumGeschlecht

        Männlich = 1

        Weiblich = 2

    End Enum

    Abb. 3: Enumerationen können die Auswahl von Konstanten vereinfachen.

    Methoden von Objekttypen

    Was kann man nun mit einer Klasse anfangen, die es erlaubt, Eigenschaften eines Kontaktes einzugeben und wieder abzurufen? Ein einfaches Beispiel ist das Zusammenstellen einer Anschrift aus den eingegebenen Daten und deren Ausgabe.

    Dazu legen Sie einfach die Prozedur aus Quellcode 1 im Klassenmodul clsKontakt an.

    Sie haben das Ende des frei verfügbaren Teils des Artikels erreicht. Lesen Sie weiter, um zu erfahren, wie Sie den vollständigen Artikel lesen und auf viele hundert weitere Artikel zugreifen können.

    Sind Sie Abonnent?Jetzt einloggen ...
     

    Kompletten Artikel lesen?

    Einfach für den Newsletter anmelden, dann lesen Sie schon in einer Minute den kompletten Artikel und erhalten die Beispieldatenbanken.

    E-Mail:

    Verwandte Beiträge:

    Ereignisprozeduren implantieren

    Das Factory-Pattern

    Schnittstellenvererbung

    © 2003-2015 André Minhorst Alle Rechte vorbehalten.