Im Beitrag „ListView-Steuerelement mit VBA programmieren“ (www.access-im-unternehmen.de/1573) haben wir gezeigt, wie wir mit dem ListView-Steuerelement arbeiten können. Dort haben wir bereits einige grundlegende VBA-Techniken gezeigt, mit denen wir das ListView-Steuerelement in den verschiedenen Ansichten mit Daten gefüllt haben. Im vorliegenden Beitrag geht es nun weiter: Wir zeigen, wie wir das Steuerelement per VBA programmieren können. Dabei liegt der Fokus auf den Methoden, mit denen wir auf Benutzereingaben reagieren oder verschiedene Informationen auslesen – zum Beispiel das aktuell markierte Element. Auch auf Mehrfachauswahl gehen wir ein, die wir sowohl setzen als auch auslesen werden. Und natürlich wird auch Drag and Drop eine Rolle in diesem Beitrag spielen.
Ereignisse des ListView-Steuerelements
Das ListView-Steuerelement bietet einige Ereignisse an, die wir uns in den folgenden Abschnitten genauer ansehen. Hier zunächst eine Übersicht mit den Funktionen der Ereignisse:
- AfterLabelEdit: Wird ausgelöst, nachdem der Benutzer die Bearbeitung einer Beschriftung beendet hat. Dient zur Prüfung oder Speicherung des geänderten Textes.
- BeforeLabelEdit: Tritt auf, bevor ein Benutzer die Beschriftung bearbeiten darf. Ermöglicht das Zulassen oder Verhindern des Editierens, wenn der Benutzer ein Element zu Bearbeiten anklicken will.
- Click: Wird ausgelöst, wenn der Benutzer auf das Steuerelement klickt (einfacher Klick, unabhängig vom ausgewählten Element).
- ColumnClick: Wird ausgelöst, wenn der Benutzer auf eine Spaltenüberschrift klickt. Wird häufig genutzt, um die Sortierung nach Spalten zu steuern.
- DblClick: Wird ausgelöst, wenn der Benutzer auf ein Element doppelklickt. Dient oft zum Öffnen oder Bearbeiten des gewählten Eintrags.
- ItemCheck: Tritt auf, wenn ein Kontrollkästchen neben einem ListItem aktiviert oder deaktiviert wird. Nur relevant, wenn Checkboxes = True gesetzt ist.
- ItemClick: Wird ausgelöst, wenn der Benutzer auf ein bestimmtes ListItem-Element klickt. Liefert direkten Zugriff auf das betroffene Element.
- KeyDown: Wird ausgelöst, wenn eine Taste gedrückt wird. Liefert Informationen über Tastencode und Status von Umschalt-, Strg– oder Alt-Tasten.
- KeyPress: Wird ausgelöst, wenn ein druckbares Zeichen eingegeben wird. Dient häufig zur Filterung von Eingaben.
- KeyUp: Wird ausgelöst, wenn eine Taste losgelassen wird. Kann genutzt werden, um Tastenkombinationen auszuwerten.
- MouseDown: Wird ausgelöst, wenn eine Maustaste gedrückt wird. Liefert Informationen über Maustaste, Position und Status der Umschalttasten.
- MouseMove: Wird ausgelöst, wenn der Mauszeiger über das Steuerelement bewegt wird. Nützlich für eigene Hover-Effekte.
- MouseUp: Wird ausgelöst, wenn eine zuvor gedrückte Maustaste losgelassen wird.
- OLECompleteDrag: Wird ausgelöst, nachdem eine Drag and Drop-Operation abgeschlossen wurde. Dient zum Bereinigen oder Aktualisieren des Zustands.
- OLEDragDrop: Wird ausgelöst, wenn ein Objekt über dem Steuerelement abgelegt wird. Hier wird üblicherweise der Drop-Inhalt verarbeitet.
- OLEDragOver: Wird fortlaufend ausgelöst, während ein Objekt über dem Steuerelement bewegt wird. Eignet sich zur Anzeige von Drop-Zielen.
- OLEGiveFeedback: Wird während einer Drag and Drop-Operation ausgelöst. Ermöglicht die Anpassung des Mauszeigers oder Feedback-Verhaltens.
- OLESetData: Wird ausgelöst, wenn das Steuerelement Daten bereitstellen soll, die per Drag and Drop übergeben werden.
- OLEStartDrag: Wird ausgelöst, wenn der Benutzer eine Drag and Drop-Operation startet. Hier werden üblicherweise die zu übertragenden Daten festgelegt.
- Updated: wird in VBA nicht ausgelöst
Spaltenköpfe und Einträge vor dem erneuten Füllen leeren
Manchmal werden die angelegten Einträge für die Spaltenköpfe und die Zeilen des ListView-Steuerelements beim Schließen gespeichert, sodass ein erneutes Öffnen und der Versuch, die Elemente erneut anzulegen, zu einem Fehler führt.
Daher sollte man diese Elemente vorsichtshalber immer löschen, bevor man das ListView-Steuerelement erneut füllt:
objListView.ColumnHeaders.Clear objListView.ListItems.Clear
Spalten anordnen
Damit der Benutzer die Spalten eines ListView-Steuerelements anordnen kann, müssen wir die Eigenschaft AllowColumnReorder auf True einstellen:
objListView.AllowColumnReorder = True
Danach kann der Benutzer die Spalten wie in Bild 1 umsortieren.

Bild 1: Umsortierte Spalten im ListView-Steuerelement
Leider gibt es kein Ereignis, dass durch das Umsortieren ausgelöst wird, sodass wir die Anordnung nicht ohne größeren Aufwand speichern und beim nächsten Öffnen des Formulars wiederherstellen können (siehe Formular frmListView_SpaltenAnordnen der Beispieldatenbank).
Selektierte Spalten vollständig markieren
Vom Listenfeld von Access sind wir gewohnt, dass markierte Einträge vollständig markiert werden. Im ListView-Steuerelement wird standardmäßig nur die erste Spalte des ausgewählten Eintrags markiert. Dies können wir ändern, indem wir die Eigenschaft FullRowSelect auf True einstellen:
objListView.FullRowSelect = True
Markieren wir nun eine Zeile, werden alle Spalten markiert (siehe Bild 2) – siehe frmListView_EintragMarkieren.

Bild 2: Vollständige Zeile markieren
Markierung bei Fokusverlust beibehalten
Standardmäßig ist die Markierung des aktuellen Eintrags nicht mehr sichtbar, wenn das ListView-Steuerelement den Fokus verliert.
Dem können wir zumindest teilweise entgegenwirken, indem wir die Eigenschaft HideSelection auf False einstellen:
objListView.HideSelection = False
Die aktuelle Zeile wird nun immerhin noch grau hinterlegt (siehe Bild 3).

Bild 3: Markierung im ListView-Steuerelement bei Fokusverlust beibehalten
Objektvariable modulweit deklarieren
In den folgenden Beispielen wollen wir aus anderen Prozeduren heraus auf das ListView-Steuerelement zugreifen. Dazu könnten wir dieses immer wieder neu deklarieren und referenzieren, aber diesen Aufwand wollen wir uns sparen. Also deklarieren wir objListView wie folgt im Kopf der Prozedur:
Dim objListView As MSComctlLib.ListView
Dann reicht es, wenn wir diese Variable einmal in der Ereignisprozedur Beim Laden füllen:
Set objListView = Me.ctlListView.Object
In den weiteren Prozeduren können wir anschließend einfach auf objListView zugreifen.
Markierten Eintrag auslesen
Im Formular frmListView_Auslesen zeigen wir, wie der aktuell markierte Listeneintrag ausgelesen werden kann. Dabei greifen wir auf den Key und den Text der ersten Spalte zu und geben diese Informationen in einem Meldungsfenster aus (siehe Bild 4).

Bild 4: Eintrag im ListView-Steuerelement auslesen
Für die Schaltfläche cmdAktuellenEintragAuslesen hinterlegen wir den folgenden Code:
Private Sub cmdAktuellenEintragAuslesen_Click() Dim objListItem As MSComctlLib.ListItem Set objListItem = objListView.SelectedItem If Not objListItem Is Nothing Then MsgBox "Es wurde der Eintrag mit dem Key ''" _ & objListItem.Key & "'' und dem Text ''" _ & objListItem.Text & "'' ausgewählt." End If End Sub
Hier lesen wir mit der Eigenschaft SelectedItem den aktuellen Eintrag aus. Ist das Ergebnis nicht Nothing, können wir über die Eigenschaften Key und Text von objListItem auf die entsprechenden Werte zugreifen.
Werte weiterer Spalten auslesen
Gegebenenfalls sind auch noch die übrigen Spalten des aktuell markierten Eintrags interessant. Diese wollen wir ein einer Meldung wie in Bild 5 ausgeben.

Bild 5: Weitere Spalten des markierten Eintrags auslesen
Dazu fügen wir für die zweite Schaltfläche diese Prozedur hinzu:
Private Sub cmdWeitereSpaltenAuslesen_Click() ... Dim objListSubItem As MSComctlLib.ListSubItem Dim strSubItems As String Set objListItem = objListView.SelectedItem If Not objListItem Is Nothing Then For Each objListSubItem In objListItem.ListSubItems With objListSubItem strSubItems = strSubItems & vbCrLf _ & .Index & " " & .Key & " " & .Text End With Next objListSubItem End If MsgBox "Weitere Spalten: " & strSubItems End Sub
Die Prozedur deklariert zusätzlich eine Variable des Typs ListSubItem. Nachdem wir mit objListItem den aktuellen Eintrag markiert haben, durchlaufen wir in einer For Each-Schleife alle Elemente der Auflistung ListSubItems. Für diese stellen wir jeweils eine Zeile mit dem Index, dem Key und dem Text in der Variablen strSubItems zusammen.
Einen Eintrag markieren
Wir wollen nicht nur den aktuellen Eintrag auslesen, sondern diesen auch einstellen können. Dazu haben wir das Formular frmListView_EintragSelektieren angelegt. Hier finden wir drei Schaltflächen. Die erste Schaltfläche löst die folgende Prozedur aus und selektiert damit den zweiten Eintrag durch Angabe des Index-Wertes dieses Eintrags beim Zuweisen des Wertes True an die Eigenschaft Selected:
Private Sub cmdZweitenEintragPerIndex_Click() objListView.ListItems(2).Selected = True Me.ctlListView.SetFocus End Sub
Wir können auch einen Eintrag über den Key-Wert selektieren. Das erledigen wir mit der zweiten Schaltfläche:
Private Sub cmdDrittenEintragPerKey_Click() objListView.ListItems("a31").Selected = True Me.ctlListView.SetFocus End Sub
Schließlich wollen wir auch noch die Selektion leeren können.
Die folgende Prozedur ermittelt den markierten Eintrag und wählt diesen ab:
Private Sub cmdAlleEintraegeAbwaehlen_Click() Dim objListItem As MSComctlLib.ListItem Set objListItem = objListView.SelectedItem objListItem.Selected = False End Sub
Mehrfachauswahl im ListView-Steuerelement
Im Formular frmListView_Mehrfachauswahl_Auslesen setzen wir uns mit der Mehrfachauswahl im ListView-Steuerelement auseinander (siehe Bild 6). Dazu stellen wir zunächst die Eigenschaft auf True ein:

Bild 6: Markieren von Einträgen im ListView-Steuerelement
objListView.MultiSelect = True
Damit können wir nun wie in bei gedrückter Umschalt– oder Strg-Taste wie im Windows Explorer mehrere Einträge gleichzeitig markieren.
Private Sub cmdAktuelleEintraegeAuslesen_Click() Dim objListItem As MSComctlLib.ListItem Dim strSelected As String For Each objListItem In objListView.ListItems If objListItem.Selected Then strSelected = strSelected & vbCrLf _ & objListItem.Key & " " & objListItem.Text End If Next objListItem MsgBox "Markierte Einträge:" & strSelected End Sub
Die Prozedur durchläuft alle Einträge des Listenfeldes. Darin prüft sie mit der Selected-Eigenschaft, ob der jeweilige Eintrag markiert ist.
Wenn wir anschließend die Schaltfläche betätigen, erhalten wir eine Liste der markierten Einträge (siehe Bild 7).

Bild 7: Ausgabe der Einträge einer Mehrfachauswahl
Mehrere Einträge im ListView per VBA selektieren
Nun wollen wir mehrere Einträge in einer Mehrfachauswahl per VBA selektieren (siehe frmListView_MehrereEintraegeSelektieren). Im Beispiel wollen wir mit einer Schaltfläche den ersten und den dritten Eintrag selektieren.
Die Schaltfläche löst die folgende Prozedur aus:
Private Sub cmdMehrereEintraegeSelektieren_Click() Dim objListItem As MSComctlLib.ListItem Set objListItem = objListView.ListItems(1) objListItem.Selected = True Set objListItem = objListView.ListItems(3) objListItem.Selected = True Me.ctlListView.SetFocus End Sub
Hier selektieren wir zuerst den ersten Eintrag und markieren diesen und führen die gleichen Schritte dann für den dritten Eintrag aus. Das Ergebnis sehen wir in Bild 8.

Bild 8: Mehrfachauswahl per VBA selektieren
Die zweite Schaltfläche wählt alle Einträge wieder ab.
Sie durchläuft alle Einträge und stellt für den Wert der Eigenschaft Selected jeweils auf False ein:
Private Sub cmdAlleEintraegeAbwaehlen_Click() Dim objListItem As MSComctlLib.ListItem For Each objListItem In objListView.ListItems objListItem.Selected = False Next objListItem End Sub
Sortieren der Einträge
Wie können die Einträge des Listenfeldes jeweils nach einer Spalte aufsteigend oder absteigend sortieren (siehe Formular frmListView_Sortieren). Dazu benötigen wir eine Prozedur, die durch das Ereignis ColumnClick des ListView-Steuerelements ausgelöst wird.
Diese Ereignisprozedur legen wir an, indem wir im Codefenster für das Klassenmodul des Formulars aus der linken Liste den Eintrag für das ListView-Steuerelement auswählen und aus der rechten den Eintrag ColumnClick (siehe Bild 9).

Bild 9: Anlegen einer Ereignisprozedur für das ListView-Steuerelement
Die so erstellte Ereignisprozedur lvwListView_ColumnClick füllen wir wie folgt:
Private Sub ctlListView_ColumnClick(ByVal ColumnHeader _ As Object) Static intAktuelleSortierspalte As Integer Static bolAufsteigend As Boolean objListView.SortKey = ColumnHeader.Index - 1 If intAktuelleSortierspalte = ColumnHeader.Index - 1 Then bolAufsteigend = Not bolAufsteigend objListView.SortOrder = Abs(bolAufsteigend) Else objListView.SortOrder = lvwAscending End If objListView.Sorted = True intAktuelleSortierspalte = ColumnHeader.Index - 1 End Sub
Sie enthält zwei als statisch deklarierte Variablen. Das heißt, dass diese Variablen auch nach dem Verlassen der Prozedur ihre Werte behalten, aber außerhalb der Prozedur dennoch nicht zugreifbar sind. Die Prozedur liest bekommt mit dem Parameter Columnheader einen Verweis auf den Spaltenkopf, den der Benutzer angeklickt hat.
Aus diesem lesen wir den aktuellen Sortierindex aus. Diesen ermitteln wir aus ColumnHeader.Index – 1 und weisen diesen der Eigenschaft SortKey des ListView-Steuerelements zu. Damit legen wir fest, welche Spalte sortiert werden soll.
Danach prüfen wir, ob intAktuelleSortierspalte den gleichen Wert wie ColumnHeader.Index – 1 hat. In diesem Fall kehren wir den Wert der Variablen bolAufsteigend, der standardmäßig 0 ist, um und weisen den Wert ohne Vorzeichen der Eigenschaft SortOrder zu.
Der Wert 0 entspricht der Konstanten lvwAscending (aufsteigend), der Wert 1 der Konstanten lvwDescending (absteigend).
Falls intAktuelleSortierspalte nicht der markierten Spalte entspricht, soll die Sortierreihenfolge auf lvwAscending (aufsteigend) eingestellt werden. Das ist immer der Fall, wenn nicht die gleiche Spalte wie zuvor angeklickt wurde.
Durch das Einstellen der Eigenschaft Sorted auf den Wert True wird die Sortierung angewendet.
Schließlich stellt die Prozedur die Variable intAktuelleSortierspalte auf den aktuellen Index minus 1 ein. Damit stellen wir sicher, dass wir, wenn der Benutzer erneut auf den gleichen Spaltenkopf klickt, diese Spalte nun andersherum sortieren.
Wert der ersten Spalte ändern
Wir können zwar im ListView-Steuerelement nicht direkt Daten bearbeiten, wie es im Datenblatt der Fall ist. Aber wir können immerhin den Wert der ersten Spalte anpassen.
Dies müssen wir wie in allerdings zunächst aktivieren, indem wir die Eigenschaft LabelEdit auf den Wert lvwAutomatic einstellen:
objListView.LabelEdit = lvwAutomatic
Standardmäßig steht dieser Wert auf lvwManual. Sobald wir diesen geändert haben, können wir den Wert der ersten Spalte anklicken und dieser wird wie im Windows Explorer zum Ändern markiert (siehe Bild 10).

Bild 10: Umbenennen eines Eintrags
Auf Änderungen reagieren
Wenn man im ListView-Steuerelement reale Daten anzeigt und den Benutzer diese ändern lässt, werden die Änderungen nicht automatisch in die Datenherkunft übernommen. Wir verwenden in diesem Beispiel zwar nur einige Beispieldaten, aber wir stellen dennoch die Vorgehensweise vor, um auf Änderungen zu reagieren und den neuen Wert zu ermitteln.
Wir haben gleich zwei Ereignisse, die durch das Ändern eines Eintrags ausgelöst werden. BeforeLabelEdit wird bereits beim Anklicken des jeweiligen Eintrags zum Ändern ausgelöst, aber bevor dieser zum Ändern freigegeben wird. Wir können hier beispielsweise prüfen, ob der aktuelle Eintrag geändert werden darf. Falls nicht, können wir in der Prozedur eine Meldung ausgeben und brechen den Änderungsvorgang durch Setzen des Parameters Cancel auf den Wert True ab.
Interessanter ist die zweite Ereignisprozedur AfterLabelEdit. Diese wird ausgelöst, wenn der Benutzer die Änderung eingetragen hat und beispielsweise mit der Eingabetaste abschließt. Diese Prozedur liefert nicht nur den Parameter Cancel, mit dem wir den Änderungsvorgang abbrechen können, wenn der eingegebene Wert beispielsweise nicht validiert werden kann, sondern auch noch den Parameter NewString, der den neu eingetragenen Wert zurückliefert.
Wir fügen die Prozedur ctlListView_AfterLabelEdit über die beiden Auswahlfelder des Codefensters hinzu und füllen sie wie in Listing 1. Die Prozedur deklariert eine Variable namens objListItem, in die wir mit der Eigenschaft SelectedItem den aktuell markierten Eintrag beim Durchführen der Änderung eintragen. Aus diesem Eintrag lesen wir den Key und den Text aus und speichern beide in den Variablen strKey und strOldString.
Private Sub ctlListView_AfterLabelEdit(Cancel As Integer, NewString As String) Dim objListItem As MSComctlLib.ListItem Dim strKey As String Dim strOldString As String Set objListItem = objListView.SelectedItem strKey = objListItem.Key strOldString = objListItem.Text MsgBox "Der Eintrag mit dem Key ''" & strKey & "'' soll geändert werden von ''" & strOldString & "'' auf ''" & NewString & "''." End Sub
Listing 1: Reagieren auf die Änderung eines ListView-Eintrags
Danach geben wir diese Informationen in einer Meldung wie in Bild 11 aus.

Bild 11: Ereignis vor dem Umbenennen
Auf Doppelklick reagieren
Der einfache Klick selektiert einen Eintrag, daher macht es wenig Sinn, hier noch weitere Funktionen zu hinterlegen. Wenn wir zum Beispiel Details zu einem Datensatz im ListView-Steuerelement anzeigen wollen, können wir das beispielsweise per Doppelklick machen (siehe frmListView_AktionPerDoppelklick).
Dazu nutzen wir das Ereignis DblClick, das wir über das Codefenster anlegen und wie folgt füllen:
Private Sub ctlListView_DblClick() Dim objListItem As MSComctlLib.ListItem Dim lngIndex As Long Dim strKey As String Dim strText As String Set objListItem = objListView.SelectedItem If Not objListItem Is Nothing Then With objListItem lngIndex = .Index strKey = .Key strText = .Text End With MsgBox "Doppelklick auf den Eintrag mit dem " _ & "Index ''" & lngIndex & "'', dem Key ''" _ & strKey & "'' und dem Text ''" & strText & "''." End If End Sub
Hier referenzieren wir das aktuelle Element mit der Variablen objListItem. Ist diese nicht leer, lesen wir die Eigenschaften Index, Key und Text ein und geben diese in einem Meldungsfenster aus (siehe Bild 12).

Bild 12: Infos zum Element per Doppelklick
Auf einen Klick auf ein Element reagieren
Es gibt aber noch eine zweite Möglichkeit, eine Aktion mit einem Element auszuführen – das ItemClick-Ereignis. Dieses liefert direkt einen Verweis auf das angeklickte Element. Damit können wir beispielsweise die Details zu dem angeklickten Eintrag in einem Unterformular im gleichen Formular anzeigen. Im folgenden Beispiel zeigen wir, wie wir nach einem Klick die Eigenschaften des angeklickten Elements ausgeben (siehe frmListView_EintragPerKlick).
Im Gegensatz zu den Ereignissen Click oder DblClick liefert das ItemClick-Ereignis direkt das angeklickte Element per Parameter mit. Wir brauchen also nur noch seine Eigenschaften auszulesen und weiterzuverarbeiten – zum Beispiel um diese per Meldungsfenster auszugeben:
Private Sub ctlListView_ItemClick(ByVal Item As Object) Dim lngIndex As Long Dim strKey As String Dim strText As String With Item lngIndex = .Index strKey = .Key strText = .Text End With MsgBox "ItemClick auf den Eintrag mit dem Index ''" _ & lngIndex & "'', dem Key ''" & strKey _ & "'' und dem Text ''" & strText & "''." End Sub
Mit Kontrollkästchen im ListView arbeiten
Wenn wir die Eigenschaft Checkboxes des ListView-Steuerelements auf True eingestellt ist, wird vor jedem Eintrag ein Kontrollkästchen angezeigt:
objListView.Checkboxes = True
Damit wir das Aktivieren oder Deaktivieren des Kontrollkästchens per VBA verarbeiten können, gibt es das Ereignis ItemCheck. Dieses füllen wir wie folgt:
Private Sub ctlListView_ItemCheck(ByVal Item As Object) If Item.Checked = True Then MsgBox "Eintrag ''" & Item.Text _ & "'' wurde ausgewählt." Else MsgBox "Eintrag ''" & Item.Text _ & "'' wurde abgewählt." End If End Sub
Wenn wir nun eines der Kontrollkästchen wie in Bild 13 anklicken, erhalten wie die Meldung mit dem Element und ob dieses ausgewählt oder abgewählt wurde.
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
