In den ersten beiden Teilen dieser Beitragsreihe haben wir ein universell einsetzbares Filterformular vorgestellt und seine Programmierung beleuchtet. Bisher bietet das Formular für Vergleichswerte schlicht ein Textfeld an. Bei einem Feld wie „AnredeID“ oder „KategorieID“, das im aufrufenden Formular über ein Kombinationsfeld dargestellt wird, muss der Benutzer aber die nackte Zahl kennen, nach der er filtern will – wenig komfortabel. In diesem Teil erweitern wir das Filterformular so, dass es solche Lookup-Felder erkennt und im Vergleichsfeld dieselbe Auswahlliste anbietet wie das Originalformular.
Die Ausgangslage
Viele Tabellen arbeiten mit Fremdschlüsseln. In der Kundentabelle aus den ersten Teilen könnte etwa ein Feld AnredeID stehen, das auf eine Tabelle tblAnreden verweist. Im Datenformular zeigt ein gebundenes Kombinationsfeld dann nicht die ID, sondern den sprechenden Namen an – also „Herr“ statt „1“. Das Filterformular kennt diese Zuordnung jedoch nicht: Es liest nur das Recordset aus und stellt für ein Zahlenfeld ein Texteingabefeld bereit.
Wie sich das auswirkt, ist in Bild 1 Bild 1 zu sehen: Der Benutzer möchte nach der Kategorie filtern, bekommt aber nur ein leeres Eingabefeld und müsste die interne ID erraten. Genau hier setzen wir an. Wir wollen die Filterkriterien für Kombinationsfelder so gestalten, dass wir erstens die Bedingungen anpassen und zweitens die vorhandenen Werte als Vergleichswerte auswählen können.

Bild 1: Bisher muss der Benutzer die interne ID des Kategorie-Feldes kennen
Bild 2 zeigt die neuen Bedingungen für Nachschlagefelder an:

Bild 2: Der Zwischenschritt: Wir bekommen für Nachschlagefelder neue Bedingungen.
- Gleich: Liefert alle Datensätze, für die der gleiche Wert ausgewählt ist.
- Nicht gleich: Liefert alle Datensätze, die nicht den ausgewählten Wert enthalten.
- Ist leer: Liefert alle Datensätze, für die das Nachschlagefeld leer ist.
- Ist nicht leer: Liefert alle Datensätze, für die das Nachschlagefeld nicht leer ist.
Bild 3 zeigt, wie wir die vorhandenen Werte als Vergleichswerte auswählen können.

Bild 3: Das Ziel – im Vergleichsfeld erscheint dieselbe Auswahlliste wie im Datenformular.
Das Konzept
Die Lösung besteht aus drei Bausteinen. Erstens muss das Filterformular beim Einlesen der Felder erkennen, ob ein Feld im aufrufenden Formular über ein Kombinationsfeld dargestellt wird, und sich dessen Datensatzherkunft merken.
Zweitens braucht jede Filterzeile ein zusätzliches Kombinationsfeld als alternatives Wertfeld. Drittens muss beim Aufbau des SQL-Ausdrucks der gebundene Wert – also die ID – verwendet werden, nicht der angezeigte Text.
Der angenehme Nebeneffekt: An der eigentlichen SQL-Logik in GetFilterausdruck ändert sich nichts.
Da das neue Kombinationsfeld seinen gebundenen Wert liefert und der zugrunde liegende Feldtyp (Zahl oder Text) erhalten bleibt, quotiert die Funktion den Wert wie gewohnt – Zahlen ohne, Texte mit Anführungszeichen.
Vorbereitung: Übergabe des zu filternden Recordsets durch Formular ersetzen
Bisher haben wir beim Aufrufen des Filterformulars einen Verweis auf das aufrufende Formular sowie auf das zu filternde Recordset übergeben. Um für ein zu filterndes Nachschlagefeld jedoch die notwendigen Informationen zu holen, benötigen wir einen Verweis auf das jeweilige Nachschlagefeld. Deshalb haben wir den Aufruf des Filterformulars so angepasst, dass wir keinen Verweis auf das zu filternde Recordset übergeben, sondern einen auf das Form-Objekt, welches das Recordset anzeigt.
Der Aufruf ändert sich also wie folgt:
Private Sub cmdFilter_Click() DoCmd.OpenForm "frmFilter" Set Forms!frmFilter.CallingForm = Me Set Forms!frmFilter.RecordsetForm = _ Me.sfmDatenMitFilter.Form End Sub
In Form_frmFilter haben wir dazu eine neue Variable hinterlegt:
Private m_frmDaten As Form
Sie kann über diese öffentliche Property Set-Prozedur gefüllt werden:
Public Property Set CallingForm(frm As Form) Set m_frmAufrufend = frm End Property
Schritt 1: Lookup-Felder erkennen
Beim Öffnen liest das Filterformular in LadeFelder alle Felder des Recordsets aus. An dieser Stelle ergänzen wir die Erkennung. Für jedes Feld prüfen wir, ob im aufrufenden Formular ein an dieses Feld gebundenes Kombinationsfeld existiert. Die dazu nötigen Metadaten halten wir in einem benutzerdefinierten Typ fest, den wir wie folgt definieren:
Private Type TKombiInfo IstKombi As Boolean RowSource As String RowSourceType As String ColumnCount As Integer ColumnWidths As String BoundColumn As Integer End Type
Das Array m_Kombi speichert für jedes Recordset-Feld die komplette Konfiguration eines eventuell vorhandenen Kombinationsfelds:
Private m_Kombi() As TKombiInfo
Die Matrix m_bolAktKombi merkt sich pro Filterzeile, ob das dort gerade gewählte Feld ein Lookup-Feld ist – analog zur bereits vorhandenen Feldtyp-Matrix:
Private m_bolAktKombi(1 To 5, 1 To 5) As Boolean
Die eigentliche Erkennung erledigt ErmittleKombiInfo. Die Prozedur sucht im datentragenden Formular nach einem Steuerelement, dessen Datensatzherkunft (die Eigenschaft ControlSource) dem Feldnamen entspricht, und kopiert dessen Eigenschaften in die Struktur (siehe Listing 1).
Private Sub ErmittleKombiInfo(strFeld As String, ByRef tKombi As TKombiInfo) Dim cbo As ComboBox tKombi.IstKombi = False If m_frmAufrufend Is Nothing Then Exit Sub End If Set cbo = SucheKombiSteuerelement(m_frmAufrufend, strFeld) If cbo Is Nothing Then Exit Sub End If If Len(Nz(cbo.RowSource, "")) = 0 Then Exit Sub End If tKombi.IstKombi = True tKombi.RowSource = cbo.RowSource tKombi.RowSourceType = cbo.RowSourceType tKombi.ColumnCount = cbo.ColumnCount tKombi.ColumnWidths = Nz(cbo.ColumnWidths, "") tKombi.BoundColumn = cbo.BoundColumn End Sub
Listing 1: ErmittleKombiInfo merkt sich die Liste eines gebundenen Kombinationsfelds
Hier ist m_frmDaten der entscheidende Punkt. Das zu filternde Recordset gehört immer zu genau einem Formular – entweder dem Hauptformular selbst oder dem konkret angegebenen Unterformular.
Und genau in diesem Formular sitzen auch die gebundenen Kombinationsfelder, deren Liste wir brauchen. Die Funktion SucheKombiSteuerelement durchsucht deshalb Steuerelemente dieses einen Formulars, wie Listing 2 zeigt.
Private Function SucheKombiSteuerelement(frm As Form, strFeld As String) As ComboBox Dim ctl As Control For Each ctl In frm.Controls If ctl.ControlType = acComboBox Then If StrComp(Nz(ctl.ControlSource, ""), strFeld, vbTextCompare) = 0 Then Set SucheKombiSteuerelement = ctl Exit Function End If End If Next ctl End Function
Listing 2: SucheKombiSteuerelement durchsucht genau das datentragende Formular
Damit dieses datentragende Formular überhaupt zur Verfügung steht, übergeben wir es, wie oben bereits beschrieben, statt wie bisher nur das Recordset.
Schritt 2: Passende Bedingungen anbieten
Für ein Lookup-Feld ergeben nur diskrete Vergleiche Sinn. Operatoren wie Größer als oder Enthält wären hier unpassend, weil der Benutzer ja einen konkreten Listeneintrag auswählt. Gleichzeitig wollen wir für die Nachschlagefelder keine Eingabe von Vergleichsausdrücken mit Platzhaltern erlauben. Deshalb spendieren wir dem Modul mdlFilter eine eigene, schlanke Bedingungsliste, die das folgende Listing wiedergibt:
Unser exklusives Angebot für Dich!
(Gilt für den Abschluss eines Jahres-Abonnements im ersten Jahr, danach 189,-/Jahr)
Hier geht’s weiter →Die ersten 4 Wochen kostenlos testen – voller Zugriff auf alle Artikel, vollständigen Code und Beispieldatenbanken. Kein Risiko: Wenn es nicht passt, kündigst Du einfach innerhalb der ersten vier Wochen.
Hast Du eine konkrete Frage zu Deiner eigenen Access-Anwendung?
Vielleicht stellt Deine Anwendung Dich vor eine Herausforderung, zu der Du bisher keine Lösung findest. Schlechte Performance, kein ausreichender Zugriffsschutz, Du bist unsicher über Dein Datenmodell oder Dein Code liefert unerklärliche Fehler?
In unserem kostenlosen Access-Audit schaut sich André Minhorst persönlich gemeinsam mit Dir Deine Lösung per Zoom an – und zeigt Dir, wo Datenmodell, VBA-Code, Ergonomie und Sicherheit Optimierungspotenzial bieten.
Jetzt kostenloses Access-Audit anfordern →