ABOUT Visual Basic Programmieren Programmierung Download Downloads Tips & Tricks Tipps & Tricks Know-How Praxis VB VBA Visual Basic for Applications VBS VBScript Scripting Windows ActiveX COM OLE API ComputerPC Microsoft Office Microsoft Office 97 Office 2000 Access Word Winword Excel Outlook Addins ASP Active Server Pages COMAddIns ActiveX-Controls OCX UserControl UserDocument Komponenten DLL EXE
Diese Seite wurde zuletzt aktualisiert am 31.05.2001

Diese Seite wurde zuletzt aktualisiert am 31.05.2001
Aktuell im ABOUT Visual Basic-MagazinGrundlagenwissen und TechnologienKnow How, Tipps und Tricks rund um Visual BasicAddIns für die Visual Basic-IDE und die VBA-IDEVBA-Programmierung in MS-Office und anderen AnwendungenScripting-Praxis für den Windows Scripting Host und das Scripting-ControlTools, Komponenten und Dienstleistungen des MarktesRessourcen für Programmierer (Bücher, Job-Börse)Dies&Das...

Themen und Stichwörter im ABOUT Visual Basic-Magazin
Code, Beispiele, Komponenten, Tools im Überblick, Shareware, Freeware
Ihre Service-Seite, Termine, Job-Börse
Melden Sie sich an, um in den vollen Genuss des ABOUT Visual Basic-Magazins zu kommen!
Informationen zur AVB-Web-Site, Kontakt und Impressum

Zurück...

Wahlklasse

Zurück...

(-hg) mailto:hg_tvwmultiselect@aboutvb.de

Das TreeView-Steuerelement aus den Microsoft Common Controls bietet von Hause aus keine Möglichkeit der Mehrfachauswahl von Knoten an - wenn Sie von den ab Version 6 möglichen Anzeige von CheckBoxen zu jedem Knoten absehen. Eine Mehrfachauswahl ist eher in dem Sinne gemeint, dass der Anwender vorübergehend mehrere Knoten nacheinander markieren kann, etwa für Drag&Drop-Operationen oder Mehrfachbearbeitungen und ähnlichem. Die CheckBoxen hingegen repräsentieren eher eine dauerhafte Auswahl von Optionen.

Mehrfachauswahl in einem TreeView-Steuerelement möglich gemacht

Mehrfachauswahl in einem TreeView-Steuerelement möglich gemacht

Wie üblich sollten die Markierungen in der Art und Weise dargestellt werden, wie sie es auch im ListView-Steuerelement oder in einer einfachen ListBox werde - nämlich durch Darstellung eines markierten Elements in den im System eingestellten Standard-Hintergrund- und -Vordergrundfarben für Markierungen. Allerdings steht die Möglichkeit der Farbänderungen eines Knotens erst ab Version 6 der Microsoft Common Controls zur Verfügung.

Das Markieren selbst sollte dabei ähnlich dem Markieren bzw. Aufheben einer Markierung im ListView oder in einer ListBox (erweiterte Mehrfachauswahl) erfolgen: durch Anklicken bei gleichzeitig gedrückter Strg-Taste. Eine Mehrfachauswahl über einen Bereich von einem Startelement bis zum aktuell angeklickten Element, wie sie ansonsten bei gleichzeitig gedrückter Umschalt-Taste erfolgen würde, macht bei einem TreeView-Steuerelement wegen der Verzweigungen der Knoten nur wenig Sinn.

Dagegen ist vielleicht das Markieren bzw. Freigeben eines Knoten samt des ganzen Astes unterhalb dieses Knotens interessant (Umschalt- und Strg-Taste gleichzeitig beim Anklicken gedrückt). Die Markierung per Tastatur bzw. die Aufhebung einer Markierung erfolgt über die Leertaste (wie bei einer ListBox mit einfacher Mehrfachauswahl), die Markierung bzw. Freigabe eines Knotens samt des ganzen Astes darunter mit Umschalt-Leertaste. Die komplette Aufhebung einer Mehrfachauswahl erfolgt durch einen Klick in den freien Raum außerhalb einer Knoten-Beschriftung oder per Tastatur über die Kombination Umschalt-Escape-Taste. An weiteren Tastenkombinationen stehen zur Verfügung: Strg-A markiert den gesamten Inhalt, während Strg-T alle Markierungen umkehrt.

Das alles haben wir in die Klasse TreeViewMultiSelect verpackt. Sie brauchen sie nur für jeweils jedes TreeView-Steuerelement, das Sie mit der Fähigkeit der Mehrfachauswahl versehen wollen, einmal zu instanzieren. Das betreffende TreeView-Steuerelement übergeben Sie dann als Parameter eines Aufrufs der Init-Methode.

Auf die normale Selected-Eigenschaft eines Knotens bzw. auf die SelectedItem-Eigenschaft des TreeViews sollten Sie nicht mehr zugreifen. Die Klasse selbst repräsentiert die aktuelle Auswahl, die Sie in einer For...Each-Schleife durchlaufen können. Auf die einzelnen Elemente der Auswahl greifen Sie über die Eigenschaft SelectedNode mit einer nummerischen Indexangabe als Parameter zu. Den Knoten, der die Fokus-Markierung (dies ist der gepunktete Rahmen um einen Knoten) trägt, repräsentiert die Eigenschaft FocusNode. Sie entspricht weitestgehend der ursprünglichen Eigenschaft SelectedItem. Das setzen dieses Fokus-Knotens erledigen Sie über die Methode SetFocusNode mit einem Index oder einem Schlüssel eines Knotens.

Abweichend von den Standardfarben des TreeViews und den Standard-Markierungsfarben des Systems können Sie auch eigene Farbkombinationen in den Eigenschaften der Klasse setzen: BackColor und ForeColor für nicht markierte Knoten, und SelBackColor und SelForeColor für markierte Knoten. Zusätzlich können Sie über SelBold festlegen, ob markierte Knoten fett dargestellt werden sollen.

Mit der Eigenschaft NoDefaultSel legen Sie fest, ob der normale Selektions-Mechanismus des TreeViews übergangen werden soll. Sie ist auf True voreingestellt. Wird sie auf False gesetzt, wird die normale Knotenmarkierung sichtbar, was vor allem bei eigenen Farbkombinationen für die Markierungen störend wirken dürfte.

Ist die Eigenschaft NoClearOnSpaceKlick gesetzt, werden die Markierungen nicht bei einem Klick in den freien Raum aufgehoben.

Die meisten Ereignisse des TreeViews stehen über die Klasse zur Verfügung. Sie sollten sie anstelle der Original-Ereignisse nutzen, um Störungen der Funktion der Klasse und Seiteneffekte zu vermeiden. Beim MouseDown-Ereignis ist der Parameter Cancel hinzugekommen. Geben Sie in Cancel den Wert zurück, erfolgt keine Markierung, falls die Strg-Taste oder die Kombination Umschalt-Strg beim Anklicken eines Knotens gedrückt gewesen sind. Hinzugekommen ist zum einen das Ereignis SelChange, das bei jeder Änderung der Auswahl ausgelöst wird. Zum anderen informiert das praktische Ereignis NodeDblClick darüber, ob ein Doppelklick auf einen Knoten erfolgt ist.

Die Auswahl der Knoten bzw. die Aufhebung von Auswahlen können Sie auch über einige Methoden vornehmen. ClearSelection hebt die gesamte Auswahl auf. Übergeben Sie einen bestimmten Knoten als Parameter, wird nur die Markierung dieses Knotens und des Astes darunter aufgehoben. Mit SelectAllNodes markieren Sie alle Knoten im TreeView. Bei Übergabe eines bestimmten Knotens wird nur der Knoten samt des Astes darunter ausgewählt. SelectNode markiert einen einzelnen Knoten bzw. hebt die Markierung auf, je nach Wert des Parameters Selected. Mit ToggelNode kehren Sie die Markierung eines einzelnen Knotens um. Setzen Sie den optionalen Parameter Children auf True, werden auch die Markierungen aller knoten unterhalb des betreffenden Knotens umgekehrt. Mit ToggleSelection schließlich kehren Sie die Markierungen aller Knoten im TreeView um. Analog zu ClearSelection und SelectAllNodes betrifft der Aufruf auch wieder nur einen einzelnen Knoten samt des Astes darunter, wenn Sie diesen als Parameter übergeben.

Private WithEvents eTreeView As TreeView

Private mKbdMode As Boolean
Private mMultiSelectMode As Boolean
Private mSelectedNodes As Collection

Public Event AfterLabelEdit(Cancel As Integer, NewString As String)
Public Event BeforeLabelEdit(Cancel As Integer)
Public Event Click()
Public Event Collapse(ByVal Node As MSComctlLib.Node)
Public Event DblClick()
Public Event Expand(ByVal Node As MSComctlLib.Node)
Public Event KeyDown(KeyCode, Shift)
Public Event KeyPress(KeyAscii)
Public Event KeyUp(KeyCode, Shift)
Public Event MouseDown(Button As Integer, Shift As Integer, _
 ByVal x As Single, ByVal y As Single, Cancel As Boolean)
Public Event MouseMove(Button As Integer, Shift As Integer, _
 ByVal x As Single, ByVal y As Single)
Public Event MouseUp(Button As Integer, Shift As Integer, _
 ByVal x As Single, ByVal y As Single)
Public Event NodeClick(ByVal Node As MSComctlLib.Node)
Public Event NodeDblClick(ByVal Node As MSComctlLib.Node)
Public Event SelChange()

Private pBackColor As OLE_COLOR
Private pFocusNode As Node
Private pForeColor As OLE_COLOR
Private pNoClearOnSpaceClick As Boolean
Private pNoDefaultSel As Boolean
Private pSelBackColor As OLE_COLOR
Private pSelForeColor As OLE_COLOR
Private pSelBold As Boolean

Public Property Get BackColor() As OLE_COLOR
  BackColor = pBackColor
End Property

Public Property Let BackColor(New_BackColor As OLE_COLOR)
  Dim nNode As Node
  Dim nSelNode As Node
  
  Select Case New_BackColor
    Case pBackColor
    Case Else
      pBackColor = New_BackColor
      On Error Resume Next
      For Each nNode In mSelectedNodes
        Set nSelNode = mSelectedNodes(CStr(ObjPtr(nNode)))
        If Err.Number Then
          Err.Clear
          nNode.BackColor = pBackColor
          If Err.Number Then
            Exit Property
          End If
        End If
      Next
  End Select
End Property

Public Property Get Count() As Long
  Count = mSelectedNodes.Count
End Property

Public Property Get FocusNode() As Node
  Set FocusNode = pFocusNode
End Property

Public Property Get ForeColor() As OLE_COLOR
  ForeColor = pForeColor
End Property

Public Property Let ForeColor(New_ForeColor As OLE_COLOR)
  Dim nNode As Node
  Dim nSelNode As Node
  
  Select Case New_ForeColor
    Case pForeColor
    Case Else
      pForeColor = New_ForeColor
      For Each nNode In mSelectedNodes
        Set nSelNode = mSelectedNodes(CStr(ObjPtr(nNode)))
        If Err.Number Then
          Err.Clear
          nNode.ForeColor = pForeColor
          If Err.Number Then
            Exit Property
          End If
        End If
      Next
  End Select
End Property

Public Property Get NoClearOnSpaceClick() As Boolean
  NoClearOnSpaceClick = pNoClearOnSpaceClick
End Property

Public Property Let NoClearOnSpaceClick _
 (New_NoClearOnSpaceClick As Boolean)

  pNoClearOnSpaceClick = New_NoClearOnSpaceClick
End Property

Public Property Get NoDefaultSel() As Boolean
  NoDefaultSel = pNoDefaultSel
End Property

Public Property Let NoDefaultSel(New_NoDefaultSel As Boolean)
  pNoDefaultSel = New_NoDefaultSel
End Property

Public Property Get SelBackColor() As OLE_COLOR
  SelBackColor = pSelBackColor
End Property

Public Property Let SelBackColor(New_SelBackColor As OLE_COLOR)
  Dim nNode As Node
  
  Select Case New_SelBackColor
    Case pSelBackColor
    Case Else
      pSelBackColor = New_SelBackColor
      On Error Resume Next
      For Each nNode In mSelectedNodes
        nNode.BackColor = pSelBackColor
        If Err.Number Then
          Exit Property
        End If
      Next
  End Select
End Property

Public Property Get SelBold() As Boolean
  SelBold = pSelBold
End Property

Public Property Let SelBold(New_SelBold As Boolean)
  Dim nNode As Node
  
  Select Case New_SelBold
    Case pSelBold
    Case Else
      pSelBold = New_SelBold
      On Error Resume Next
      For Each nNode In mSelectedNodes
        nNode.Bold = pSelBold
        If Err.Number Then
          Exit Property
        End If
      Next
  End Select
End Property

Public Property Get SelectedNode(Index As Long) As Collection
  If mSelectedNodes.Count Then
    Set SelectedNode = mSelectedNodes(Index)
  End If
End Property

Public Property Get SelForeColor() As OLE_COLOR
  SelForeColor = pSelForeColor
End Property

Public Property Let SelForeColor(New_SelForeColor As OLE_COLOR)
  Dim nNode As Node
  
  Select Case New_SelForeColor
    Case pSelForeColor
    Case Else
      pSelForeColor = New_SelForeColor
      On Error Resume Next
      For Each nNode In mSelectedNodes
        nNode.ForeColor = pSelForeColor
        If Err.Number Then
          Exit Property
        End If
      Next
  End Select
End Property

Public Sub ClearSelection(Optional Node As Node)
  Dim nNode As Node
  Dim nChild As Node
  
  If Node Is Nothing Then
    Set nNode = zGetFirstNode()
  Else
    Set nNode = Node
  End If
  If nNode Is Nothing Then
    Exit Sub
  End If
  With nNode
    .BackColor = pBackColor
    .ForeColor = pForeColor
    .Bold = False
    On Error Resume Next
    mSelectedNodes.Remove CStr(ObjPtr(nNode))
    If .Children Then
      Set nChild = .Child
      Do While Not (nChild Is Nothing)
        Me.ClearSelection nChild
        Set nChild = nChild.Next
      Loop
    End If
  End With
  RaiseEvent SelChange
End Sub

Public Sub SelectAllNodes(Optional Node As Node)
  Dim nNode As Node
  Dim nChild As Node
  
  If Node Is Nothing Then
    Set nNode = zGetFirstNode()
  Else
    Set nNode = Node
  End If
  If nNode Is Nothing Then
    Exit Sub
  End If
  With nNode
    .BackColor = pSelBackColor
    .ForeColor = pSelForeColor
    .Bold = pSelBold
    On Error Resume Next
    mSelectedNodes.Add nNode, CStr(ObjPtr(nNode))
    If .Children Then
      Set nChild = .Child
      Do While Not (nChild Is Nothing)
        Me.SelectAllNodes nChild
        Set nChild = nChild.Next
      Loop
    End If
    RaiseEvent SelChange
  End With
End Sub

Public Sub SelectNode(Node As Node, ByVal Selected As Boolean)
  If Node Is Nothing Then
    Exit Sub
  End If
  With Node
    Select Case Selected
      Case True
        .BackColor = pSelBackColor
        .ForeColor = pSelForeColor
        .Bold = pSelBold
        On Error Resume Next
        mSelectedNodes.Add Node, CStr(ObjPtr(Node))
      Case False
        .BackColor = pBackColor
        .ForeColor = pForeColor
        .Bold = False
        On Error Resume Next
        mSelectedNodes.Remove CStr(ObjPtr(Node))
    End Select
  End With
  RaiseEvent SelChange
End Sub

Public Sub SetFocus()
  On Error Resume Next
  eTreeView.SetFocus
End Sub

Public Sub SetFocusNode(KeyIndex As Variant)
  With eTreeView.Nodes(KeyIndex)
    .Selected = True
    .Selected = False
  End With
End Sub

Public Sub ToggleNode(Optional Node As Variant, _
 Optional ByVal Children As Boolean)

  Dim nNode As Node
  Dim nChild As Node
  Dim nSelected As Boolean
  
  If IsMissing(Node) Then
    Set nNode = pFocusNode
  Else
    Set nNode = Node
  End If
  If nNode Is Nothing Then
    Exit Sub
  End If
  With nNode
    Select Case .BackColor
      Case pSelBackColor
        .BackColor = pBackColor
        .ForeColor = pForeColor
        .Bold = False
        On Error Resume Next
        mSelectedNodes.Remove CStr(ObjPtr(nNode))
      Case pBackColor
        .BackColor = pSelBackColor
        .ForeColor = pSelForeColor
        .Bold = pSelBold
        mSelectedNodes.Add nNode, CStr(ObjPtr(nNode))
        nSelected = True
    End Select
    If CBool(.Children) And Children Then
      Set nChild = .Child
      Do While Not (nChild Is Nothing)
        zSelectChildren nChild, nSelected
        Set nChild = nChild.Next
      Loop
    End If
  End With
  RaiseEvent SelChange
End Sub

Private Sub zSelectChildren(Node As Node, _
 ByVal Selected As Boolean)

  Dim nChild As Node
  
  With Node
    Select Case Selected
      Case False
        .BackColor = pBackColor
        .ForeColor = pForeColor
        .Bold = False
        On Error Resume Next
        mSelectedNodes.Remove CStr(ObjPtr(Node))
      Case True
        .BackColor = pSelBackColor
        .ForeColor = pSelForeColor
        .Bold = pSelBold
        On Error Resume Next
        mSelectedNodes.Add Node, CStr(ObjPtr(Node))
    End Select
    Set nChild = .Child
    Do While Not (nChild Is Nothing)
      zSelectChildren nChild, Selected
      Set nChild = nChild.Next
    Loop
  End With
End Sub

Public Sub ToggleSelection(Optional Node As Node)
  Dim nNode As Node
  Dim nChild As Node
  
  If Node Is Nothing Then
    Set nNode = zGetFirstNode()
  Else
    Set nNode = Node
  End If
  If nNode Is Nothing Then
    Exit Sub
  End If
  With nNode
    Select Case .BackColor
      Case pSelBackColor
        .BackColor = pBackColor
        .ForeColor = pForeColor
        .Bold = False
        On Error Resume Next
        mSelectedNodes.Remove CStr(ObjPtr(nNode))
      Case pBackColor
        .BackColor = pSelBackColor
        .ForeColor = pSelForeColor
        .Bold = pSelBold
        On Error Resume Next
        mSelectedNodes.Add nNode, CStr(ObjPtr(nNode))
    End Select
    If .Children Then
      Set nChild = .Child
      Do While Not (nChild Is Nothing)
        Me.ToggleSelection nChild
        Set nChild = nChild.Next
      Loop
    End If
  End With
  RaiseEvent SelChange
End Sub

Public Function NewEnum() As IUnknown
  Set NewEnum = mSelectedNodes.[_NewEnum]
End Function

Public Sub Init(TreeView As TreeView)
  Set eTreeView = TreeView
  With eTreeView.Nodes(1)
    .Selected = True
    .Selected = False
  End With
  Set pFocusNode = eTreeView.Nodes(1)
End Sub

Private Sub eTreeView_AfterLabelEdit(Cancel As Integer, _
 NewString As String)

  RaiseEvent AfterLabelEdit(Cancel, NewString)
End Sub

Private Sub eTreeView_BeforeLabelEdit(Cancel As Integer)
  If mMultiSelectMode Then
    Cancel = True
  Else
    RaiseEvent BeforeLabelEdit(Cancel)
  End If
End Sub

Private Sub eTreeView_Click()
  RaiseEvent Click
End Sub

Private Sub eTreeView_Collapse(ByVal Node As MSComctlLib.Node)
  If mMultiSelectMode Then
    Node.Selected = False
  End If
  RaiseEvent Collapse(Node)
End Sub

Private Sub eTreeView_DblClick()
  Dim nNode As Node
  
  Set nNode = pFocusNode
  If Not (nNode Is Nothing) Then
    RaiseEvent NodeDblClick(nNode)
  End If
  RaiseEvent DblClick
End Sub

Private Sub eTreeView_Expand(ByVal Node As MSComctlLib.Node)
  RaiseEvent Expand(Node)
End Sub

Private Sub eTreeView_KeyDown(KeyCode As Integer, Shift As Integer)
  RaiseEvent KeyDown(KeyCode, Shift)
  mKbdMode = True
End Sub

Private Sub eTreeView_KeyPress(KeyAscii As Integer)
  Select Case KeyAscii
    Case vbKeyEscape
      KeyAscii = 0
    Case vbKeySpace
      KeyAscii = 0
  End Select
  If KeyAscii Then
    RaiseEvent KeyPress(KeyAscii)
  End If
End Sub

Private Sub eTreeView_KeyUp(KeyCode As Integer, Shift As Integer)
  Select Case KeyCode
    Case vbKeyEscape
      If Shift = vbShiftMask Then
        Me.ClearSelection
        KeyCode = 0
      End If
    Case vbKeySpace
      Select Case Shift
        Case 0
          Me.ToggleNode , CBool(Shift = vbShiftMask)
          KeyCode = False
        Case vbShiftMask
          Me.ToggleNode pFocusNode, CBool(Shift = vbShiftMask)
          KeyCode = False
      End Select
    Case vbKeyA
      If Shift = vbCtrlMask Then
        Me.SelectAllNodes
        KeyCode = 0
      End If
    Case vbKeyT
      If Shift = vbCtrlMask Then
        Me.ToggleSelection
        KeyCode = 0
      End If
  End Select
  If KeyCode Then
    RaiseEvent KeyUp(KeyCode, Shift)
  End If
End Sub

Private Sub eTreeView_MouseDown(Button As Integer, _
 Shift As Integer, x As Single, y As Single)

  Dim nNode As Node
  Dim nCancel As Boolean
  
  mMultiSelectMode = False
  mKbdMode = False
  RaiseEvent MouseDown(Button, Shift, x, y, nCancel)
  If Not nCancel Then
    Set nNode = eTreeView.HitTest(x, y)
    If (Shift And vbCtrlMask) = vbCtrlMask Then
      mMultiSelectMode = True
    ElseIf Not pNoClearOnSpaceClick Then
      Me.ClearSelection
      RaiseEvent SelChange
    End If
  End If
End Sub

Private Sub eTreeView_MouseMove(Button As Integer, _
Shift As Integer, x As Single, y As Single)

  RaiseEvent MouseMove(Button, Shift, x, y)
End Sub

Private Sub eTreeView_MouseUp(Button As Integer, _
 Shift As Integer, x As Single, y As Single)

  Dim nNode As Node
  
  Set nNode = eTreeView.HitTest(x, y)
  Select Case Button
    Case vbLeftButton
      If Not (nNode Is Nothing) Then
        If (Shift And vbCtrlMask) = vbCtrlMask Then
          Me.ToggleNode nNode, CBool((Shift And vbShiftMask) _
           = vbShiftMask)
          nNode.Selected = False
        End If
      End If
    Case Else
      If mMultiSelectMode Then
        If Not (nNode Is Nothing) Then
          nNode.Selected = False
        End If
      End If
  End Select
  Set pFocusNode = nNode
  RaiseEvent MouseUp(Button, Shift, x, y)
End Sub

Private Sub eTreeView_NodeClick(ByVal Node As MSComctlLib.Node)
  If Not mMultiSelectMode And Not mKbdMode Then
    If pNoDefaultSel Then
      Node.Selected = False
    End If
    With Node
      .BackColor = pSelBackColor
      .ForeColor = pSelForeColor
      .Bold = pSelBold
    End With
    Set mSelectedNodes = New Collection
    mSelectedNodes.Add Node, CStr(ObjPtr(Node))
    RaiseEvent SelChange
  End If
  If mKbdMode And pNoDefaultSel Then
    Node.Selected = False
  End If
  Set pFocusNode = Node
  RaiseEvent NodeClick(Node)
End Sub

Private Sub Class_Initialize()
  pBackColor = vbWindowBackground
  pForeColor = vbWindowText
  pNoDefaultSel = True
  pSelBackColor = vbHighlight
  pSelForeColor = vbHighlightText
  Set mSelectedNodes = New Collection
End Sub

Private Sub Class_Terminate()
  Set mSelectedNodes = Nothing
  Set pFocusNode = Nothing
  Set eTreeView = Nothing
End Sub

Private Function zGetFirstNode() As Node
  With eTreeView.Nodes
    If .Count Then
      Set zGetFirstNode = .Item(1).Root.FirstSibling
    End If
  End With
End Function

Klasse TreeViewMultiSelect und Beispiel-Projekt (tvwmultiselect.zip - ca. 7,5 KB)



Komponenten-Übersicht

Schnellsuche




Zum Seitenanfang

Copyright © 1999 - 2023 Harald M. Genauck, ip-pro gmbh  /  Impressum

Zum Seitenanfang

Zurück...

Zurück...