Filterformular erweitern: Kombinationsfelder

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.

Bisher muss der Benutzer die interne ID des Kategorie-Feldes kennen

Bild 1: Bisher muss der Benutzer die interne ID des Kategorie-Feldes kennen

Bild 2 zeigt die neuen Bedingungen für Nachschlagefelder an:

Der Zwischenschritt: Wir bekommen für Nachschlagefelder neue Bedingungen.

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.

Das Ziel - im Vergleichsfeld erscheint dieselbe Auswahlliste wie im Datenformular.

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:

Access im Unternehmen

Unser exklusives Angebot für Dich!

Access im Unternehmen
13,25 € im Monat*

(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.

PayPal VISA Mastercard SEPA
Kostenlos & unverbindlich

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 →