Lies diesen Artikel und viele weitere mit einem kostenlosen, einwöchigen Testzugang.
Neulich fiel mir in einer Benutzerumgebung auf, dass ich dort im Listenfeld per Eingabe eines Zeichens direkt zu den Einträgen springen konnte, die mit diesem Zeichen beginnen. Das ist immer ein schöner Anlass, dies in Access nach zu programmieren. Dieser Beitrag liefert also eine Erweiterung für Listenfelder, mit der Sie dem Benutzer die Auswahl der enthaltenen Einträge noch leichter machen können.
Als Beispiel dient die Tabelle tblArtikel der Südsturm-Beispieldatenbank. Diese verwenden wir als Datensatzherkunft eines neuen Listenfeldes in einem Formular namens lstArtikel – und zwar über eine Abfrage, die nur die beiden Felder ArtikelID und Artikelname liefert. Dabei sortiert die Abfrage die Datensätze noch nach dem Artikelnamen (siehe Bild 1).
Bild 1: Abfrage als Datenherkunft des Listenfeldes
Mit dieser Abfrage statten wir dann das Listenfeld lstArtikel im Formular frmListenfeldSchnellsuche aus. Damit das Listenfeld nur die Spalte mit den Artikelnamen anzeigt und nicht den Primärschlüsselwert der Datensätze, stellen wir die Eigenschaft Spaltenanzahl auf 2 und Spaltenbreiten auf 0cm ein. Das Formular sieht dann im Entwurf wie in Bild 2 aus.
Bild 2: Entwurfsansicht des Beispielformulars
Funktion schon da …
Nun wollen wir eine Funktion zum Listenfeld hinzufügen, die dafür sorgt, dass die Eingabe eines Buchstabens direkt zum ersten Datensatz springt, der mit diesem Buchstaben anfängt.
Als ich dann allerdings testweise in die Formularansicht des Formulars wechselte und einen Buchstaben eingegeben habe, während das Listenfeld den Fokus hat, stellte ich erstaunt fest, dass diese Funktion bereits in das Listenfeld von Access integriert ist! Das Eintippen des Buchstabens C beispielsweise sorgte direkt zur Markierung des ersten Datensatzes, der mit dem Buchstaben C beginnt (siehe Bild 3).
Bild 3: Formular in Aktion
Das zeigt mal wieder, dass auch eine Anwendung wie Access, die praktisch seit 2010 überhaupt nicht mehr weiterentwickelt wurde, noch Funktionen offenbart, die man bis dahin noch nie genutzt hat, geschweige denn erkannt hat. Nun: Ich gehe davon aus, dass der eine oder andere diese Funktion bereits kennt – an mir ist diese bisher jedoch vorübergegangen.
Nun denn: So einfach lassen wir uns nicht abspeisen und bieten Varianten zum Standardverhalten des Listenfeldes bei Eingabe eines Buchstabens an. Das Standardverhalten sieht wie folgt aus:
Wenn Sie einen Buchstaben eingeben, zu dem das Listenfeld in der ersten Spalte einen Wert enthält, der mit diesem Buchstaben beginnt, wird dieser Datensatz markiert.
Geben Sie den gleichen Buchstaben nochmals ein, wird die Markierung zum nächsten Eintrag verschoben, dessen Wert in der ersten Spalte mit diesem Buchstaben beginnt. Ist nur ein passender Eintrag vorhanden, bleibt dieser markiert. Liegen mehrere Einträge vor, durchläuft das Listenfeld diese Einträge immer wieder, wenn der Benutzer die gleiche Taste mehrfach betätigt. Ist kein passender Eintrag vorhanden, bleibt der aktuelle Eintrag markiert.
Varianten
Die erste Variante, die wir uns ansehen wollen, entspricht dem Verhalten, das die Dateiliste im Windows Explorer bietet. Wenn die Dateiliste den Fokus hat und Sie geben einen Buchstaben ein, verhält sich die Liste wie das Listenfeld in Access, das heißt, dass der erste Eintrag markiert wird, dessen Dateiname mit dem angegebenen Anfangsbuchstaben beginnt.
Das funktioniert auch noch genauso wie im Listenfeld, wenn Sie beispielsweise drei Einträge haben, die mit p beginnen und mehrfach die Taste p drücken. Wenn Sie aber bei der Konstellation von Bild 4 erst p und dann direkt l drücken, springt die Markierung nicht erst zum Eintrag pic001 und dann zum ersten Eintrag, der mit l beginnt. Stattdessen tut sich nichts und die Markierung verharrt gefühlt eine Sekunde auf dem Eintrag mit dem Anfangsbuchstaben p. Der Grund ist einfach: Im Windows Explorer können Sie auch durch zügige Eingabe mehrerer aufeinanderfolgender Zeichen zu Einträgen springen, die mit diesen Zeichen beginnen.
Bild 4: Tastatureingabe im Windows Explorer
Wenn Sie also wie im Beispiel in der Abbildung pic003 eingeben, dann springt die Markierung erst zum ersten Eintrag mit p und dann weiter zum Eintrag pic003.png.
Der Explorer wartet also immer einige Augenblicke auf weitere schnell eingegebene Zeichen, bevor er davon ausgeht, dass nun doch ein anderer Eintrag angesteuert werden soll.
Diese Funktion wollen wir nun für das Listenfeld abbilden. Der erste Ansatz, den wir unternehmen, soll nur zum ersten Element mit dem Anfangsbuchstaben springen, den wir mit der Tastatur eingeben.
Dazu wollen wir es mit der FindFirst-Methode probieren, die wir in der Prozedur, die durch das Ereignis Bei Taste ab auslösen, wie folgt einsetzen:
Private Sub lstArtikel_KeyDown(KeyCode As Integer, Shift As Integer) Dim strSQL As String strSQL = "Artikelname LIKE ''''" & Chr(KeyCode) & "*''''" Debug.Print strSQL Me!lstArtikel.Recordset.FindFirst strSQL End Sub
Das Ergebnis ist allerdings ernüchternd, wie Bild 5 zeigt: Bei der Eingabe der Taste C beispielsweise springt die Markierung noch zum richtigen Datensatz, aber wenn wir diese Taste mehrfach betätigen, sieht das Resultat wie in der Abbildung aus.
Bild 5: Die FindFirst-Methode funktioniert für unseren Anwendungszweck funktioniert.
Darüber hinaus gibt es nach ein paar weiteren Tastatureingaben noch eine nicht reproduzierbare Fehlermeldung (siehe Bild 6).
Bild 6: Fehlermeldung nach mehrmaligem Auslösen der Prozedur
Listeneinträge durchlaufen
Also müssen wir uns einen anderen Ansatz überlegen. Dieser ist nur sinnvoll, wenn das Listenfeld nicht allzuviele Datensätze enthält, denn wir durchlaufen hier die Listeneinträge, bis wir den ersten passenden Eintrag gefunden haben.
Der erste Entwurf des Codes sieht wie in Listing 1 aus. In dieser Prozedur durchlaufen wir alle Datensätze vom ersten bis zu dem Datensatz, dessen erstes Zeichen in der Spalte mit dem Index 1, i mit dem eingetippten Zeichen übereinstimmt.
Private Sub lstArtikel_KeyDown(KeyCode As Integer, Shift As Integer) Dim i As Integer For i = 0 To Me!lstArtikel.ListCount - 1 Debug.Print i, Left(Me!lstArtikel.Column(1, i), 1), Me!lstArtikel.Column(1, i) If Left(Me!lstArtikel.Column(1, i), 1) = Chr(KeyCode) Then Me!lstArtikel.Selected(i) = True Exit For End If Next i End Sub
Listing 1: Versuch, den ersten passenden Eintrag zu finden und zu markieren
Wenn wir diesen Code ausprobieren und etwa den Buchstaben B eingeben, funktioniert es. Wenn wir allerdings einen Anfangsbuchstaben eingeben, für den es mehrere Artikelnamen gibt – wie beim Buchstaben C -, erhalten wir das Ergebnis aus Bild 7. Wir landen also immer genau einen Eintrag unter dem erwarteten Ergebnis.
Bild 7: Falsche Selektion
Warum das so ist, lässt sich nicht so einfach erklären.
Zu Analysezwecken haben wir per Debug.Print-Anweisung die jeweils durchlaufenen Werte für i, den ersten Buchstaben des Artikels und den kompletten Artikelnamen ausgeben lassen. Auch das lieferte keine Auffälligkeiten – wenn wir beispielsweise den Buchstaben C eingeben, erschien im Direktbereich die folgende Ausgabe:
0 A Alice Mutton 1 A Aniseed Syrup 2 B Boston Crab Meat 3 C Camembert Pierrot
Es wurde aber dennoch nicht der Eintrag Camembert Pierrot, sondern Carnarvon Tigers markiert – also genau ein Eintrag weiter unten. Wir gingen also davon aus, dass die Prozedur für Eintrag mit dem Index-Wert 3 die Eigenschaft Selected auf den Wert True einstellt. Den entsprechenden Befehl haben wir dann über den Direktbereich abgesetzt:
Forms(0)!lstArtikel.Selected(3) = true
Interessanterweise hat dies den richtigen Eintrag markiert (siehe Bild 8). Warum aber wird im Code der falsche Eintrag markiert Die Aufklärung erhofften wir uns über das Debuggen des Codes. Also haben wir einen Haltepunkt für den Prozedurkopf festgelegt, haben den Fokus auf das Listenfeld gelegt, den Buchstaben C eingetippt und dann den Code Zeile für Zeile durchlaufen.
Ende des frei verfügbaren Teil. Wenn Du mehr lesen möchtest, hole Dir ...
Testzugang
eine Woche kostenlosen Zugriff auf diesen und mehr als 1.000 weitere Artikel
diesen und alle anderen Artikel mit dem Jahresabo