Suchen mit der clsFlexSearch-Klasse

Wenn Sie ein Abonnement des Magazins 'Access im Unternehmen' besitzen, können Sie sich anmelden und den kompletten Artikel lesen.
Anderenfalls können Sie das Abonnement hier im Shop erwerben.

Suchen mit der clsFlexSearch-Klasse

Die Klasse clsFlexSearch lässt sich einfach in Formulare integrieren und fügt einem einfachen Textfeld umfassende Suchmöglichkeiten hinzu. Wie Sie diese Suche implementieren, erfahren Sie im Beitrag Flexible Suche in Formularen (www.access-im-unternehmen.de/965). Der vorliegende Beitrag erläutert die Klasse clsFlexSearch und stellt den Code vor, damit Sie diesen nachvollziehen und ihn gegebenenfalls an Ihre eigenen Bedürfnisse anpassen können.

Alles in einer Klasse

Die Klasse clsFlexSearch bietet nicht nur eine praktische Suchfunktion, sondern Sie ist außerdem auch noch ganz leicht zu implementieren.

Der Grund ist, dass der komplette Code in einer einzigen Klasse gekapselt ist und Sie dem Formular, das Sie mit der Funktion ausstatten möchten, lediglich einige Zeilen VBA-Code hinzufügen müssen.

Die Klasse hat die Aufgabe, ein Textfeld mit einer Suchfunktion zu versehen (s. Bild 1). Der Benutzer gibt dort das Suchkriterium ein und die in der Klasse enthaltenen Ereignisprozeduren liefern die Funktionen dazu:

Die Klasse clsFlexSearch in Aktion

Bild 1: Die Klasse clsFlexSearch in Aktion

  • die automatische Ergänzung der Eingabe des Benutzers bezüglich der zu durchsuchenden Feldnamen und
  • die Funktion, die den eingegebenen Ausdruck parst und eine entsprechende Where-Klausel formuliert und zurückgibt.

Die Klasse clsFlexSearch

Um die Klasse anzulegen, erstellen Sie im VBA-Editor über Einfügen|Klassenmodul ein neues Klassenmodul und speichern es unter dem Namen clsFlexSearch.

Die Klasse verwendet insgesamt vier Member-Variablen, denen der Benutzer vom Klassenmodul des Formulars aus die entsprechenden Eigenschaftswerte zuweist. Diese Member-Variablen werden wie folgt im Kopf des Klassenmoduls clsFlexSearch deklariert:

Private m_Suchabfrage As String
Private m_PKFeld As String
Private m_PKFeldEinschliessen As Boolean
Private WithEvents m_Suchfeld As TextBox

Eigenschaften zuweisen

Die in diesen vier Variablen gespeicherten Werte sollen über öffentliche Eigenschaften der Implementierung der Klasse clsFlexSearch zugewiesen werden, also etwa so:

With objFlexSearch
     .Suchabfrage = "qryArtikelsuche"
     .PKFeld = "ArtikelID"
     .PKFeldEinschliessen = False
     Set .Suchfeld = Me!txtSucheNach
End With

Diese Eigenschaften zum Entgegennehmen der Werte für die Member-Variablen programmieren wir in der Klasse clsFlexSearch als Public Property Let- beziehungsweise Public Property Set-Prozeduren. Die erste sieht wie in Listing 1 aus und nimmt als Parameter einen Wert entgegen, der nach dem Zuweisen in die Variable m_Suchabfrage eingetragen wird.

Public Property Let Suchabfrage(strSuchabfrage As String)
     m_Suchabfrage = strSuchabfrage
End Property

Listing 1: Öffentliche Eigenschaft für die Angabe der Suchabfrage

Für Wert-Variablen etwa vom Datentyp String verwenden wir das Schlüsselwort Let, später für Objektvariablen das Schlüsselwort Set.

Die Public Property Let-Prozedur PKFeld aus Listing 2 erwartet den Namen des Primärschlüsselfeldes und weist diesen der Membervariablen m_PKFeld zu.

Public Property Let PKFeld(strPKFeld As String)
     m_PKFeld = strPKFeld
End Property

Listing 2: Öffentliche Eigenschaft für die Angabe des Primärschlüsselfeldes

Ähnlich arbeitet die Public Property Let-Prozedur PKFeldEinschliessen. Die an diese Eigenschaft übergebene Variable legt fest, ob der Name des Primärschlüsselfelds im Such-Textfeld automatisch ergänzt und ob es bei der Suche über alle Felder berücksichtigt werden soll (s. Listing 3).

Public Property Let PKFeldEinschliessen(bolPKFeldEinschliessen As Boolean)
     m_PKFeldEinschliessen = bolPKFeldEinschliessen
End Property

Listing 3: Hiermit legen Sie fest, ob der Primärschlüssel für die Suche berücksichtigt wird.

Interessant wird es bei der Public Property Set-Prozedur Suchfeld. Diese nimmt einen Verweis auf das Textfeld entgegen, das zur Eingabe der Suchbegriffe verwendet werden soll.

Die Prozedur speichert diesen Verweis in der Membervariablen m_Suchfeld, welches den Datentyp Textbox aufweist und mit dem Schlüsselwort WithEvents deklariert wurde.

Auf diese Weise können Sie, auch wenn das Textfeld gar kein Objekt der aktuellen Klasse ist, in dieser Klasse auf seine Ereignisse reagieren. Dazu tragen wir für die den relevanten Ereignissen entsprechenden Eigenschaften jeweils den Wert [Event Procedure] ein – hier für die Eigenschaften OnKeyUp und OnKeyDown (s. Listing 4).

Public Property Set Suchfeld(txtSuchfeld As TextBox)
     Set m_Suchfeld = txtSuchfeld
     With m_Suchfeld
         .OnKeyDown = "[Event Procedure]"
         .OnKeyUp = "[Event Procedure]"
     End With
End Property

Listing 4: Zuweisen des Such-Textfeldes

Auf die entsprechenden Ereignisse Bei Taste ab und Bei Taste auf reagieren wir, um bei der Eingabe von Zeichen erstens zu prüfen, ob hier eine automatische Vervollständigung angewendet werden muss, und zweitens, um auf die Tab-Taste und das Zeichen Doppelpunkt (:) zu reagieren.

Beides soll den als Autovervollständigungs-Wert angegebenen Ausdruck bestätigen und einen Doppelpunkt hinten anfügen, damit der Benutzer hier den Vergleichsausdruck eintragen kann.

Beim Herunterdrücken einer Taste

Nun müssen wir die Ereignisprozedur programmieren, die beim Herunterdrücken einer Taste im Suchen-Textfeld ausgelöst wird. Die Prozedur sieht wie in Listing 5 aus und liefert mit KeyCode einen der gedrückten Taste entsprechenden Integer-Wert sowie mit Shift einen Wert, der angibt, ob gleichzeitig die Umschalt-, die Alt- oder die Strg-Taste gedrückt wurde.

Private Sub m_Suchfeld_KeyDown(KeyCode As Integer, Shift As Integer)
     Dim intSelStart As Integer
     Dim intSelLength As Integer
     Dim intStarttemp As Integer
     Dim i As Integer
     Dim intLenTemp As Integer
     Dim strFeldTemp As String
     Dim strSuche As String
     intKeycode = KeyCode
     Select Case intKeycode
         Case 9, 190
             If intKeycode = 190 And Not Shift = acShiftMask Then
                 Exit Sub
             End If
             KeyCode = 0
             strSuche = m_Suchfeld.Text
             intSelStart = m_Suchfeld.SelStart
             intSelLength = m_Suchfeld.SelLength
             If Not ArrayGefuellt(strSuchfelder) Then
                 SuchfelderEinlesen
             End If
             intStarttemp = InStrRev(strSuche, " ", intSelStart + intSelLength) + 1
             strFeldTemp = Mid(strSuche, intStarttemp, intSelStart + intSelLength)
             If Len(strFeldTemp) > 0 Then
                 intLenTemp = Len(strFeldTemp)
                 For i = LBound(strSuchfelder) To UBound(strSuchfelder)
                     If strFeldTemp = Left(strSuchfelder(i), intLenTemp) Then
                         m_Suchfeld.Text = Left(m_Suchfeld.Text, intSelStart + intSelLength - 1) _
                             & Mid(strSuchfelder(i), intLenTemp) & ":" _
                             & Mid(m_Suchfeld.Text, intSelStart + intSelLength + 1)
                         m_Suchfeld.SelStart = _
                             intSelStart + intSelLength + Len(strSuchfelder(i)) - intLenTemp + 1
                         Exit For
                     End If
                 Next i
             End If
         Case 13
             Suchen m_Suchfeld.Text
             KeyCode = 0
         Case Else
             Debug.Print intKeycode
     End Select
End Sub

Listing 5: Ereignisprozedur, die bei Herunterdrücken einer Taste im Suchen-Textfeld ausgelöst wird

Die Prozedur speichert zunächst den KeyCode in der Variablen intKeyCode, die wir im Kopf des Klassenmoduls wie folgt deklarieren:

Dim intKeycode As Integer

Dies ist nötig, weil wir den KeyCode in einigen Fällen auch noch in der später aufgerufenen Ereignisprozedur m_Suchfeld_KeyUp benötigen, diese aber in m_Suchfeld_KeyDown auf den Wert 0 setzen, damit die eigentliche Wirkung dieses Tastendrucks unterdrückt wird.

Die folgende Select Case-Bedingung prüft einige Werte für intKeyCode. Der erste Zweig reagiert auf die Werte 9 und 190. 9 entspricht der Tab-Taste, 190 dem Doppelpunkt.

Eigentlich entspricht 190 der Taste, auf der sich der Punkt und der Doppelpunkt befinden, aber auf den Punkt wollen wir nicht reagieren. Also verlassen wir die Prozedur, wenn der zweite Parameter, Shift, nicht den Wert 1 (oder acShiftMask) enthält.

In diesem Fall stellen wir KeyCode auf den Wert 0 ein, da etwa das Betätigen der Tab-Taste sonst zum Verlassen des Textfeldes führen würde. Die Prozedur speichert den aktuellen Inhalt des mit m_Suchfeld referenzierten Such-Textfeldes in der Variablen strSuche. Die Variable intSelStart nimmt die aktuelle Position der Einfügemarke auf, die Variable intSelLength die Länge des aktuell markierten Textes.

Nun benötigen wir eine Liste aller Suchfelder, also derjenigen Felder, die in der für die Eigenschaft Suchabfrage angegebenen Abfrage enthalten sind.

Der Performance halber wollen wir diese nicht jedes Mal neu aus der Definition der Abfrage abrufen, deshalb speichern wir diese einmalig in einem Array namens strSuchfelder.

Um dieses nur einmal zu füllen, prüfen wir zunächst mithilfe der Funktion ArrayGefuellt, ob das Array strSuchfelder bereits gefüllt ist. Diese Funktion erläutern wir im Detail im Beitrag Mit Arrays arbeiten (www.access-im-unternehmen.de/963).

Die Variable strSuchfelder deklarieren wir übrigens wie folgt im Kopf des Klassenmoduls clsFlexSearch:

Dim strSuchfelder() As String

Wenn das Array noch nicht gefüllt ist, liest die Prozedur SuchfelderEinlesen die Felder der unter m_Suchabfrage angegebenen Abfrage in das Array strSuchfelder ein (s. Listing 6). Die Prozedur öffnet ein QueryDef-Objekt auf Basis der angegebenen Abfrage und durchläuft in einer For Each-Schleife alle Felder dieser Abfrage. Dabei prüft die Prozedur, ob es sich bei dem aktuellen Feld um das als Primärschlüssel angegebene Feld handelt und dieses gleichzeitig für die Suche berücksichtigt werden soll.

Private Sub SuchfelderEinlesen()
     Dim db As DAO.Database
     Dim qdf As DAO.QueryDef
     Dim fld As DAO.Field
     Dim i As Integer
     Set db = CurrentDb
     Set qdf = db.QueryDefs(m_Suchabfrage)
     For Each fld In qdf.Fields
         If Not (fld.Name = m_PKFeld And m_PKFeldEinschliessen = False) Then
             ReDim Preserve strSuchfelder(qdf.Fields.Count) As String
             strSuchfelder(i) = fld.Name
             i = i + 1
         End If
     Next fld
End Sub

Listing 6: Einlesen von Suchfeldern in ein Array

Ist dies der Fall oder handelt es sich um eines der übrigen Felder, fügt die Prozedur den Namen des Feldes zum Array hinzu, wobei zuvor die Anzahl der zulässigen Elemente angepasst wird.

Die Prozedur ermittelt dann ausgehend von der aktuellen Position der Einfügemarke die Position des ersten Leerzeichens links von der Einfügemarke und speichert diese in der Variablen intStartTemp. Sollte hierbei kein Leerzeichen gefunden werden, liefert die InStrRev-Funktion den Wert 0. In jedem Fall addiert diese Zeile den Wert 1 zum Ergebnis.

In strFeldTemp landet dann die Zeichenkette, die sich zwischen dieser Position und der aktuellen Position der Einfügemarke befindet (inklusive Markierung, falls vorhanden).

Enthält strFeldTemp nun einen Wert (Len(strFeldTemp) > 0), beginnt die weitere Verarbeitung. Die Variable intLen­Temp wird nun mit der Länge des in strFeldTemp gespeicherten Ausdrucks gefüllt.

In einer For...Next-Schleife durchläuft die Prozedur alle Einträge des Arrays strSuchfelder, also alle Feldnamen der Suchabfrage. Darin prüft die Prozedur, ob der in strFeldTemp gespeicherte Ausdruck mit den ersten intLenTemp Zeichen des Feldnamens übereinstimmt.

Wenn strFeldTemp also nun den Aus­druck Art enthält, weil der Benutzer gerade das Feld Artikelname eintippen möchte, vergleicht die Prozedur diesen Ausdruck jeweils mit den ersten drei Zeichen der in der Variablen strSuchfelder gespeicherten Feldnamen. Stößt die Prozedur so auf das Feld Artikelname, wird der Teil innerhalb der If...Then-Bedingung ausgeführt. Hier trägt die Prozedur einen Ausdruck in die Eigenschaft Text des Suchen-Textfeldes ein, der aus den folgenden Elementen besteht:

  • Inhalt des Such-Textfeldes bis zur Einfügemarke und
  • den Teil des gefundenen Feldnamens, der noch nicht eingegeben wurde (in diesem Beispiel Artikelname ohne die ersten drei Buchstaben Art, also ikelname) und
  • den Doppelpunkt.

Dies war die Leseprobe dieses Artikels.
Melden Sie sich an, um auf den vollständigen Artikel zuzugreifen.

Bitte geben Sie die Zeichenfolge in das nachfolgende Textfeld ein

Die mit einem * markierten Felder sind Pflichtfelder.

Ich habe die Datenschutzbestimmungen zur Kenntnis genommen.