TreeView mit Kontextmenü

TreeViews sind sehr flexible Steuer-elemente, die sich vor allem zur Darstellung von Daten in hierarchischen Strukturen etabliert haben. Sie bieten viele verschiedene Möglichkeiten zur Visualisierung von Daten. Außerdem lassen sich die gängigen Ereignisse für die Elemente des TreeView-Steuerelements abbilden – zum Beispiel Mausklicks, Drag and Drop und so weiter. Leider bietet das TreeView-Steuerelement keine eingebaute Möglichkeit, wie bei den Standard-Steuerelementen Kontextmenüs anzuzeigen. Daher schauen wir uns in diesem Beitrag an, wie Sie ein TreeView-Steuerelement um Kontextmenü-Funktionen erweitern und welche Strategien dabei wichtig sind.

Aktionen zu TreeView-Einträgen

Ein TreeView, das Daten aus verknüpften Tabellen hierarchisch anzeigt, ist in vielen Szenarien sinnvoll: egal, ob Sie nun Kunden, Projekte und Aufgaben, Bauteile mit den einzelnen Elementen oder andere Daten abbilden. Sie können Elemente auf- und zuklappen, Elemente anklicken, um Details dazu in weiteren Steuerelementen anzuzeigen und vieles mehr.

Was aber noch fehlt, ist die Möglichkeit, Befehle für das aktuell angeklickte Element anzuzeigen. Wenn das TreeView-Steuerelement beispielsweise einen Kunden anzeigt, möchten Sie vielleicht verschiedene Aktionen für diesen Kunden ausführen – ein neues Projekt anlegen, den Kunden löschen oder eine Mail an diesen Kunden schicken.

Natürlich könnte man solche Befehle über Schaltflächen auslösen, die in einem Detailformular angezeigt werden, das nach einem Klick auf das Kundenelement im TreeView erscheint.

Die Lösung: Ein Kontextmenü

Es geht aber auch noch eleganter, und zwar mit einem Kontextmenü, das genau die zu dem angeklickten Element gehörenden Befehle anzeigt.

Ein Kontextmenü hat den Vorteil, dass es keinen Platz benötigt – Sie zeigen es an, indem Sie mit der rechten Maustaste auf das Element klicken, wählen die gewünschte Aktion aus und es verschwindet wieder. Im Detailformular würden die Befehle beziehungsweise die Schaltflächen Platz wegnehmen.

Der Nachteil von Kontextmenüs ist, dass der Benutzer erst einmal wissen muss, dass es diese gibt – immerhin gibt es in der Regel keinen Hinweis darauf, dass sich durch einen Rechtsklick auf ein Element weitere Optionen erschließen lassen.

Beispieldaten

Die Beispieldaten zu diesem Beitrag stammen aus den beiden Tabellen tblKunden und tblProjekte. Diese sind über das Fremdschlüsselfeld KundeID der Tabelle tblProjekte verknüpft (siehe Bild 1).

Datenquelle des TreeView-Steuerelements

Bild 1: Datenquelle des TreeView-Steuerelements

Die beiden Tabellen haben wir mit einigen Beispieldaten gefüllt – siehe Bild 2.

Daten der beiden Tabellen tblKunden und tblProjekte

Bild 2: Daten der beiden Tabellen tblKunden und tblProjekte

TreeView-Steuerelement

Das TreeView-Steuerelement fügen wir unter dem Namen ctlTreeView zu einem neuen Formular namens frmKundenProjekte hinzu (siehe Bild 3).

TreeView und ImageList in der Entwurfsansicht

Bild 3: TreeView und ImageList in der Entwurfsansicht

Hier erkennen Sie auch, dass wir bereits ein ImageList-Steuerelement hinzugefügt haben.

Dieses nennen wir ctlImageList und fügen ihm gleich noch zwei Icons hinzu, die wir mit den Werten user und folder für die Eigenschaft Key versehen (siehe Bild 4).

Bilder im ImageList-Steuerelement

Bild 4: Bilder im ImageList-Steuerelement

Formular vorbereiten

Da das Formular keine Daten anzeigen soll, stellen wir seine Eigenschaften Datensatzmarkierer, Navigationsschaltflächen und Bildlaufleisten auf den Wert Nein ein und Automatisch zentrieren auf Ja.

TreeView formatieren

Danach stellen wir bereits die notwendigen Eigenschaften für das TreeView-Steuerelement ein, was wir per VBA erledigen statt über den Eigenschaften-Dialog des Steuerelements.

Allein das ImageList-Steuerelement weisen wir über den Eigenschaften-Dialog zu, und zwar über den Wert ctl-ImageList für die Eigenschaft ImageList.

Im Klassenmodul des Formulars hinterlegen wir eine Objektvariable für das TreeView-Steuerelement:

Dim WithEvents objTreeView As MSComctlLib.TreeView

Dann implementieren wir die Ereignisprozedur, die durch das Ereignis Beim Laden des Formulars ausgelöst wird, und stellen darin die wichtigsten Eigenschaften des TreeView-Steuerelements ein:

Private Sub Form_Load()
     Set objTreeView = Me!ctlTreeView.Object
     With objTreeView
         .Appearance = ccFlat
         .BorderStyle = ccNone
         .LineStyle = tvwRootLines
         .Style = tvwTreelinesPlusMinusPictureText
     End With
     FillTreeView
End Sub

Dazu gehören die Eigenschaften Appearance (wir wollen keinen 3D-Effekt, daher stellen wir diese Eigenschaft auf den Wert ccFlat ein), BorderStyle, LineStyle und Style – diese Eigenschaft erhält den Wert tvwTreelinesPlusMinusPictureText, damit wir ein TreeView wie in Bild 5 erhalten.

Kunden und Projekte im TreeView

Bild 5: Kunden und Projekte im TreeView

Die letzte Anweisung der Prozedur ruft eine weitere Routine namens FillTreeView auf, die wie in Listing 1 aussieht. Diese Routine referenziert zunächst das Database-Objekt der aktuellen Datenbank und füllt dann ein Recordset-Objekt mit den Daten der Tabelle tblKunden – und zwar nach dem Feld Kunde sortiert.

Private Sub FillTreeView()
     Dim db As DAO.Database
     Dim rstKunden As DAO.Recordset
     Dim rstProjekte As DAO.Recordset
     Set db = CurrentDb
     Set rstKunden = db.OpenRecordset("SELECT * FROM tblKunden ORDER BY Kunde", dbOpenDynaset)
     Do While Not rstKunden.EOF
         objTreeView.Nodes.Add , , "k" & rstKunden!KundeID, rstKunden!Kunde, "user"
         Set rstProjekte = db.OpenRecordset("SELECT * FROM tblProjekte WHERE KundeID = " & rstKunden!KundeID, _
             dbOpenDynaset)
         Do While Not rstProjekte.EOF
             objTreeView.Nodes.Add "k" & rstKunden!KundeID, tvwChild, "p" & rstProjekte!ProjektID, _
                 rstProjekte!Projekt, "folder"
             rstProjekte.MoveNext
         Loop
         rstKunden.MoveNext
     Loop
End Sub

Listing 1: Diese Prozedur füllt das TreeView-Steuerelement

Die Datensätze dieses Recordsets durchläuft sie dann in einer Do While-Schleife. Innerhalb dieser Schleife erstellt sie zunächst jeweils ein Node-Element im TreeView-Steuerelement. Dabei weist sie mit der Add-Methode der Nodes-Auflistung ein Element in der ersten Ebene zu – deshalb bleiben die ersten beiden Parameter der Methode leer.

Der dritte Parameter gibt den Key an, also einen eindeutigen Identifizierer für das Node-Element im TreeView-Steuerelement. Für den Wert gibt es genau eine Voraussetzung: Er muss mit einem Buchstaben beginnen. Wir können also nicht einfach den Primärschlüsselwert des Kunden für die Eigenschaft Key angeben.

Das ist aber auch kein Problem, denn wenn wir das tun könnten, würden wir schnell doppelte Key-Werte produzieren, denn ein Primärschlüsselwert kann ja durchaus mehrfach in den Tabellen vorkommen, deren Daten im TreeView-Steuerelement angezeigt werden sollen.

Also fügen wir einfach einen Buchstaben voran, der die Art des Eintrags kennzeichnet – hier k für Kunde -, und fügen dahinter den Primärschlüsselwert ein. Für den Primärschlüsselwert 123 lautet der Key-Wert dann also k123.

Dahinter folgt der anzuzeigende Text, den wir aus dem Feld Kunde des Recordsets entnehmen (rstKunden!Kunde). Schließlich geben wir für den Parameter Image den Wert user an.

Dieser entspricht dem Icon aus dem ImageList-Steuer-element, das wir in Zusammenhang mit dem Kunden-Element anzeigen wollen.

Danach erstellt die Prozedur ein weiteres Recordset, dass diesmal alle Datensätze der Tabelle tblProjekte enthält, die über das Feld KundeID mit dem Kunden verknüpft sind, den wir gerade im Datensatz der übergeordneten Do While-Schleife bearbeiten.

Diese Projekt-Datensätze durchlaufen wir ebenfalls in einer Do While-Schleife. Innerhalb der Schleife legen wir für jedes Projekt ein neues Element unterhalb des jeweiligen Kunden-Elements an. Für diese Zuordnung nutzen wir die ersten beiden Parameter der Add-Methode der Nodes-Auflistung.

Der erste nimmt den Key-Wert des Node-Elements entgegen, unter dem wir das Projekt-Element anlegen wollen.

Der zweite legt fest, in welchem Verhältnis das neue Element zu dem mit dem ersten Parameter referenzierten Element stehen soll – in diesem Fall soll es untergeordnet werden, also verwenden wir den Wert tvwChild.

Der dritte, vierte und fünfte Parameter werden analog zum Aufruf der Add-Methode für die Kunden-Nodes gefüllt. Der wichtigste Unterschied ist, dass der Wert der Key-Eigenschaft mit p beginnt (für Projekt). Außerdem verwenden wir das Icon mit der Bezeichnung folder.

Auf diese Weise füllen wir mit der Prozedur schnell das TreeView mit allen Datensätzen der beiden Tabellen tblKunden und tblProjekte.

Kontextmenü anzeigen

Wenn es keine Eigenschaft gibt, mit der wir ein Kontextmenü zuweisen können und auch kein spezielles Ereignis vorliegt, das dies erledigen würde – wie zeigen wir das Kontextmenü dann an

Das erledigen wir über einen kleinen Umweg, nämlich über das Ereignis, dass durch das Herunterdrücken der rechten Maustaste ausgelöst wird. Auch dafür gibt es kein spezielles Ereignis, daher nutzen wir das Ereignis, das beim Herunterdrücken beliebiger Maustasten ausgelöst wird: nämlich Bei Maustaste ab. Bei ActiveX-Steuerelementen finden wir dieses Ereignis nicht im Eigenschaftsfenster, daher legen wir es direkt über den VBA-Editor an.

Dazu wählen Sie im linken Kombinationsfeld den Namen des Steuerelements aus, hier ctlTreeView, und dann im rechten Kombinationsfeld den Eintrag MouseDown.

Dies legt dann die Ereignisprozedur ctlTreeView_MouseDown an (siehe Bild 6).

Anlegen der Ereignisprozedur für das Ereignis Bei Maustaste ab

Bild 6: Anlegen der Ereignisprozedur für das Ereignis Bei Maustaste ab

Auf rechten Mausklick reagieren

Die Ereignisprozedur füllen wir wie in Listing 2. Sie nimmt unter anderem mit X und Y die aktuelle Position des Mauszeigers entgegen – diese werden wir gleich noch nutzen.

Private Sub ctlTreeView_MouseDown(ByVal Button As Integer, ByVal Shift As Integer, ByVal X As Long, ByVal Y As Long)
     Dim strTyp As String
     Dim lngID As Long
     Dim strText As String
     Dim objNode As MSComctlLib.Node
     Select Case Button
         Case acRightButton
             Set objNode = objTreeView.HitTest(X, Y)
             If Not objNode Is Nothing Then
                 strTyp = Left(objNode.Key, 1)
                 lngID = Mid(objNode.Key, 2)
                 strText = objNode.Text
                 Select Case strTyp
                     Case "k"
                         MsgBox "Rechtsklick auf Kunde '" & strText & "'"
                     Case "p"
                         MsgBox "Rechtsklick auf Projekt '" & strText & "'"
                 End Select
             Else
                 MsgBox "Rechtsklick auf leeren Bereich"
             End If
     End Select
End Sub

Listing 2: Diese Prozedur reagiert auf Klicks mit der rechten Maustaste.

Zunächst einmal ist zu beachten, dass das Ereignis Bei Maustaste ab bei jedem Mausklick ausgelöst wird – sowohl mit der linken und der rechten, aber auch mit der mittleren Taste. Welche Maustaste gedrückt wurde, werten wir in einer Select Case-Bedingung aus. Diese untersucht den Wert eines weiteren Parameters, nämlich Button.

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