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.
Bild 1: Listenfeld mit BeispieldatenDie 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.
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.
Bild 3: Löschen einer MehrfachauswahlWenn 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):
Bild 4: Einstellen der Datensatzherkunft der beiden ListenfelderSELECT 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.