ListBox 到 TreeView 拖放





3.00/5 (18投票s)
在本文中,我们将学习如何将 ListBox 中的一个项拖放到 TreeView 中。我们还将讨论如何在 TreeView 中创建文件夹以及删除文件夹。
引言
在本文中,我们将学习如何将 ListBox
中的一个项拖放到 TreeView
中。我们还将讨论如何在 TreeView
中创建文件夹以及删除文件夹。
模块思路
该模块使用 SQL Server 2000 的 NorthWind 数据库中的 Customers 表中的“ContactName”值填充 ListBox
。在 TreeView
中,有一个名为“Country”的根文件夹。通过单击“NewFolder”按钮,用户可以创建文件夹在“Country”文件夹下,并可以将其命名为相应的国家名称。当程序运行时,您将看到以下屏幕
图 (a) 初始拖放屏幕
拖放操作后,您将看到类似以下屏幕截图的内容
图 (b) 最终拖放屏幕
可以在用户创建的文件夹下拖放 ListBox 中列出的客户。客户只能拖放到文件夹下。但是,TreeView 中列出的客户可以拖放到TreeView 内部。为了区分TreeView 中的客户和不在TreeView 中的客户,当客户被拖放到TreeView 中时,模块会将 ListBox 中的客户颜色从蓝色更改为黑色。用户可以通过单击“DeleteFolder”按钮来删除文件夹。这样做会改变此删除文件夹下的 ListBox 中项的颜色。
在此模块中,不同控件的名称为
lstCust
:ListBox
trvCntry
:TreeView
拖放操作
在从 ListBox
拖动项的操作中,以下事件参与其中
ListBox_MouseDown
当鼠标指针位于控件上且按下鼠标按钮时,会发生此事件。我们使用此事件来捕获正在从 ListBox
拖动的项。以下代码行可完成此操作
lstCust.Items(lstCust.IndexFromPoint(e.X, e.Y)).ToString()
其中 X
获取鼠标单击的 x 坐标,Y
获取鼠标单击的 y 坐标。IndexFromPoint
返回指定坐标处项的零基索引。
DoDragDrop Method: Begins a drag-and-drop operation.
Public Function DoDragDrop( _
ByVal data As Object, _
ByVal allowedEffects As DragDropEffects _
) As DragDropEffects
参数
data
- 要拖动的数据。allowedEffects
-DragDropEffects
值之一。allowedEffects
参数决定了可以发生哪些拖动操作。
在我们的模块中,我们使用了以下代码行
DoDragDrop(strItem, DragDropEffects.All)
DragDropEffects
指定拖放操作的效果。DragDropEffects
的成员如下所示
All
- 数据被复制,从拖动源中删除,并在放置目标中滚动。Copy
- 数据被复制到放置目标。Link
- 来自拖动源的数据链接到放置目标。Move
- 来自拖动源的数据被移动到放置目标。None
- 放置目标不接受数据。Scroll
- 放置目标中的滚动即将开始或正在进行中。
在从 ListBox
将项拖放到 TreeView
的放置操作中,以下事件参与其中
trvCntry_DragEnter
当一个对象被拖动到控件的边界内时,会发生此事件。我们在该事件中编写了以下代码行
If e.Data.GetDataPresent(DataFormats.Text) Then
e.Effect = DragDropEffects.Move
Else
e.Effect = DragDropEffects.None
End If
e.Data
获取IDataObject
(提供一种与格式无关的数据传输机制),其中包含与此事件相关的数据。e.Data.GetDataPresent
:我们可以使用GetDataPresent
方法来确定数据是否符合数据正在被拖动的控件的格式要求。e.Effect
获取或设置拖动事件目标允许的拖放操作。
trvCntry_DragDrop
拖放操作完成时会发生此事件。我们在该事件中编写了以下代码行。我们将拖动的项存储在一个虚拟节点中,以便将其放置在 TreeView
上
strNodeDragged = CType(e.Data.GetData(strDummy.GetType), String)
DragNode = New TreeNode(strNodeDragged)
接下来,我们查找要放置项的 TreeView 中的目标项
position.X = e.X
position.Y = e.Y
PointToClient
将指定的屏幕点转换为客户端坐标。
position = trvCntry.PointToClient(position)
DropNode = Me.trvCntry.GetNodeAt(position)
我们按如下方式验证目标 TreeNode
。它应该是 RootNode
If IsNothing(DropNode) Or DropNode.Text = "Country" Then
Exit Sub
End If
为了确保项只能拖放到文件夹上,我们通过编辑 TreeNode
的 Tag
属性来为项分配“N”,为文件夹节点分配“Y”,如下所示
If IsNothing(DragNode.Tag) Then
DragNode.Tag = "N"
End If
现在,我们的下一个任务是检查拖动的项是否已在 TreeView
中。我们通过调用 ExistInTreeView ()
方法来实现,如下所示
'*************************************************************
' Function Name : ExistInTreeView
' Purpose : This Function Removes The DragNode
' from the tree from its Previous Place
' Input : DragNode,Node
' Output : Integer
' Author : Ujwal Watgule
' Date : 6th May 2006
' Modification History
' --------------------------------------------------------
'*************************************************************
Private Function ExistInTreeView(ByVal node As TreeNode, _
ByVal nddrag As TreeNode) As Integer
Dim anode As TreeNode
Try
anode = New TreeNode()
For Each anode In node.Nodes
If Trim(anode.Text) = Trim(nddrag.Text) Then
trvCntry.Nodes.Remove(anode)
Return sThree
End If
If anode.Nodes.Count > 0 Then
ExistInTreeView(anode, nddrag)
End If
If Trim(anode.Text) = Trim(nddrag.Text) Then
trvCntry.Nodes.Remove(anode)
Return sThree
End If
Next
Catch ex As Exception
Throw ex
End Try
End Function
如下所示,我们遍历 TreeView
的每个节点,并确保被拖动的节点从其先前的父文件夹中移除。
mTrNode = New TreeNode()
For Each mTrNode In trvCntry.Nodes
ExistInTreeView(mTrNode, DragNode)
Next
现在,我们可以将拖动的项附加到 TreeView
的目标节点。
如果目标节点是文件夹节点,则可以使用以下代码行插入拖动的项。但是,如果目标节点不是文件夹节点,则必须将拖动的项插入到目标节点的父节点中。如下面的代码行所示,我们将拖动项的 Tag
属性设置为“N”,其含义我们已解释过。
If DropNode.Tag = "Y" Then
DropNode.Nodes.Insert(DropNode.Index + 1, DragNode)
DragNode.Tag = "N"
DragNode.ImageIndex = 5
DragNode.SelectedImageIndex = 5
DropNode.Expand()
Else
DropNode.Parent.Nodes.Insert(DropNode.Index + 1, DragNode)
DragNode.Tag = "N"
DragNode.ImageIndex = 5
DragNode.SelectedImageIndex = 5
DropNode.Expand()
End If
我们还已将节点的 ImageIndex
和 SelectedImageIndex
属性设置为“5”,以便在选中或未选中模式下,文件夹图标都不会出现在它们前面。
现在,该项已成功放置在目标文件夹下。剩余的任务是反映 ListBox 中相应项的正确项路径。我们使用 UpdateListItem
方法将文件夹路径附加到 ListBox 中作为父级的相应项。
新建文件夹按钮
我们可以使用“新建文件夹”按钮在“Country”文件夹下添加新节点。我们在“新建文件夹”按钮的 Click
事件中编写了以下代码行。为了确保文件夹仅在文件夹节点下创建,我们检查所选节点的 Tag
属性。如果它是“Y”,则该节点有资格充当其他节点的父节点。
'Make sure the folder is being created under folder node only
If trvCntry.SelectedNode.Tag = "Y" Then
SubFolder = New TreeNode()
'If node selected is the last node
If IsNothing(trvCntry.SelectedNode.LastNode) Then
trvCntry.SelectedNode.Nodes.Insert(
trvCntry.SelectedNode.Index + 1, SubFolder)
trvCntry.SelectedNode.Expand()
Else
trvCntry.SelectedNode.Nodes.Insert(
trvCntry.SelectedNode.LastNode.Index + 1, SubFolder)
trvCntry.SelectedNode.Expand()
End If
SubFolder.Tag = "Y"
SubFolder.ImageIndex = 0
SubFolder.Text = "NewFolder"
trvCntry.SelectedNode = SubFolder
trvCntry.LabelEdit = True
trvCntry.SelectedNode.BeginEdit()
SubFolder.NodeFont = mFnt
End If
删除文件夹按钮
“删除文件夹”按钮允许我们删除一个文件夹,从而刷新该文件夹下的任何其他项(即,它们的颜色从黑色变为蓝色)在 ListBox
中。如下面的代码片段所示,不允许用户删除“Country”文件夹。
If trvCntry.SelectedNode.Text = "Country" Then
Exit Sub
End If
If trvCntry.SelectedNode.Tag = "Y" Then
DeleteItems(trvCntry.SelectedNode)
trvCntry.SelectedNode.Remove()
End If
现在,为了刷新要删除的文件夹下的项,我们调用 DeleteItems()
方法
'*****************************************************
' Function Name : DeleteItems
' Purpose : This Subroutine Deletes
' The item From the Treeview
' Input : Treenode
' Output : Nothing
' Author : Ujwal Watgule
' Date : 11th May 2006
'*****************************************************
Private Sub DeleteItems(ByVal mNode As TreeNode)
Dim aNode As TreeNode
Try
For Each aNode In mNode.Nodes
DeleteItems(aNode)
RefreshList(aNode.Text)
Next
Catch ex As Exception
Throw ex
End Try
End Sub
DeleteItems()
方法又调用 RefreshList
方法,如下所示
'*********************************************************
' Function Name : RefreshList
' Purpose : This Subroutine Refreshes The Listbox
' Input : Items Name
' Output : Nothing
' Author : Ujwal Watgule
' Date : 11th May 2006
'*********************************************************
Private Sub RefreshList(ByVal mItem As String)
Dim strRefreshListItem As String
Dim strChkItem As String
Dim intCntr, icntr As Integer
Try
For intCntr = 0 To lstCust.Items.Count - 1
strRefreshListItem = lstCust.Items(intCntr)
For icntr = 0 To strRefreshListItem.Length - 1
If mItem = strRefreshListItem.Substring(0, icntr) Then
strChkItem = mItem
lstCust.Items.RemoveAt(intCntr)
lstCust.Items.Insert(intCntr, (strChkItem))
lstCust.Refresh()
Exit For
End If
Next
Next
Catch ex As Exception
Throw ex
End Try
End Sub
结论
在本文中,我们了解了 ListBox
和 TreeView
在拖放操作中参与的事件。我们还看到了如何在 TreeView
中创建新文件夹以及删除文件夹的步骤。在我的下一篇文章中,我们将学习如何将树形结构保存在数据库中并在运行时进行填充。在此之前,祝您一切顺利。