Löschen im Listenfeld per Tastatur

Dieser Artikel ist Teil des Magazins 'Access im Unternehmen', Ausgabe 3/2018.

Löschen im Listenfeld per Tastatur

Wenn Sie Daten im Listenfeld anzeigen, die durch den Benutzer etwa per Doppelklick bearbeitet oder per Schaltfläche gelöscht oder erweitert werden sollen, lässt sich dies leicht erledigen. Eher selten trifft man auf Listenfelder, deren Einträge man einfach durch Markieren und Betätigen der Entf-Taste löschen kann. Wie Sie dies programmieren, schauen wir uns im vorliegenden Beitrag an.

Einfach Daten im Listenfeld markieren und mit der Entf-Taste löschen – das wäre in vielen Fällen eine praktische Erweiterung der sonst üblichen Löschen-Schaltfläche. Wenn man mehr als einen Datensatz aus der Liste löschen möchte, muss man sonst nämlich ordentlich mit der Maus arbeiten – markieren, auf Löschen klicken, markieren, auf Löschen klicken ...

Das können wir auch einfacher programmieren und dem Benutzer so die Anwendung vereinfachen.

Einträge aus ungebundenem Listenfeld löschen

Als Erstes schauen wir uns an, wie wir Einträge aus einem ungebundenen Listenfeld löschen können. Dieses legen wir unter dem Namen lstUngebunden in einem neuen Formular an. Das Formular soll beim Laden einige Einträge zum Listenfeld hinzufügen, was wir mit folgender Ereignisprozedur erledigen:

Private Sub Form_Load()
     Dim i As Integer
     Me!lstUngebunden.RowSourceType = "Value List"
     For i = 1 To 10
         Me!lstUngebunden.AddItem "Eintrag " & i
     Next i
End Sub

Die Prozedur stellt die Eigenschaft Herkunftsart des Listenfeldes auf Wertliste ein und fügt innerhalb einer For...Next-Schleife zehn durchnummerierte Einträge zum Listenfeld hinzu.

Dies liefert das Listenfeld mit den Einträgen aus Bild 1. Wenn wir nun einen der Einträge per Tastatur mit der Entf-Taste löschen wollen, müssen wir die Tastenereignisse des Listenfeldes hinzuziehen. In diesem Fall wollen wir den Eintrag löschen, sobald der Benutzer die Entf-Taste herunterdrückt. Dazu hinterlegen wir die Ereignisprozedur aus Listing 1 für das Ereignis Bei Taste ab des Listenfeldes.

Listenfeld mit Beispieldaten

Bild 1: Listenfeld mit Beispieldaten

Die Prozedur prüft, ob der Wert des Parameters KeyCode, der beim Herunterdrücken der Taste geliefert wird, der Zahl 46 entspricht. In diesem Fall ermittelt die Prozedur den Index des aktuell markierten Eintrags im Listenfeld und schreibt diesen in die Variable lngItem.

Diese Variable prüft die folgende If...Then-Bedingung auf den Wert -1. Ist der Wert nicht gleich -1, ruft die Prozedur die RemoveItem-Methode des Listenfeldes auf und übergibt mit lngItem den Index der zu löschenden Zeile. Damit wird der aktuell markierte Eintrag entfernt. Das Listenfeld behält den Fokus, aber danach ist kein Datensatz markiert (siehe Bild 2). Sollten wir die Markierung nach dem Löschen auf einen anderen Datensatz verschieben? Denkbar wäre, dass der Benutzer beispielsweise von oben nach unten einige Datensätze löschen möchte. Also markieren wir nach dem Löschen den Datensatz, der sich direkt unterhalb des gelöschten Datensatzes befunden hat.

Listenfeld nach dem Löschen eines Datensatzes

Bild 2: Listenfeld nach dem Löschen eines Datensatzes

Dazu haben wir hinter der Zeile mit der RemoveItem-Methode zunächst die folgende Zeile eingefügt:

Me!lstUngebunden.ListIndex = lngItem

Damit kann der Benutzer nun durch mehrmaliges Betätigen der Entf-Taste mehrere untereinander liegende Einträge hintereinander löschen, ohne zwischendurch einen neuen Datensatz markieren zu müssen. Soll ein Datensatz nicht gelöscht werden, kann der Benutzer den nächsten Datensatz mit den Nach oben- und Nach unten-Tasten ansteuern.

Allerdings war dies etwas zu kurz gedacht, denn die Prozedur lieferte einen Fehler, wenn wir den letzten vorhandenen Eintrag gelöscht haben – und auch das Löschen des letzten Eintrags der Liste lieferte regelmäßig einen Fehler.

Also haben wir noch ein paar verschachtelte Bedingungen hinzugefügt. Die erste fragt ab, ob das Listenfeld überhaupt noch Einträge enthält. Falls nicht, wird auch kein Eintrag mehr markiert. Falls doch, prüfen wir, ob lngItem, also der Index des gelöschten und des nun zu markierenden Datensatzes, der letzte Eintrag im Listenfeld ist. Falls nein, wird einfach der Eintrag mit dem Index des gelöschten Eintrags markiert, also der erste Eintrag hinter dem gelöschten Eintrag. Sollten wir uns schon an der letzten Position befinden, markiert die Prozedur den letzten Eintrag des Listenfeldes.

Auf diese Weise können wir auch den hinteren Eintrag markieren und von dort aus alle Einträge von hinten nach vorne löschen, ohne dass wir zwischendurch einen Eintrag von Hand markieren müssen.

Mehrfachauswahl löschen

Nun wollen wir uns ansehen, wie wir Einträge aus einem Listenfeld löschen können, für das die Mehrfachauswahl aktiviert ist. Dazu fügen wir dem Beispielformular ein weiteres Listenfeld namens lstUngebundenMehrfach hinzu, dessen Eigenschaft Mehrfachauswahl wir auf Einfach oder Erweitert einstellen. Damit auch dieses Listenfeld mit einigen Beispieleinträgen gefüllt wird, fügen wir der For...Next-Schleife der Prozedur Form_Load die folgende Zeile hinzu:

Me!lstUngebundenMehrfach.AddItem "Eintrag " & i

In diesem Fall können wir nicht nur einen, sondern mehrere Einträge markieren (siehe Bild 3). Wir fügen der Prozedur, die durch das Ereignis Bei Taste ab des Listenfeldes lstUngebundenMehrfach ausgelöst wird, die Zeilen aus Listing 2 hinzu.

Löschen einer Mehrfachauswahl

Bild 3: Löschen einer Mehrfachauswahl

Wenn wir dann die Einträge wie im Bild oben markieren und auf die Entf-Taste klicken, wird nur der erste Eintrag gelöscht. Warum das? Weil durch das Löschen des ersten Eintrags und damit der Aktualisierung des Listenfeldes auch die vorhandenen Markierungen entfernt werden.

Also müssen wir dies etwas anders angehen und die Indizes der zu löschenden Einträge erst in einem Array zwischenspeichern.

Die programmieren wir in der neuen Version der Prozedur, die Sie in Listing 3 finden. Hier verwenden wir gleich drei neue Variablen, nämlich i und l mit dem Datentyp Long und ein Array namens arrItems ebenfalls mit dem Datentyp Long. Wenn der Benutzer die Entf-Taste gedrückt hat, durchlaufen wir wie zuvor eine For Each-Schleife über alle markierten Elemente des Listenfeldes und redimensionieren das Array jeweils auf die Anzahl der erfolgten Durchläufe.

Private Sub lstUngebundenMehrfach_KeyDown(KeyCode As Integer, Shift As Integer)
     Dim varItem As Variant
     Dim arrItems() As Long
     Dim l As Long
     Dim i As Integer
     Select Case KeyCode
         Case 46
             For Each varItem In Me!lstUngebundenMehrfach.ItemsSelected
                 ReDim Preserve arrItems(i)
                 arrItems(i) = varItem
                 i = i + 1
             Next varItem
             For l = i - 1 To 0 Step -1
                 Me!lstUngebundenMehrfach.RemoveItem arrItems(l)
             Next l
     End Select
End Sub

Listing 3: Zweiter Versuch, Einträge aus der Mehrfachauswahl eines Listenfeldes zu löschen

Um diese zu zählen, erhöhen wir jeweils die Variable i um den Wert 1. Der Position des Arrays mit dem Indexwert aus i weisen wir dabei jeweils den Index beziehungsweise die Position des soeben bearbeiteten Listeneintrags zu – in diesem Beispiel erhalten also etwa die Zeilen 0, 1 und 2 des Arrays die Werte 0, 2 und 4. Nach dem Durchlaufen wissen wir über den Wert von i, wieviele Zeilen gelöscht werden sollen. In einer For...Next-Schleife mit der Schrittweite -1 durchlaufen wir dann die Werte von i-1 bis 0.

Warum rückwärts? Wenn wir vorwärts arbeiten, würden wir nicht die Einträge mit dem Index 0, 2 und 4 löschen, sondern die mit dem Index 0, 3 und 6. Warum? Wenn wir den Eintrag mit dem Index 0 löschen, rückt der Eintrag mit dem Index 2, den wir auch löschen wollen, auf den Index 1. Wir löschen dann den Eintrag, der zuvor den Index 3 hatte.

Beim Löschen aus Auflistungen also immer rückwärts in der Schleife arbeiten! In der Schleife entfernen wir dann die jeweiligen Einträge wieder mit der RemoveItem-Methode, wobei wir den Index diesmal dem Array arrItems entnehmen. Nach dem Durchlaufen der Schleife sind dann alle gewünschten Einträge entfernt.

Wir sparen uns es an dieser Stelle auch, wie im ersten Beispiel gleich den ersten Eintrag nach dem gelöschten Eintrag zu markieren.

Löschen aus gebundenen Listenfeldern

Nun schauen wir uns die beiden Beispiele von oben noch für gebundene Listenfelder an. Dazu erstellen wir eine kleine Beispieltabelle namens frmWerte mit den Feldern ID (Primärschlüsselfeld) und Wert (Textfeld).

Das Formular frmListenfeldGebunden ist genauso aufgebaut wie das vorherige Beispielformular.

Der Unterschied ist, dass wir die Eigenschaft Herkunftsart bei Tabelle/Abfrage belassen. Außerdem stellen wir die Eigenschaft Datensatzherkunft auf die folgende Abfrage ein (siehe Bild 4):

Einstellen der Datensatzherkunft der beiden Listenfelder

Bild 4: Einstellen der Datensatzherkunft der beiden Listenfelder

SELECT tblWerte.ID, tblWerte.Wert FROM tblWerte;

Damit die Listenfelder das erste Feld der Datenquelle als gebundene Spalte nutzen, die aber nicht angezeigt wird und nur das Feld Wert anzeigen, stellen wir die Eigenschaft Spaltenanzahl auf 2 und die Eigenschaft Spaltenbreiten auf 0cm ein.

Einzelne Einträge löschen

Die Prozedur zum Löschen einzelner Einträge aus dem gebundenen Listenfeld finden Sie in Listing 4. Sie prüft in der Select Case-Bedingung, ob der Benutzer die Taste mit dem KeyCode-Wert 46, also die Entf-Taste, gedrückt hat. In diesem Fall erstellt sie einen Verweis auf die aktuelle Datenbank und speichert diese in der Variablen db.

Private Sub lstGebunden_KeyDown(KeyCode As Integer, Shift As Integer)
     Dim db As DAO.Database
     Dim lngItem As Long
     Select Case KeyCode
         Case 46
             Set db = CurrentDb
             lngItem = Me!lstGebunden.ListIndex
             If Not lngItem = -1 Then
                 db.Execute "DELETE FROM tblWerte WHERE ID = " & Me!lstGebunden.ItemData(lngItem)
                 Me!lstGebunden.Requery
                 If Not Me!lstGebunden.ListCount = 0 Then
                     If lngItem < Me!lstGebunden.ListCount Then
                         Me!lstGebunden.ListIndex = lngItem
                     Else
                         Me!lstGebunden.ListIndex = Me!lstGebunden.ListCount - 1
                     End If
                 End If
             End If
     End Select
End Sub

Listing 4: Gebundenes Listenfeld: Einzelne Einträge löschen

Die Prozedur prüft dann, ob überhaupt ein Eintrag ausgewählt ist. Falls ja, löscht sie den Eintrag aus der Tabelle tblWerte, dessen Feld ID den Wert hat, den die Eigenschaft ItemData für den Eintrag mit dem Index aus lngItem liefert. lngItem ist der Index des markierten Eintrags, ItemData liefert den Wert der gebundenen Spalte für den Eintrag mit dem entsprechenden Index.

Nach dem Aktualisieren der Datensatzherkunft des Listenfeldes mit der Requery-Methode folgt das Markieren des nächsten Datensatzes – also das Markieren des folgenden Datensatzes, sofern einer vorhanden ist, oder das Markieren des vorherigen Datensatzes, wenn der Benutzer zuvor den letzten Datensatz in der Liste gelöscht hat. Dazu prüft die Prozedur, ob das Listenfeld überhaupt noch einen Eintrag anzeigt. Falls nicht, wird entsprechend kein Eintrag markiert.

Falls doch, prüft die Prozedur, ob der gelöschte Eintrag nicht der letzte Eintrag war. In diesem Fall stellt sie den Index auf den gleichen Index-Wert ein, den der zuvor gelöschte Eintrag besaß. Bleibt noch die Möglichkeit, dass der Benutzer den letzten Eintrag der Liste gelöscht hat. In diesem Fall soll der nun letzte Eintrag im Listenfeld markiert werden.

Löschen einer Mehrfachauswahl aus dem gebundenen Listenfeld

Damit kommen wir zum Löschen mehrerer Datensätze aus dem gebundenen Listenfeld. Hier ist die Eigenschaft Mehrfachauswahl des Listenfeldes lstGebundenMehrfach beispielsweise auf Erweitert eingestellt. Damit kann der Benutzer die Einträge wie etwa die Dateien im Windows Explorer auswählen.

Nach der Auswahl und dem Betätigen der Entf-Schaltfläche prüft die Prozedur, die durch das Ereignis Bei Taste ab ausgelöst wird und die wie in Listing 5 aussieht, wieder den Wert des Parameters KeyCode auf den Wert 46. In diesem Fall wird die Variable db über die Funktion CurrentDb mit einem Verweis auf die aktuelle Datenbank gefüllt. Dann durchläuft die Prozedur in einer For Each-Schleife alle markierten Einträge des Listenfeldes, auf die wir mit der Auflistung ItemsSelected zugreifen.

Private Sub lstGebundenMehrfach_KeyDown(KeyCode As Integer, Shift As Integer)
     Dim db As DAO.Database
     Dim varItem As Variant
     Dim arrItems() As Long
     Dim lngLoeschen As Long
     Dim l As Long
     Dim i As Integer
     Select Case KeyCode
         Case 46
             Set db = CurrentDb
             For Each varItem In Me!lstGebundenMehrfach.ItemsSelected
                 ReDim Preserve arrItems(i)
                 arrItems(i) = varItem
                 i = i + 1
             Next varItem
             For l = i - 1 To 0 Step -1
                 lngLoeschen = Me!lstGebundenMehrfach.ItemData(arrItems(l))
                 db.Execute "DELETE FROM tblWerte WHERE ID = " & lngLoeschen
             Next l
             Me!lstGebundenMehrfach.Requery
     End Select
End Sub

Listing 5: Löschen mehrerer Einträge im gebundenen Listenfeld

Die von dieser Auflistung gelieferten Index-Werte landen jeweils in der Variant-Variablen varItem. Wir erweitern das Array arrItems dann jeweils auf die Anzahl, die dem Wert der Zählervariablen i entspricht und fügen ihm den aktuell durchlaufenen Wert aus der Variablen varItem zu. Dann erhöhen wir i um 1 und bearbeiten den nächsten Eintrag der Auflistung.

Damit ausgestattet durchlaufen wir in einer For...Next-Schleife rückwärts alle Elemente des Arrays von i - 1 bis 0. In der Variablen lngLoeschen nehmen wir den Wert der gebundenen Spalte des Listenfeldes für den jeweils angegebenen Index-Wert aus dem Array arrItems auf, den wir mit der ItemData-Eigenschaft ermitteln. Diesen Wert nutzen wir dann als Vergleichswert für das Kriterium der DELETE-Aktionsabfrage, welche den aktuellen Datensatz aus der Tabelle tblWerte löscht. Schließlich aktualisieren wir nach dem Durchlaufen aller Elemente des Arrays die Datenherkunft des Listenfeldes mit der Requery-Methode.

Zusammenfassung und Ausblick

Das Löschen von Listenfeld-Einträgen erfolgt meist nach vorherigem Markieren der zu löschenden Daten und anschließendem Löschen mit einer dafür vorgesehenen Schaltfläche.

Dieser Beitrag zeigt einmal, wie Sie auch aus dem Listenfeld ganz einfach Datensätze durch Betätigen der Entf-Schaltfläche löschen können, und zwar für ungebundene und gebundene Listenfelder.

Bitte geben Sie die Zeichenfolge in das nachfolgende Textfeld ein

Die mit einem * markierten Felder sind Pflichtfelder.

Ich habe die Datenschutzbestimmungen zur Kenntnis genommen.