ListView-Steuerelement mit VBA programmieren

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.

Umsortierte Spalten im ListView-Steuerelement

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.

Vollständige Zeile markieren

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).

Markierung im ListView-Steuerelement bei Fokusverlust beibehalten

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).

Eintrag im ListView-Steuerelement auslesen

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.

Weitere Spalten des markierten Eintrags auslesen

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:

Markieren von Einträgen im ListView-Steuerelement

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).

Ausgabe der Einträge einer Mehrfachauswahl

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.

Mehrfachauswahl per VBA selektieren

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).

Anlegen einer Ereignisprozedur für das ListView-Steuerelement

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).

Umbenennen eines Eintrags

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.

Ereignis vor dem Umbenennen

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).

Infos zum Element per Doppelklick

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

Schreibe einen Kommentar