Schnellsuche im Listenfeld mal anders

In vielen bisherigen Lösungen haben wir für die Schnellsuche im Listenfeld oder auch in Unterformularen in der Datenblattansicht ein Textfeld als Suchfeld verwendet. Direkt bei Eingabe eines jeden Zeichens wurde das Suchergebnis aktualisiert. In diesem Beitrag wollen wir einmal eine noch ergonomischere Version vorstellen. Der Unterschied soll so aussehen, dass man den Suchbegriff eingeben kann, während das Listenfeld den Fokus hat. Es soll also kein Wechseln vom Suchfeld zum Listenfeld und zurück nötig sein, wenn man durch die Suche den gewünschten Datensatz vorgefunden hat und diesen beispielsweise markieren und beispielsweise durch Betätigen der Eingabetaste eine Aktion für diesen Eintrag durchführen möchte. Wir zeigen dies am Beispiel aus dem Beitrag “m:n-Beziehung mit Listenfeld und Datenblatt” (www.access-im-unternehmen.de/1510).

Im oben genannten Beitrag haben wir bereits eine effiziente Möglichkeit entwickelt, um eine m:n-Beziehung mithilfe eines Listenfeldes und eines Datenblattes in einem Unterformular abzubilden. Das Ziel war es, dass wir nicht wie in üblichen Bestellformularen einfach nur das gesuchte Produkt aus dem Auswahlfeld der hinzuzufügenden Bestellposition heraussuchen können.

Stattdessen wollten wir die Möglichkeit bieten, solche Einträge aus einem Listenfeld auszuwählen und diese schnell per Doppelklick zu dem Datensatz im übergeordneten Formular hinzuzufügen. Bei dem Beispiel dreht es sich um Fahrzeuge und ihre Ausstattungen (siehe Bild 1).

Beispiel für die Listenfeldsuche

Bild 1: Beispiel für die Listenfeldsuche

Es ist nun vielleicht bereits etwas effizienter, einen Eintrag aus dem Listenfeld auszuwählen und dieses per Doppelklick zum Fahrzeug hinzuzufügen – gerade, wenn die ausgewählten Einträge danach nicht mehr über das Listenfeld angeboten werden. Allerdings kann es sein, dass es über 200 Einträge in der Liste der Sonderausstattungen gibt. In diesem Fall ist es immer noch langwierig, wenn man sich durch die ganze Liste wühlen muss, um zum gesuchten Eintrag zu gelangen. Auch eine alphabetische Sortierung ist nicht unbedingt zielführend, weil manche Ausstattungen so benannt sind, dass der gesuchte Begriff noch nicht einmal vorn in der Bezeichnung der Ausstattung steht.

Suchfunktion zum Listenfeld hinzufügen

Der nächste Schritt wäre also eine Such- beziehungsweise Filterfunktion zum Listenfeld hinzuzufügen. Eine solche haben wir schon des Öfteren gebaut und wir haben immer ein Textfeld zum Listenfeld hinzugefügt, in das der Benutzer zeichenweise den Suchbegriff eingeben kann.

Der Inhalt des Listenfeldes wurde nach jeder Änderung aktualisiert, damit der Benutzer schnell sehen konnte, wenn der gesuchte Eintrag im sichtbaren Bereich auftauchte oder sogar ganz oben in der Liste stand.

Diesem Textfeld, das wir wie auch in diesem Fall meist txtSuche nennen, fügen wir für die Ereigniseigenschaft Bei Änderung den Wert [Ereignisprozedur] hinzu und hinterlegen für diese eine Ereignisprozedur wie die folgende:

Private Sub txtSuche_Change()
     AusstattungslisteFuellen Me!txtSuche.Text
End Sub

Diese ruft die Prozedur AusstattungslisteFuellen auf und übergibt dieser den aktuellen Inhalt des Textfeldes txtSuche als Parameter.

Füllen des Listenfeldes auf Basis des Suchkriteriums

Die Prozedur AusstattungslisteFuellen erwartet mit dem Parameter strSuche den Suchbegriff, also die Zeichenkette, die in den anzuzeigenden Listenfeld-Einträgen enthalten sein muss (siehe Listing 1).

Public Sub AusstattungslisteFuellen(Optional strSuche As String)
     Dim strSQL As String
     Dim lngFahrzeugID As Long
     If Me.NewRecord = False Then
         lngFahrzeugID = Nz(Me!FahrzeugID)
         strSQL = "SELECT AusstattungID, Ausstattung " _
             & "FROM tblAusstattungen " _
             & "WHERE [Suche]AusstattungID " _
             & "Not In (" _
             & "SELECT AusstattungID " _
             & "FROM tblFahrzeugeAusstattungen " _
             & "WHERE FahrzeugID = " & lngFahrzeugID _
             & ") " _
             & "ORDER BY Ausstattung;"
         If Len(strSuche) = 0 Then
             strSQL = Replace(strSQL, "[Suche]", "")
         Else
             strSQL = Replace(strSQL, "[Suche]", "Ausstattung LIKE ''*" & strSuche & "*'' AND ")
         End If
     Else
         strSQL = "SELECT AusstattungID, Ausstattung FROM tblAusstattungen ORDER BY Ausstattung"
     End If
     Me!lstAusstattungen.RowSource = strSQL
     Me!lstAusstattungen.Value = Null
End Sub

Listing 1: Prozedur zum Aktualisieren der Einträge im Listenfeld

Sie prüft zuerst, ob das Hauptformular aktuell einen neuen, leeren Datensatz enthält. In diesem Fall wird der zweite Teil der If…Then-Bedingung ausgeführt, der dem Listenfeld eine Datensatzherkunft zuweist, die alle Einträge der Tabelle tblAusstattungen liefert.

Anderenfalls ermittelt die Prozedur den Primärschlüsselwert des im Hauptformular angezeigten Fahrzeugs und speichert diesen in der Variablen lngFahrzeugID.

Anschließend setzt sie in der Variablen strSQL eine SQL-Anweisung zusammen, die alle Datensätze der Tabelle tblAusstattungen liefert, die noch nicht mit dem aktuell angezeigten Fahrzeug verknüpft sind.

Diese Abfrage verwendet eine Unterabfrage, die alle Einträge der Tabelle tblFahrzeugeAusstattungen liefert, deren FahrzeugID mit dem Wert des aktuellen Fahrzeugs übereinstimmt.

Hier finden wir einen Platzhalter namens [Suche], der anschließend ersetzt wird. Befindet sich im Textfeld txtSuche eine Zeichenkette mit einer Länge von 0 Zeichen, wird [Suche] einfach durch eine leere Zeichenkette ersetzt.

Anderenfalls fügen wir für [Suche] ein vollständiges Kriterium wie Ausstattung LIKE ”*Suchbegriff*” AND ein.

Schließlich wird der Inhalt aus strSQL der Eigenschaft RowSource (Datensatzherkunft) des Listenfeldes zugewiesen und der Wert des Listenfeldes wird auf Null eingestellt.

Auf diese Weise funktioniert die herkömmliche Suche über das Textfeld (siehe Bild 2) – das Listenfeld liefert nur noch solche Einträge, die zum angegebenen Suchbegriff passen.

Beispiel für eine Suche über das Textfeld

Bild 2: Beispiel für eine Suche über das Textfeld

Upgrade der Schnellsuche

Nun stellen wir uns vor, wie das Arbeiten in diesem Formular funktioniert: Der Benutzer gibt einen Suchbegriff ein, bis er den gewünschten Eintrag sieht, und klickt diesen dann mit der Maus doppelt an, damit dieser zum Fahrzeug hinzugefügt wird (siehe Bild 3). Alternativ kann er auch den Fokus zum Listenfeld wechseln, den gewünschten Eintrag markieren und diesen mit der Eingabetaste zu den Ausstattungen des Fahrzeugs hinzufügen. Zusätzlich können wir auch noch dafür sorgen, dass das Suchfeld geleert wird und das Listenfeld wieder alle noch verfügbaren Einträge anzeigt – das dürfte in den meisten Settings sinnvoll sein.

Ein per Doppelklick hinzugefügter Eintrag

Bild 3: Ein per Doppelklick hinzugefügter Eintrag

Wenn der Benutzer nun jedoch das nächste Ausstattungsmerkmal hinzufügen und dieses dazu suchen möchte, muss er den Fokus zunächst manuell wieder zum Suchen-Textfeld zurückversetzen.

Damit kommt man auf eine ganze Menge Mausklicks und Tastenanschläge, bis man alle Ausstattungsmerkmale hinzugefügt hat. Und damit kommt das Feature ins Spiel, dass uns die Aufgabe deutlich vereinfacht: Wir wollen den Suchbegriff nun einfach eingeben können, ohne dass wir das Listenfeld verlassen müssen! Der Benutzer soll also, während er durch das Listenfeld navigiert und per Eingabetaste Einträge zu den Ausstattungen hinzufügt, einfach den Inhalt des Suchfeldes aktualisieren und Buchstaben hinzufügen oder entfernen können.

Tastenanschläge über das Listenfeld abfangen

Dazu müssen wir alle Tastenanschläge abfangen, die der Benutzer erledigt, während das Listenfeld den Fokus hat. Dazu verwenden wir das Ereignis Bei Taste des Listenfeldes. Für dieses hinterlegen wir die Prozedur aus Listing 2. Diese erhält mit dem Parameter KeyAscii den jeweiligen ASCII-Wert der gedrückten Taste. Davon interessieren uns die folgenden Zeichen inklusive des Leerzeichens, die wir in einer Konstanten namens cStrChars speichern:

Private Sub lstAusstattungen_KeyPress(KeyAscii As Integer)
     Dim strSuche As String
     Const cStrChars As String = " abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZßäÄöÖüÜ" _
         & "1234567890!§$%&/()=?*+~''#-_.:,;"
     strSuche = Nz(Me!txtSuche, "")
     If Not InStr(1, cStrChars, Chr(KeyAscii)) = 0 Then
         Me!txtSuche = Me!txtSuche & Chr(KeyAscii)
         KeyAscii = 0
     Else
         Select Case KeyAscii
             Case 8
                 If Not Len(Me!txtSuche) = 0 Then
                     Me!txtSuche = Left(Me!txtSuche, Len(Me!txtSuche) - 1)
                 End If
             Case vbKeyEscape
                 Me!txtSuche = Null
                 KeyAscii = 0
         End Select
     End If
     If Not Nz(Me!txtSuche, "") = strSuche Then
         Me.TimerInterval = 100
     End If
End Sub

Listing 2: Prozedur zum Abfangen der Tastenanschläge über das Listenfeld

abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZßäÄöÖüÜ1234567890!§$%&/()=?*+~''#-_.:,;

Wir fügen dann den Inhalt des Suchfeldes in die Variable strSuche ein. Sollte txtSuche den Wert Null enthalten, landet eine leere Zeichenkette in strSuche.

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

Schreibe einen Kommentar