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:
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.
Außerdem positioniert die Prozedur die Einfügemarke hinter den Doppelpunkt.
Da die Prozedur nun ein passendes Feld für die Autoergänzung gefunden hat, können wir die For…Next-Schleife verlassen.
Der folgende Zweig der Select Case-Bedingung prüft noch, ob der Benutzer die Eingabetaste gedrückt hat (KeyCode hat dann den Wert 13). Dies soll die Suche auslösen.
Ist dies der Fall, wird KeyCode auf den Wert 0 eingestellt, damit die Eingabe nicht wie üblich verarbeitet wird. Außerdem ruft die Prozedur die Routine Suchen mit dem aktuellen Inhalt des Textfeldes als Parameter auf.
Bevor wir uns diese Routine ansehen, werfen wir noch einen Blick auf die Prozedur, die durch das Ereignis Bei Taste auf ausgelöst wird.
Taste im Suchfeld loslassen
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