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 14.11.2001

Diese Seite wurde zuletzt aktualisiert am 14.11.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...

Knoten-Transporteur

Zurück...

(-hg) mailto:hg_@aboutvb.de

Es gibt nur eine einzige direkte Möglichkeit, einen Knotens in einem TreeView-Steuerelement an eine andere Position zu verschieben: Sie können ihn einem anderen Elternknoten zuweisen. Die Änderung der Reihenfolge der Knoten auf einer Ebene können Sie nachträglich nicht direkt ändern. Genau so wenig können Sie einen Knoten auf einfache Weise von einem TreeView-Steuerelement in ein anderes umhängen.

Es wird Ihnen nichts übrig bleiben, als den betreffenden Knoten aus der Nodes-Sammlung des TreeViews heraus zu nehmen und einen neuen Knoten an der gewünschten Stelle mit den Eigenschaften des alten Knotens wieder einzufügen. Während sämtliche Kindknoten und Verzweigungen eines Knotens beim Umhängen an einen anderen Elternknoten erhalten bleiben, gehen sie beim Herausnehmen eines Knotens unweigerlich verloren. Die Eigenschaften und Positionen sämtlicher Kindknoten müssen also vor dem Umhängen ebenfalls ermittelt und festgehalten werden, damit sie nach dem Umhängen wieder entsprechend eingefügt werden können.

Die im folgenden beschriebene Klasse clsNodeStore dient dazu, die Eigenschaften eines Knotens und die seiner Kindknoten und die Positionen in den Verzweigungen festzuhalten ("den Knoten zu serialisieren") und an einen neuen Knoten nach seinem Einfügen zu übergeben ("deserialisieren").

Die Eigenschaften des Knotens werden zudem als Eigenschaften der Klasse clsNodeStore zur Verfügung gestellt, so dass sie während der Phase der Zwischenspeicherung beliebig ausgelesen und auch manipuliert werden können. Dies gilt auch für die Kindknoten - die unter dem in einer Instanz von clsNodeStore serialisierten Knoten liegende Hierarchie ist daher auch nach dem Entfernen des Anfangsknotens aus der Nodes-Collection des TreeViews zugänglich. Alle Kindknoten sind hier ebenfalls als clsNodeStore-Instanzen abgelegt.

Sie können daher auch eine neue leere clsNodeStore-Instanz erzeugen, mit aus einer beliebigen Quelle stammenden Daten für die Eigenschaften füllen und als neuen Knoten in die Nodes-Collection einfügen. Ebenso können Sie so auch eine komplette, darunter liegende Hierarchie vorbereiten und zugleich einfügen. Dazu verfügt die Klasse clsNodeStore über die für eine Collection üblichen Methoden Add, Remove und Clear, um die jeweilige Kind-Ebene eines Knotens bearbeiten zu können. Zugriff auf die einzelnen Kindknoten bietet die Eigenschaft ChildNode und die Anzahl der Kindknoten liefert die Eigenschaft Children (statt des üblichen "Count" die analoge Bezeichnung wie beim Node-Objekt). Auch die Möglichkeit der Enumeration der Kindknoten in einer For...Each-Schleife steht zur Verfügung.

Die Klasse clsNodeStore ist für Knoten des TreeView-Steuerelements der Version 5 der Microsoft Common Controls geeignet. Zur Verwendung mit der Version 5 ist die Klasse clsNodeStore5 gedacht. Diese ist gegenüber der 6er-Version ein wenig abgespeckt - es fehlen die erweiterten Eigenschaften BackColor, Bold, Checked und ForeColor. Außerdem kann hier die Tag-Eigenschaft keine Objekt-Referenzen aufnehmen. Hier sehen Sie die 6er-Version, die 5er-Version ist im Download-Paket zu diesem Artikel enthalten.

Private pChildNodes As Collection

Private pBackColor As OLE_COLOR
Private pBold As Boolean
Private pChecked As Boolean
Private pExpanded As Boolean
Private pExpandedImage As Variant
Private pForeColor As OLE_COLOR
Private pImage As Variant
Private pKey As String
Private pSelected As Boolean
Private pSelectedImage As Variant
Private pTag As Variant
Private pText As String

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

Public Property Let BackColor(New_BackColor As OLE_COLOR)
  pBackColor = New_BackColor
End Property

Public Property Get Bold() As Boolean
  Bold = pBold
End Property

Public Property Let Bold(New_Bold As Boolean)
  pBold = New_Bold
End Property

Public Property Get Checked() As Boolean
  Checked = pChecked
End Property

Public Property Let Checked(New_Checked As Boolean)
  pChecked = New_Checked
End Property

Public Property Get ChildNode(KeyIndex As Variant) As clsNodeStore
  If Not (pChildNodes Is Nothing) Then
    Set ChildNode = pChildNodes(KeyIndex)
  End If
End Property

Public Property Get Children() As Long
  If Not (pChildNodes Is Nothing) Then
    Children = pChildNodes.Count
  End If
End Property

Public Property Get Expanded() As Boolean
  Expanded = pExpanded
End Property

Public Property Let Expanded(New_Expanded As Boolean)
  pExpanded = New_Expanded
End Property

Public Property Get ExpandedImage() As Variant
  ExpandedImage = pExpandedImage
End Property

Public Property Let ExpandedImage(New_ExpandedImage As Variant)
  pExpandedImage = New_ExpandedImage
End Property

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

Public Property Let ForeColor(New_ForeColor As OLE_COLOR)
  pForeColor = New_ForeColor
End Property

Public Property Get Image() As Variant
  Image = pImage
End Property

Public Property Let Image(New_Image As Variant)
  pImage = New_Image
End Property

Public Property Get Key() As String
  Key = pKey
End Property

Public Property Let Key(New_Key As String)
  pKey = New_Key
End Property

Public Property Get Selected() As Boolean
  Selected = pSelected
End Property

Public Property Get SelectedImage() As Variant
  SelectedImage = pSelectedImage
End Property

Public Property Let SelectedImage(New_SelectedImage As Variant)
  pSelectedImage = New_SelectedImage
End Property

Public Property Get Tag() As Variant
  If IsObject(pTag) Then
    Set Tag = pTag
  Else
    Tag = pTag
  End If
End Property

Public Property Let Tag(New_Tag As Variant)
  zSetTag New_Tag
End Property

Public Property Set Tag(New_Tag As Variant)
  zSetTag New_Tag
End Property

Private Sub zSetTag(New_Tag As Variant)
  If IsObject(New_Tag) Then
    Set pTag = New_Tag
  Else
    pTag = New_Tag
  End If
End Sub

Public Property Get Text() As String
  Text = pText
End Property

Public Property Let Text(New_Text As String)
  pText = New_Text
End Property

Public Function Add(Optional Key As Variant, _
 Optional Before As Variant, Optional After As Variant) _
 As clsNodeStore

  Dim nNodeStore As clsNodeStore
  
  If pChildNodes Is Nothing Then
    Set pChildNodes = New Collection
  End If
  Set nNodeStore = New clsNodeStore
  pChildNodes.Add nNodeStore, Key, Before, After
  Set Add = nNodeStore
End Function

Public Sub Clear()
  Set pChildNodes = Nothing
End Sub

Public Sub Remove(KeyIndex As Variant)
  If Not (pChildNodes Is Nothing) Then
    pChildNodes.Remove KeyIndex
  End If
End Sub

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

Ehe wir zu den eigentlich interessanten Methoden der Klasse zur Serialisierung und Deserialisierung kommen, möchte ich noch ein weiteres Feature erwähnen: Die Serialisierung in ein PropertyBag-Objekt, das sie allerdings erst ab Visual Basic 6 als eigenständiges Objekt selbst instanzieren können. Auf die direkte Serialisierung der Klasse, wie sie ab Visual Basic 6 ebenfalls möglich ist, wurde hier verzichtet - sie bringt nicht allzu viel und würde die Klasse nur komplizierter gestalten. Wenn Sie wollen, dürfte es aber nicht schwierig sein, die Klasse an eine direkte Serialisierung anzupassen.

Public Sub ReadProperties(PropBag As PropertyBag)
  Dim nChildren As Long
  Dim nPropBag As PropertyBag
  Dim nNodeStore As clsNodeStore
  Dim nChildKey As String
  Dim l As Long
  
  With PropBag
    pBackColor = .ReadProperty("BackColor")
    pBold = .ReadProperty("Bold")
    pChecked = .ReadProperty("Checked")
    pExpanded = .ReadProperty("Expanded")
    pExpandedImage = .ReadProperty("ExpandedImage")
    pForeColor = .ReadProperty("ForeColor")
    pImage = .ReadProperty("Image")
    pKey = .ReadProperty("Key")
    pSelectedImage = .ReadProperty("SelectedImage")
    pTag = .ReadProperty("Tag")
    pText = .ReadProperty("Text")
    nChildren = .ReadProperty("Children")
    If nChildren Then
      Set pChildNodes = New Collection
      For l = 1 To nChildren
        Set nNodeStore = New clsNodeStore
        Set nPropBag = New PropertyBag
        nPropBag.Contents = .ReadProperty("Child" & l)
        nNodeStore.ReadProperties nPropBag
        nChildKey = nNodeStore.Key
        If Len(nChildKey) Then
          pChildNodes.Add nNodeStore, nChildKey
        Else
          pChildNodes.Add nNodeStore
        End If
      Next
    End If
  End With
End Sub

Public Sub WriteProperties(PropBag As PropertyBag)
  Dim nNodeStore As clsNodeStore
  Dim nPropBag As PropertyBag
  Dim l As Long
  
  With PropBag
    .WriteProperty "BackColor", pBackColor
    .WriteProperty "Bold", pBold
    .WriteProperty "Checked", pChecked
    .WriteProperty "Expanded", pExpanded
    .WriteProperty "ExpandedImage", pExpandedImage
    .WriteProperty "ForeColor", pForeColor
    .WriteProperty "Image", pImage
    .WriteProperty "Key", pKey
    .WriteProperty "SelectedImage", pSelectedImage
    If Not IsObject(pTag) Then
      .WriteProperty "Tag", pTag
    End If
    .WriteProperty "Text", pText
    If pChildNodes Is Nothing Then
      .WriteProperty "Children", 0
    Else
      .WriteProperty "Children", pChildNodes.Count
      For Each nNodeStore In pChildNodes
        Set nPropBag = New PropertyBag
        nNodeStore.WriteProperties nPropBag
        l = l + 1
        .WriteProperty "Child" & l, nPropBag.Contents
      Next
    End If
  End With
End Sub

Schauen wir uns nun zunächst die Methode Serialize an. Im ersten Parameter geben Sie den zu serialisierenden Knoten an - entweder als Schlüssel (Key) oder Index des Knotens, oder Sie übergeben den betreffenden Knoten direkt. Geben Sie nur den Schlüssel oder Index an, müssen Sie im zweiten Parameter das TreeView-Steuerelement angeben, in dem sich der Knoten befindet. In nächsten optionalen Parameter IncludeChildren legen Sie fest, ob die unter dem Knoten liegende Kindknoten-Hierarchie mit serialisiert werden soll. Setzen Sie den nächsten optionalen Parameter Remove nicht auf True, wird der Knoten so zu sagen nur kopiert und nicht aus der Nodes-Collection des TreeView-Steuerelements entfernt. Setzen Sie ihn auf True, müssen Sie zuvor auch das TreeView-Steuerelement angegeben haben, aus dem der Knoten entfernt werden soll. Im letzten optionalen Parameter ToPropBag können Sie eine Instanz eines PropertyBag-Objekts übergeben, die Sie ab Visual Basic 6 selbst erzeugen können. Übergeben Sie hier ein PropertyBag-Objekt, wird der komplette Inhalt der Klasse einschließlich der Kindknoten-Hierarchie über die intern aufgerufene oben stehende WriteProperties-Methode darin abgelegt.

Public Sub Serialize(Node As Variant, _
 Optional TreeView As TreeView, _
 Optional ByVal IncludeChildren As Boolean, _
 Optional ByVal Remove As Boolean, _
 Optional ToPropBag As PropertyBag)

  Dim nNode As Node
  Dim nNodeStore As clsNodeStore
  Dim nChildKey As String
  
  If IsObject(Node) Then
    If TypeOf Node Is Node Then
      Set nNode = Node
    End If
  Else
    Set nNode = TreeView.Nodes(Node)
  End If
  If Not (nNode Is Nothing) Then
    With nNode
      pBackColor = .BackColor
      pBold = .Bold
      pChecked = .Checked
      pExpanded = .Expanded
      pExpandedImage = .ExpandedImage
      pForeColor = .ForeColor
      pImage = .Image
      pKey = .Key
      pSelected = .Selected
      pSelectedImage = .SelectedImage
      If IsObject(.Tag) Then
        Set pTag = .Tag
      Else
        pTag = .Tag
      End If
      pText = .Text
      If IncludeChildren Then
        If .Children Then
          Set pChildNodes = New Collection
          Set nNode = .Child
          With pChildNodes
            Do While Not (nNode Is Nothing)
              Set nNodeStore = New clsNodeStore
              nNodeStore.Serialize nNode, , True
              nChildKey = nNode.Key
              If Len(nChildKey) Then
                .Add nNodeStore, nChildKey
              Else
                .Add nNodeStore
              End If
              Set nNode = nNode.Next
            Loop
          End With
        End If
      Else
        Set pChildNodes = Nothing
      End If
      If Remove Then
        TreeView.Nodes.Remove .Index
      End If
    End With
    If Not (ToPropBag Is Nothing) Then
      Me.WriteProperties ToPropBag
    End If
  End If
End Sub

Das Einfügen eines in einer clsNodeStore-Instanz serialisierten Knotens erfolgt über die Methode Deserialize. Ihr übergeben Sie im ersten Parameter das TreeView-Steuerelement, in dessen Nodes-Collection der serialiserte Knoten eingefügt werden soll. Die weiteren, optionalen Parameter Relative, Relationship und Key entsprechen denen der Add-Methode der Nodes-Collection. Hiermit bestimmen Sie also die tatsächliche (gegebenenfalls neue) Position des neu eingefügten Knotens. Setzen Sie den nächsten optionalen Parameter UseOriginalKey auf True, wird der ursprüngliche Schlüssel des serialiserten Knotens wieder verwendet (das gilt jeweils auch für seine Kindknoten) - der eventuell zuvor im Parameter Key übergebene Schlüssel wird ignoriert. Im Parameter IncludeChildren geben Sie an, ob auch eine mit serialisierte Kindknoten-Hierarchie eingefügt werden soll. In KeepExpanded und KeepSelection legen Sie fest, ob die eingefügten Knoten so wie serialisiert expandiert werden sollen, und ob der Knoten, der beim Serialisieren gegebenenfalls selektiert war, nun auch wieder selektiert werden soll. Im letzten Parameter können Sie wieder ein PropertyBag-Objekt übergeben aus dem der Inhalt der clsNodeStore-Instanz zunächst ausgelesen wird, ehe der weitere Aufbau des Knotens erfolgt. Die Methode gibt wie die Add-Methode der Nodes-Collection eine Referenz auf den neu eingefügten Knoten zurück.

Public Function Deserialize(TreeView As TreeView, _
 Optional Relative As Variant, _
 Optional ByVal Relationship As Variant, _
 Optional Key As Variant, _
 Optional ByVal UseOriginalKey As Boolean, _
 Optional ByVal IncludeChildren As Boolean, _
 Optional ByVal KeepExpanded As Boolean, _
 Optional ByVal KeepSelection As Boolean, _
 Optional FromPropBag As PropertyBag) As Node

  Dim nNode As Node
  Dim nNodeStore As clsNodeStore
  
  If Not (FromPropBag Is Nothing) Then
    Me.ReadProperties FromPropBag
  End If
  If UseOriginalKey Then
    Set nNode = _
     TreeView.Nodes.Add(Relative, Relationship, pKey, pText)
  Else
    Set nNode = _
     TreeView.Nodes.Add(Relative, Relationship, Key, pText)
  End If
  With nNode
    .BackColor = pBackColor
    .Bold = pBold
    .Checked = pChecked
    .ExpandedImage = pExpandedImage
    .ForeColor = pForeColor
    .Image = pImage
    .SelectedImage = pSelectedImage
    If IsObject(pTag) Then
      Set .Tag = pTag
    Else
      .Tag = pTag
    End If
    .Text = pText
    If IncludeChildren Then
      If Not (pChildNodes Is Nothing) Then
        For Each nNodeStore In pChildNodes
          nNodeStore.Deserialize TreeView, nNode, tvwChild, , _
           UseOriginalKey, True, KeepExpanded, KeepSelection
        Next
      End If
    End If
    .Expanded = pExpanded And KeepExpanded
    If KeepSelection And pSelected Then
      .Selected = True
      Set TreeView.SelectedItem = nNode
    End If
  End With
  Set Deserialize = nNode
End Function

Damit hätten Sie eigentlich schon alles, was Sie zum Serialisieren, Transportieren und wieder Einfügen von Knoten samt einer darunter liegenden Knoten-Hierarchie benötigen. Da zum Serialisieren und zum wieder Einfügen die Methoden Serialize und Deserialize immer paarweise aufgerufen werden, lassen sie sich auch zusammenfassen - in den Methoden CopyNode und MoveNode. Beide rufen intern die private Prozedur zCopyMoveNode auf. Dort wird nur beim Aufruf von MoveNode aus der alte Knoten aus der Nodes-Collection des TreeView-Steuerelements entfernt.

Public Function CopyNode(Node As Variant, _
 FromTreeView As TreeView, _
 Optional ByVal IncludeChildren As Boolean, _
 Optional ByVal KeepExpanded As Boolean, _
 Optional ToTreeView As TreeView, _
 Optional Relative As Variant, _
 Optional ByVal Relationship As Variant, _
 Optional Key As Variant, _
 Optional ByVal DestNodeExpanded As Boolean) As Node

  Set CopyNode = zCopyMoveNode(Node, FromTreeView, IncludeChildren, _
   KeepExpanded, ToTreeView, Relative, Relationship, Key, , _
   DestNodeExpanded)
End Function

Public Function MoveNode(Node As Variant, _
 FromTreeView As TreeView, _
 Optional ByVal IncludeChildren As Boolean, _
 Optional ByVal KeepExpanded As Boolean, _
 Optional ToTreeView As TreeView, _
 Optional Relative As Variant, _
 Optional ByVal Relationship As Variant, _
 Optional Key As Variant, _
 Optional ByVal UseOriginalKey As Boolean, _
 Optional ByVal DestNodeExpanded As Boolean, _
 Optional ByVal KeepSelection As Boolean) As Node

  Set MoveNode = zCopyMoveNode(Node, FromTreeView, IncludeChildren, _
   KeepExpanded, ToTreeView, Relative, Relationship, Key, _
   UseOriginalKey, DestNodeExpanded, KeepSelection, True)
End Function

Private Function zCopyMoveNode(Node As Variant, _
 FromTreeView As TreeView, _
 Optional ByVal IncludeChildren As Boolean, _
 Optional ByVal KeepExpanded As Boolean, _
 Optional ToTreeView As TreeView, _
 Optional Relative As Variant, _
 Optional ByVal Relationship As Variant, _
 Optional Key As Variant, _
 Optional ByVal UseOriginalKey As Boolean, _
 Optional ByVal DestNodeExpanded As Boolean, _
 Optional ByVal KeepSelection As Boolean, _
 Optional ByVal Remove As Boolean) As Node

  Dim nToTreeView As TreeView
  Dim nNode As Node
  
  Me.Serialize Node, FromTreeView, IncludeChildren, Remove
  If ToTreeView Is Nothing Then
    Set nToTreeView = FromTreeView
  Else
    Set nToTreeView = ToTreeView
  End If
  Set nNode = Me.Deserialize(nToTreeView, Relative, Relationship, _
   Key, UseOriginalKey, IncludeChildren, KeepExpanded, _
   KeepSelection)
  With nNode
    If Not (.Parent Is Nothing) Then
      .Expanded = DestNodeExpanded
    End If
  End With
  Set zCopyMoveNode = nNode
End Function

Klassen clsNodeStore und clsNodeStore5 (tvwnodestore.zip - ca. 4,8 KB)



Komponenten-Übersicht

Schnellsuche




Zum Seitenanfang

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

Zum Seitenanfang

Zurück...

Zurück...