Lookuptabellen speichern meist Werte, die zum Vermeiden von Redundanzen und Inkonsistenzen aus einer anderen Tabelle ausgelagert wurden. Die Formulare für ihre Bearbeitung sehen meist gleich aus: Ein Hauptformular mit einer OK-Schaltfläche, ein Unterformular mit den Daten – das war es. Solche Formulare braucht man nicht für jede dieser Tabellen einzurichten: Es reicht ein einziges, dem Sie nur noch mitteilen, aus welcher Tabelle oder Abfrage die angezeigten Felder stammen sollen.
Wie ein solches Formular aussieht, entnehmen Sie Bild 1: Es zeigt lediglich die vorhandenen Einträge der Lookuptabelle an und bietet die Möglichkeit, diese zu bearbeiten. Solch ein Formular ist schnell hergestellt: Schnell ein Haupt- und ein Unterformular erstellen, Datenherkunft des Unterformulars einstellen, Felder aus der Feldliste hinzufügen, Unterformular ins Hauptformular einfügen, OK-Schaltfläche unterbringen – fertig!
Bild 1: Ein typisches Lookupformular
Was aber, wenn man eine ganze Reihe solcher Formulare benötigt Dann kommt schon ein wenig mehr Arbeit auf einen zu. Außerdem steigt der Aufwand für änderungen wie etwa das Hinzufügen einer Fehlerbehandlungen oder Wartungsarbeiten proportional zur Anzahl der Formulare.
Aus x mach 1
Was tun Sie, wenn Sie die gleiche Abfolge identischer Codezeilen in einer oder mehreren VBA-Funktionen verwenden Sie erzeugen natürlich eine Prozedur oder Funktion, welche die enthaltenen Anweisungen an nur einer Stelle versammelt und rufen diese Anweisungen dann über die entsprechende Prozedur beziehungsweise Funktion auf – gegebenenfalls unter Einbeziehung eines oder mehrerer Parameter, welche die Prozedur oder Funktion individualisieren.
Genau das gleiche machen wir jetzt mit den Lookupformularen. Wenn Sie in einer Anwendung eine Reihe ähnlich aufgebauter Formulare verwenden, denken Sie einmal darüber nach, ob Sie deren Aufbau nicht genau gleich gestalten können (oder zumindest so, dass dieser über Parameter im gewünschten Maße variiert werden kann).
Wir zeigen, wie das mit einem Lookupformular wie aus Bild 1 funktioniert. Als einzigen Parameter verwenden wir dabei den Namen der Tabelle oder Abfrage, deren Daten angezeigt werden sollen beziehungsweise eine entsprechende SQL-Anweisung. Diese soll mit dem Parameter OpenArgs übergeben werden, sodass der Aufruf unseres Formulars beispielsweise so aussieht:
DoCmd.OpenForm "frmLookup", OpenArgs:="tblVerbrauchsarten"
Das aufgerufene Formular wertet diese Datenherkunft dann aus und füllt die Felder des Formulars entsprechend.
Hauptformular
Das Hauptformular übernimmt die Hauptarbeit des Lookupformulars – zumindest, was den Code angeht. Ansonsten enthält es lediglich das Unterformular sfmLookup, das wir im Anschluss beschreiben, sowie eine Schaltfläche mit der Beschriftung OK, die das Formular schließen soll (siehe Bild 2). Diese Schaltfläche löst die folgende Ereignisprozedur aus:
Bild 2: Das Formular frmLookup samt Unterformular in der Entwurfsansicht
Private Sub cmdOK_Click() DoCmd.Close End Sub
Das Unterformular enthält drei ungebundene Textfelder samt Bezeichnungsfeldern. Die Textfelder heißen txtValue1, txtValue2 und txtValue3, die Bezeichnungsfelder lblValue1, lblValue2 und lblValue3. Wie Sie die Felder anordnen, ist egal – hauptsache, Sie stellen die Eigenschaft Standardansicht des Unterformulars auf Datenblatt ein.
Formular öffnen
Kommen wir zum Aufrufen des Formulars. Dies geschieht, wie bereits erwähnt, über die DoCmd-OpenForm-Anweisung mit dem Namen der Datenherkunft als OpenArgs-Parameter. Diesen muss das Formular beim Öffnen auswerten, was in einer Prozedur geschieht, die durch das Ereignis Beim Öffnen geschieht.
Diese Prozedur prüft, ob der OpenArgs-Parameter einen Wert enthält und bricht das Öffnen des Formulars ab, wenn dies nicht der Fall ist:
Private Sub Form_Open(Cancel As Integer) If Len(Nz(Me.OpenArgs, "")) = 0 Then Cancel = True End If End Sub
Dies sollten Sie bedenken, wenn Sie das Formular frmLookup der Beispieldatenbank per Doppelklick auf den Eintrag im Datenbankfenster beziehungsweise Navigationsbereich öffnen möchten.
Nach dieser Prüfung geht die eigentliche Arbeit los, und zwar in der Ereignisprozedur Beim Laden des Formulars (s. Listing 1).
Listing 1: Beim Laden des Formulars werden auch die Felder angepasst und gefüllt.
Private Sub Form_Load() Dim db As DAO.Database Dim obj As Object Dim strColumnHeader As String Dim strOpenArgs As String Dim strCaption As String Dim i As Integer Dim intFieldcount As Integer Dim lngWidth As Long strOpenArgs = Nz(Me.OpenArgs, "") Set db = CurrentDb Me!sfmLookup.Form.Recordsource = strOpenArgs WizHook.Key = 51488399 Select Case WizHook.ObjTypOfRecordSource(strOpenArgs) Case 0 On Error Resume Next db.QueryDefs.Delete "qdfTemp" On Error Goto 0 Set obj = db.CreateQueryDef("qdfTemp", strOpenArgs) Case 1 Set obj = db.TableDefs(strOpenArgs) Case 2 Set obj = db.QueryDefs(strOpenArgs) End Select intFieldcount = obj.Fields.Count If intFieldcount > 3 Then intFieldcount = 3 End If For i = 1 To 3 If intFieldcount < i Then Me!sfmLookup.Form.Controls("txtValue" & i).ColumnHidden = True Else Me!sfmLookup.Form.Controls("txtValue" & i).ControlSource = obj.Fields(i - 1).Name strColumnHeader = obj.Fields(i - 1).Name On Error Resume Next strColumnHeader = obj.Fields(i - 1).Properties("Caption") On Error Goto 0 Me!sfmLookup.Form.Controls("lblValue" & i).Caption = strColumnHeader Me!sfmLookup.Form.Controls("txtValue" & i).ColumnWidth = (Spaltenbreite(db, _ strOpenArgs, strColumnHeader, Me!sfmLookup.Form.Controls("txtValue" & i)) + 500) lngWidth = lngWidth + Me!sfmLookup.Form.Controls("txtValue" & i).ColumnWidth End If Next i Me.InsideWidth = Me.InsideWidth - Me.sfmLookup.Width + lngWidth + 500 Me!sfmLookup.Width = lngWidth + 500 strCaption = obj.Name On Error Resume Next strCaption = obj.Properties("Description") On Error Goto 0 Me.Caption = strCaption End Sub
Das Öffnungsargument wird hier zunächst in der Variablen strOpenArgs zwischengespeichert und dem Unterformular über die Eigenschaft Recordsource als Datenherkunft zugewiesen. Damit ist das Unterformular an die betroffene Tabelle oder Abfrage gebunden.
Danach benötigten wir ein Objekt, anhand dessen wir die Felder der Datenherkunft durchlaufen können, um die Felder des Unterformulars anpassen und füllen zu können. Da der Benutzer mit dem Öffnungsargument beliebige Datenherkünfte übergeben können soll (also Tabellen, Abfragen oder SQL-Ausdrücke), haben wir zwei Möglichkeiten:
Entweder wir öffnen ein Recordset-Objekt auf Basis der angegebenen Datenherkunft und stellen dies per WHERE-Bedingung so ein, dass es keine Datensätze zurückliefert (denn wir brauchen es ja nur zur Identifikation der Felder), oder wir verwenden eines der Datendefinitions-Objekte wie TableDef oder QueryDef. Diese enthalten keine Daten, sondern nur die Definition der Tabelle beziehungsweise Abfrage.
Die erste Variante übergehen wir diesmal, da wir erst noch prüfen müssten, ob der übergebene Ausdruck eine Tabelle, Abfrage oder ein SQL-Ausdruck ist und ob dieser gegebenenfalls schon eine WHERE-Klausel enthält – sprich: Es würden eine Reihe Zeichenkettenfunktionen aufgerufen, die wir uns diesmal einfach sparen möchten.
Im Falle der TableDef-/QueryDef-Variante wissen wir allerdings ebenfalls nicht, ob strOpenArgs nun eine Tabelle, eine Abfrage oder einen SQL-Ausdruck enthält. Das ist aber kein Problem, denn die nicht dokumentierte WizHook-Klasse liefert uns mit ObjTypOfRecordSource eine kleine Funktion, der wir den Datenherkunftsausdruck einfach übergeben können (vorherige Aktivierung durch WizHook.Key = 51488399 nötig). Heraus kommt eine von drei Zahlen:
Ende des frei verfügbaren Teil. Wenn Du mehr lesen möchtest, hole Dir ...
den kompletten Artikel im PDF-Format mit Beispieldatenbank
diesen und alle anderen Artikel mit dem Jahresabo