Schnelle Suche mit Klasse

Sie kennen sicher die Art von Schnellsuche, bei der direkt bei der Eingabe von Zeichen gefiltert wird. Diese kann sich auf eines oder mehrere Felder beziehen, arbeitet aber sonst prinzipiell immer gleich: Das Eingeben eines Zeichens löst ein Ereignis aus, dass den aktuellen Suchbegriff ermittelt, eine SQL-Where-Bedingung zusammenstellt und diese dem Filter-Kriterium des Formulars zuweist. Wie Sie eine solche Suche ganz leicht implementieren, zeigt dieser Beitrag.

In letzter Zeit stelle ich fest, dass ich eine solche Suche eigentlich in fast allen Formularen benötige – egal, ob es sich um die Formular-, Endlos- oder Datenblattansicht handelt. In der Regel reicht die Eingabe eines oder mehrerer Buchstaben aus, um schnell beim gesuchten Datensatz zu landen – eine effizientere Suchmethode gibt es nicht.

Eine Ausnahme ist es wohl, wenn Sie aus vielen Datensätzen einen oder mehrere herausfiltern möchten, die bestimmte Kriterien aufweisen – dann sind Sie aber mit einer Abfrage oder einer darauf aufbauenden umfassenderen Suchfunktion besser bedient. Die Lösung aus diesem Beitrag bezieht sich eher auf solche Anwendungsfälle, bei denen Sie mal eben den Kunden zu einer E-Mail-Anfrage herausfinden möchten oder diesen über seine Kundennummer identifizieren möchten.

Beispielsuche

Die Basis für die in diesem Beitrag beschriebene Lösung ist ein Formular wie das aus Bild 1 (siehe Formular frmSchnellsuche in der Beispieldatenbank). Das Formular zeigt Daten in der Endlosansicht an und besitzt ein Textfeld zur Eingabe von Suchbegriffen.

pic002.png

Bild 1: Die Beispielsuche in Aktion

Nach der Eingabe etwa des Buchstabens L filtert das Formular bereits und zeigt nur noch alle Datensätze an, deren Artikelname mit dem Buchstaben L beginnt.

Wenn Sie hier nun den Buchstaben A eingeben, zeigt das Formular nur noch alle Artikel an, deren Name mit La beginnt.

Im Entwurf sieht das Formular wie in Bild 2 aus. Es ist an die Tabelle tblArtikel gebunden und verwendet für die Eigenschaft Standardansicht den Wert Endlosformular. Das Textfeld im Kopf des Formulars heißt txtSchnellsuche und besitzt eine Prozedur, die durch das Ereignis Bei änderung ausgelöst wird.

pic001.png

Bild 2: Entwurfsansicht der Beispielsuche

Die Prozedur stellt zunächst ein Filterkriterium zusammen, dass aus dem Feldnamen, dem Vergleichsoperator (hier LIKE) und dem Wert der Eigenschaft Text des Such-Textfeldes besteht. Dieser Ausdruck wird dann der Eigenschaft Filter zugewiesen.

Dies geschieht jedoch nur, wenn das Suchfeld einen Vergleichswert enthält. Es kann jedoch auch sein, dass der Benutzer ein Zeichen eingibt und dieses wieder löscht. In diesem Fall gäbe es keinen Suchbegriff mehr.

Das Filterkriterium würde zwar wegen des enthaltenen Sternchens (*) dennoch wie erwartet alle Datensätze zurückliefern, aber gegebenenfalls fällt das statisch eingebaute Sternchen später einmal weg – und dann liefert das Filterkriterium schlicht keinen Datensatz mehr zurück. Also prüft die Prozedur zunächst die Länge des Vergleichswerts:

Private Sub txtSuche_Change()
    Dim strFilter As String
    If Not Len(Me!txtSuche.Text) = 0 Then
        strFilter = "Artikelname LIKE ''" & Me!txtSuche.Text & "*''"
        Me.Filter = strFilter
        Me.FilterOn = True
    Else
        Me.Filter = ""
        Me.FilterOn = False
    End If
End Sub

Warum verwenden wir hier die Text-Eigenschaft und nicht den Wert des Suchfeldes Weil der Wert erst nach dem Abschließen der Eingabe etwa durch Drücken der Eingabetaste oder Verlassen des Suchfeldes auf die aktuell im Textfeld enthaltene Zeichenkette eingestellt wird. Die Text-Eigenschaft hingegen liefert immer den aktuell angezeigten Text.

Hakelige Eingabe

Je nach der aktuellen Einstellungen der Option Cursorverhalten bei Eintritt in Feld kann es vorkommen, dass der komplette Suchbegriff markiert wird oder die Einfügemarke wieder zum Beginn des eingegebenen Textes verschoben wird.

Obwohl es nicht so aussieht, verliert das Textfeld zur Eingabe des Suchbegriffes kurz den Fokus, während der Filter eingestellt wird – und wenn das Textfeld den Fokus zurückerhält, stellt Access den Cursor so ein, wie es in den Access-Optionen vorgesehen ist.

Unter Access 2010 finden Sie diese Einstellung etwa unter Backstage|Access-Optionen und dort im Bereich Clienteinstellungen (s. Bild 3).

pic003.png

Bild 3: Einstellung für das Cursorverhalten

Dummerweise können Sie sich nicht darauf verlassen, dass der Benutzer die von Ihnen gewünschte Einstellung verwendet – und Sie sollten diese auch nicht selbstständig anpassen, denn dann findet der Benutzer möglicherweise an anderer Stelle nicht mehr das gewohnte Verhalten vor.

Also fügen Sie ein paar Zeilen zur Suchfunktion hinzu, die dafür sorgen, dass sich diese die Cursorposition nach der Eingabe eines Zeichens merkt und diese unabhängig von der aktuellen Einstellung der Option Cursorverhalten bei Eintritt in Feld wiederherstellt.

Außerdem verlor das Textfeld den Fokus, wenn es als Text nur noch eine leere Zeichenkette anzeigte – nach dem Zurücksetzen des Filters sollte man also noch den Fokus auf das Suchfeld zurücksetzen:

Private Sub txtSuche_Change()
    Dim strFilter As String
    Dim intStart As Integer
    intStart = Me!txtSuche.SelStart
    If Not Len(Me!txtSuche.Text) = 0 Then
        strFilter = "Artikelname LIKE ''" & Me!txtSuche.Text & "*''"
        Me.Filter = strFilter
        Me.FilterOn = True
        Me!txtSuche.SelStart = intStart
    Else
        Me.Filter = ""
        Me.FilterOn = False
        Me!txtSuche.SetFocus
    End If
End Sub

Diese Prozedur lässt sich nicht nur für Formulare in der Endlosansicht, sondern auch für solche in der Formularansicht einsetzen.

Schnellsuche in Datenblättern

In der Datenblattansicht sind natürlich kleine änderungen nötig. Formulare in der Datenblattansicht zeigen nur die Daten an und keine weiteren Steuerelemente wie Suchfelder oder OK-Schaltflächen.

Dazu müssen Sie ein Hauptformular anlegen und darin zumindest das Suchfeld und das Unterformular in der Datenblattansicht anzeigen. Dies sieht im Entwurf wie in Bild 4 aus (siehe frmSchnellsucheDatenblatt und sfmSchnellsucheDatenblatt).

pic004.png

Bild 4: Entwurf des Suchformulars für Datenblätter

Die Prozedur, die durch das Eingeben eines Zeichens in das Textfeld txtSuche ausgelöst wird, sieht in diesem Fall wie in Listing 1 aus. Der erste wesentliche Unterschied ist der geänderte Bezug auf das zu filternde Formular (hier Me!sfmSchnellsucheDatenblatt.Form). Der zweite ist, dass das Suchfeld beim Einstellen des Filters nicht den Fokus verliert und so einige Zeilen eingespart werden können.

Listing 1: Code zum Aktualisieren des Filters auf Basis des Suchbegriffs

Private Sub txtSuche_Change()
    Dim strFilter As String
    If Not Len(Me!txtSuche.Text) = 0 Then
        strFilter = "Artikelname LIKE ''" & Me!txtSuche.Text & "*''"
        Me!sfmSchnellsucheDatenblatt.Form.Filter = strFilter
        Me!sfmSchnellsucheDatenblatt.Form.FilterOn = True
    Else
        Me!sfmSchnellsucheDatenblatt.Form.Filter = ""
        Me!sfmSchnellsucheDatenblatt.Form.FilterOn = False
    End If
End Sub

Variationen der Schnellsuche

Nun möchten Sie eine Suche wie diese gegebenenfalls in mehreren Formularen einsetzen und dabei auch noch Varianten einbauen. Diese könnten so aussehen:

  • Sie möchten mit einem Suchfeld gleich mehrere Felder der Datenherkunft durchsuchen, also beispielsweise Vorname, Nachname und Firma eines Kunden. In diesem Fall sollen die einzelnen Filterkriterien mit dem Oder-Operator verknüpft werden.
  • Sie möchten mehrere Suchfelder einsetzen, um gezielt Felder wie Vorname, Nachname oder Firma zu durchsuchen. In diesem Fall ist der Und-Operator zur Verknüpfung der einzelnen Filterkriterien zu verwenden.

Beim Einsatz in mehreren Formularen einer Anwendungen müssten Sie gleichartig aufgebauten Code mehrfach verwenden. Günstiger wäre es, wenn man die benötigten Funktionen an einem einzigen Ort unterbringen könnte und im jeweiligen Formular nur noch die Such-Steuerelemente unterbringt und die Einstellungen für die gewünschte Suchfunktion vornimmt.

Einsatz der Schnellsuche

Bevor wir auf die technischen Details der nachfolgend beschriebenen Lösung eingehen, schauen wir uns die Funktionsweise und die Konfiguration an. Dabei gibt es die folgenden Varianten:

  • ein Suchfeld soll ein Feld filtern (zwei Möglichkeiten),
  • ein Suchfeld soll mehrere Felder filtern oder
  • mehrere Suchfelder sollen jeweils ein Feld filtern.

Bei allen Konfigurationen sind die folgenden Schritte nötig:

  • Die beiden Klassen clsFastSearch und clsFastSearchField müssen in die Zieldatenbank importiert werden.
  • Im Formular, dass das Textfeld zur Eingabe des Suchbegriffes enthält, wird eine Beim Laden-Ereignisprozedur angelegt, welche die Suche aktiviert und konfiguriert.
  • Das Klassenmodul des Hauptformulars enthält die folgende Deklaration:

Dim objFastsearch As clsFastSearch

  • Die zu durchsuchenden Felder können sich im gleichen Formular oder auch in einem Unterformular befinden.
  • Sie können eine Schaltfläche hinzufügen, die alle Suchfelder leert und den Filter zurücksetzt.

Ein Suchfeld filtert ein Feld, Variante I

Dieses Beispiel finden Sie im Formular frmEinSuchfeldEinErgebnisfeldOder. Die Eingabe von Text in das Textfeld txtSuche soll die im Endlosformular angezeigten Datensätze nach dem Artikelnamen filtern. Dazu fügen Sie die folgenden Prozedur für das Ereignis Beim Laden des Formulars hinzu:

Private Sub Form_Load()
    Set objFastsearch = New clsFastSearch
    With objFastsearch
        Set .Resultform = Me
        .AddSearchField Me!txtSuche
        .AddResultField "Artikelname"
    End With
End Sub

Die Prozedur erzeugt zunächst eine Instanz der Klasse clsFastSearch. Dann weist sie ihren Eigenschaften einige Werte zu:

  • Resultform erwartet einen Verweis auf das Formular, dass die zu filternden Datensätze anzeigt. Dies kann das gleiche Formular sein wie in diesem Fall oder auch ein Unterformular. In diesem Fall würde man einen Verweis wie Me!sfmSchnellsuche.Form übergeben.
  • AddSearchField fügt einen Verweis auf das Textfeld hinzu, in das der Suchbegriff eingegeben werden soll.
  • AddResultfield erwartet die Angabe des Feldnamens der zu filternden Datensätze, der in das Filterkriterium einbezogen werden soll.

Ein Suchfeld filtert ein Feld, Variante I

Bei der ersten Variante haben Sie den Verweis auf das Suchfeld sowie den Namen des zu durchsuchenden Feldnamen mit separaten Methoden übergeben. Sie können auch beide Werte mit der Methode AddSearchField übergeben. Dazu tragen Sie den Namen des zu durchsuchenden Feldes einfach als zweiten Parameter dieser Methode ein:

Private Sub Form_Load()
    Set objFastsearch = New clsFastSearch
    With objFastsearch
        Set .Resultform = Me
        .AddSearchField Me!txtSuche, "Artikelname"
    End With
End Sub

Dieses Beispiel finden Sie im Formular frmEinSuchfeldEinErgebnisfeldUnd.

Ein Suchfeld filtert mehrere Felder

Wenn Sie ein Suchfeld verwenden möchten, um damit mehrerer Felder zu filtern, können Sie dies mit der Konfiguration aus dem folgenden Listing erledigen:

Private Sub Form_Load()
    Set objFastsearch = New clsFastSearch
    With objFastsearch
        Set .Resultform = Me
        .AddSearchField Me!txtSuche
        .AddResultField "Artikelname"
        .AddResultField "Einzelpreis"
    End With
End Sub

Hier werden die ersten drei Eigenschaften wie in den vorherigen Beispielen eingestellt. Allerdings folgen dann gleich zwei Aufrufe der Methode AddResultField. Im Beispielformular frmEinSuchfeldMehrereErgebnisfelderOder können Sie so sowohl die ersten Buchstaben eines Artikels als auch die ersten Ziffern eines Preises eingeben.

Mehrere Suchfelder filtern je ein Feld

Schließlich fehlt noch die Möglichkeit, mehrere Suchfelder zu verwenden, wobei jedes Suchfeld genau ein Feld der Datenherkunft der zu filternden Daten durchsucht. Dieses Beispiel finden Sie im Formular frmEinSuchfeldMehrereErgebnisfelderOder. Der Code sieht wie folgt aus:

Private Sub Form_Load()
    Set objFastsearch = New clsFastSearch
    With objFastsearch
        Set .Resultform = Me
        .AddSearchField Me!txtSuche, "Artikelname"
        .AddSearchField Me!txtEinzelpreis, "Einzelpreis"
        Set .Clearbutton = Me!cmdZuruecksetzen
    End With
End Sub

Hier wurde zusätzlich noch eine Schaltfläche namens cmdZuruecksetzen hinzugefügt. Wenn Sie diese der Eigenschaft ClearButton hinzufügen, können Sie damit die bisherigen Eingaben in die Suchfelder löschen und den Filter zurücksetzen. Sie brauchen dazu keinen weiteren Code einzugeben. Das Formular sieht wie in Bild 5 aus.

pic005.png

Bild 5: Formular mit zwei Suchfeldern und einer Zurücksetzen-Schaltfläche

Suche im Unterformular

Wenn Sie die oben beschriebenen Lösungen in einer Kombination aus Haupt- und Unterformular einsetzen möchten, legen Sie für das Beim Laden-Ereignis des Hauptformular die folgende Prozedur an:

Private Sub Form_Load()
    Set objFastsearch = New clsFastSearch
    With objFastsearch
        Set .Resultform =
        Me!sfmBeispielUnterformular.Form
        .AddSearchField Me!txtSuche
        .AddResultField "Artikelname"
    End With
End Sub

Ein Beispiel hierfür finden Sie in den beiden Formularen frmBeispielUnterformular und sfmBeispielUnterformular.

Programmierung der Lösung

Nachdem Sie nun wissen, wie Sie die Lösung in eigene Anwendungen einbauen, möchten Sie vielleicht noch erfahren, wie diese im Detail funktioniert. Auf diese Weise können Sie gegebenenfalls eigene Anpassungen vornehmen. Für jedes Formular erstellen Sie eine Instanz der Klasse clsFastSearch. Jede Instanz dieser Klasse kann eine oder mehrere Instanzen der Klasse clsFastSearchField erzeugen, wobei diese die einzelnen Suchfelder repräsentieren.

Zu filterndes Formular festlegen

Der Instanz der Klasse clsFastSearch übergibt das aufrufende Formular zunächst einen Verweis auf das Formular, das die zu filternden Daten enthält. Diese werden in dieser Variablen gespeichert:

Dim m_Resultform As Form

Den Verweis auf das Formular nimmt die folgende Property Set-Methode entgegen und speichert ihn in der Variablen m_Resultform:

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