|
In einem TreeView-Steuerelement aus den Microsoft Common Controls können Sie einen Knoten verschieben, indem Sie seiner Parent-Eigenschaft einen anderen Knoten als neuen übergeordneten Knoten zuweisen:
Set Node.Parent = OtherNode
Damit wird nicht nur der Knoten selbst, sondern auch der gesamte Ast darunter gleich mit verschoben.
Soll allerdings ein Knoten in die oberste Hierarchieebene verschoben werden, funktioniert das so leider nicht. Denn auch wenn die Parent-Eigenschaft eines Knotens der obersten Hierarchieebene "Nothing" zurückgibt, ist es umgekehrt nicht möglich, der Parent-Eigenschaft ein "Nothing" zuzuweisen, um den Knoten auf die oberste Ebene zu befördern.
Der einzige Ausweg ist, einen neuen Knoten mit dem gleichen Text und den gleichen Image-Schlüsseln auf der obersten Ebene einzufügen (ohne Parent-Schlüssel und ohne Bezugsangabe), die Unterknoten (wie oben beschrieben, samt den Ästen jeweils darunter) des zu verschiebenden Knotens nachträglich unter diesen neuen Knoten zu schieben, und den "alten" Knoten zu löschen. Soll der Expansionszustand des alten Knotens erhalten bleiben, ist der neue Knoten noch zu expandieren. Und falls der alte Knoten selektiert war, und auch diese Selektion erhalten bleiben soll, ist der neue Knoten ebenfalls zu selektieren.
Die ganze Schieberei lässt sich einfach in eine Hilfsprozedur packen. Sie übergeben der Prozedur TvwNodeAsRoot das TreeView-Steuerelement und dazu den zu verschiebenden Knoten. Im optionalen Parameter KeepSelection können Sie festlegen, ob der Knoten auch nach dem Verschieben ausgewählt sein soll, falls er das vorher gewesen war. Setzen sie den weiteren optionalen Parameter auf True, wird die Bildschirmdarstellung des TreeViews während der ganzen Operation eingefroren - bei vielen zu verschiebenden Unterknoten entsteht so kein störendes Flackern (und es geht schneller vonstatten).
Private Declare Function LockWindowUpdate Lib "user32" _
(ByVal hwndLock As Long) As Long
Public Sub TvwNodeAsRoot(TreeView As TreeView, Node As Node, _
Optional ByVal KeepSelection As Boolean = True, _
Optional ByVal LockWindow As Boolean)
Dim nNewNode As Node
Dim nChild As Node
Dim nKey As String
Dim nSelectedNode As Node
With TreeView
If LockWindow Then
LockWindowUpdate .hWnd
End If
If KeepSelection Then
Set nSelectedNode = .SelectedItem
End If
End With
With Node
nKey = .Key
Set nNewNode = TreeView.Nodes.Add(, , , .Text, .Image, _
.SelectedImage)
With nNewNode
Set nChild = Node.Child
Do While Not (nChild Is Nothing)
With nChild
Set .Parent = nNewNode
Set nChild = .Next
End With
Loop
If KeepSelection Then
If Not (nSelectedNode Is Nothing) Then
If nSelectedNode Is Node Then
.Selected = True
End If
End If
End If
TreeView.Nodes.Remove nKey
.Key = nKey
End With
End With
If LockWindow Then
LockWindowUpdate 0&
End If
End Sub
Ein kleines Problem ergibt sich, wenn die Schlüssel der Knoten automatisch aus dem jeweiligen Pfad eines Knotens generiert werden sollen (siehe: "Knotenpfade knüpfen"). Dann muss bei allen Knoten, sowohl beim verschobenen Knoten als auch bei dessen Unterknoten und bei allen weiteren Knoten in den Verästelungen der Schlüssel entsprechend des veränderten Pfades neu gesetzt werden. Im Prinzip bleibt dazu die Prozedur die gleiche. Lediglich wird bei jedem Knoten sein Pfad aus der FullPath-Eigenschaft als Schlüssel (Key) übernommen. Auch hier brauchen die Unterknoten in den tieferen Verästelungen des zu verschiebenden Knotens nicht einzeln verschoben werden, jedoch muss die gesamte Verästelung rekursiv durchlaufen werden (private Hilfsprozedur TvwAutoKeyChildren, s.u.), um überall den Schlüssel neu zu setzen.
Public Sub TvwNodeAsRootAutoKey(TreeView As TreeView, _
Node As Node, Optional ByVal KeepSelection As Boolean = True, _
Optional ByVal LockWindow As Boolean)
Dim nNewNode As Node
Dim nChild As Node
Dim nKey As String
Dim nSelectedNode As Node
With TreeView
If LockWindow Then
LockWindowUpdate .hWnd
End If
If KeepSelection Then
Set nSelectedNode = .SelectedItem
End If
End With
With Node
nKey = .Key
Set nNewNode = TreeView.Nodes.Add(, , , .Text, .Image, _
.SelectedImage)
With nNewNode
.Key = .FullPath
Set nChild = Node.Child
Do While Not (nChild Is Nothing)
With nChild
Set .Parent = nNewNode
.Key = .FullPath
TvwAutoKeyChildren nChild
Set nChild = .Next
End With
Loop
If KeepSelection Then
If Not (nSelectedNode Is Nothing) Then
If nSelectedNode Is Node Then
.Selected = True
End If
End If
End If
TreeView.Nodes.Remove nKey
End With
End With
If LockWindow Then
LockWindowUpdate 0&
End If
End Sub
Public Sub TvwAutoKeyChildren(Node As Node)
Dim nChild As Node
Set nChild = Node.Child
Do While Not (nChild Is Nothing)
With nChild
.Key = .FullPath
TvwAutoKeyChildren nChild
Set nChild = .Next
End With
Loop
End Sub
Damit Sie in Ihrem Code nicht aufwändig untersuchen und entscheiden müssen, ob ein Knoten per Änderung der Parent-Eigenschaft umgesetzt werden kann, können sie die beiden folgenden Hilfsprozeduren (einmal ohne und einmal mit automatischer Schlüsselvergabe) in allen Fällen verwenden. Sie übergeben entweder den neuen Eltern-Knoten oder Sie übergeben Nothing, um einen Knoten auf die oberste Ebene zu schieben.
Public Sub TvwSetNodeParent(TreeView As TreeView, Node As Node, _
NewParent As Node, Optional ByVal KeepSelection _
As Boolean = True, Optional ByVal LockWindow As Boolean)
If NewParent Is Nothing Then
TvwNodeAsRoot TreeView, Node, KeepSelection, LockWindow
Else
With Node
Set .Parent = NewParent
If KeepSelection Then
.Selected = True
.EnsureVisible
End If
End With
End If
End Sub
Public Sub TvwSetNodeParentAutoKey(TreeView As TreeView, _
Node As Node, NewParent As Node, Optional ByVal KeepSelection _
As Boolean = True, Optional ByVal LockWindow As Boolean)
If NewParent Is Nothing Then
TvwNodeAsRootAutoKey TreeView, Node, KeepSelection, LockWindow
Else
With Node
Set .Parent = NewParent
.Key = .FullPath
If KeepSelection Then
.Selected = True
.EnsureVisible
End If
End With
End If
End Sub
|