哇!经过几天的玩耍和研究,我自己找到了答案。这里是为其他可能有同样问题的人准备的。
首先,几个重要的注意事项:
1)。您必须为 TreeView 和 ListView 设置以下 OLE 属性。
TreeView1.OLEDragMode = 1 'Automatic
ListView1.OLEDropMode = 1 'Manual
2)。为了从 TreeView 中确定选中的节点,必须在 MouseDown 事件期间使用 HitTest 方法。
这导致了我的大部分问题,因为我无法让它为我提供正确的选定节点,然后知道哪些数据要添加到我的 ListView。
要确定选定的节点,请使用 TreeView.SelectedItem 属性。奇怪的是,除非您在 MouseDown 事件期间设置它,否则 VB 将始终认为您先前选择的项目是当前选择的项目,并将错误的数据添加到 ListView。为什么?
TreeView.SelectedItem 由 MouseUp 事件决定。例如,如果您在“节点 1”上完全单击并释放鼠标,则 MouseDown 和 MouseUp 事件都会触发,并且 MouseUp 事件会将 TreeView.SelectedItem 设置为“节点 1”。然后,如果您在“节点 2”上单击并按住鼠标按钮,然后立即开始拖动(不释放鼠标按钮),则只会触发 MouseDown 事件。由于 MouseUp 事件永远不会触发,因此即使您拖动“节点 2”,TreeView.SelectedItem 属性也会保持为“节点 1”。因此,当您稍后尝试使用 SelectedItem 属性来确定要添加到目标 ListView(在我的情况下)的内容时,它会得到错误的数据。
3)。在 MouseDown 事件期间使用 HitTest 方法时,必须将像素转换为 TWIPS。
MouseDown 方法返回以像素为单位的 x-y 坐标,但是,在 VBA 中,HitTest 方法使用 TWIPS(显然 .NET 现在使用像素,因此在那里不需要转换)。因此,为了确定正确的节点,您必须对其进行转换。我读到的几乎所有 Windows 计算机都有 15 比 1 的比例,因此您可以简单地使用以下内容:
Set TreeView1.SelectedItem = TreeView1.HitTest(x * 15, y * 15)
但是,如果您不想冒险让 15 比 1 的比率适用于所有 Windows 计算机,您可以使用我在下面演示的 Windows API 调用来计算它。
这是代码的精简版。
注意,我通过使用“自动”拖动属性和设置来保持简单,因此我不必使用“数据对象”方法来设置光标、确定拖动效果等...我是只使用默认值并保持简单。
Private Sub TreeView1_MouseDown(ByVal Button As Integer, ByVal Shift As Integer, ByVal x As stdole.OLE_XPOS_PIXELS, ByVal y As stdole.OLE_YPOS_PIXELS)
Set TreeView1.SelectedItem = Nothing
If TreeView1.SelectedItem Is Nothing Then
Set TreeView1.SelectedItem = TreeView1.HitTest(x * 15, y * 15)
End If
End Sub
Private Sub TreeView1_OLEStartDrag(Data As MSComctlLib.DataObject, AllowedEffects As Long)
Data.SetData TreeView1.SelectedItem.Text, 1
End Sub
Private Sub ListView1_OLEDragDrop(Data As MSComctlLib.DataObject, Effect As Long, Button As Integer, Shift As Integer, x As Single, y As Single)
ListView1.ListItems.Add ListView1.ListItems.Count + 1, , Data.GetData(1)
End Sub
就是这样!
您应该能够从那里获取它以添加您想要的任何其他功能。下面,我给出了更多的选择。
备选方案 1 - 赋予高光效果
可以使用另一种方法为用户提供在选择之前突出显示树节点的视觉效果。 (注意:您也可以在 TreeView OLEDragOver 事件期间执行此操作,但我使用的是 MouseMove 事件)
Private Sub TreeView1_MouseMove(ByVal Button As Integer, ByVal Shift As Integer, ByVal x As stdole.OLE_XPOS_PIXELS, ByVal y As stdole.OLE_YPOS_PIXELS)
If Not (TreeView1.HitTest(x * TwipsPerPixelX, y * TwipsPerPixelY) Is Nothing) Then
Dim MyNode As Node
Set MyNode = TreeView1.HitTest(x * 15, y * 15)
MyNode.Selected = True
Set MyNode = Nothing
End If
End Sub
Private Sub TreeView1_OLEStartDrag(Data As MSComctlLib.DataObject, AllowedEffects As Long)
Data.SetData TreeView1.SelectedItem.Text, 1
End Sub
Private Sub ListView1_OLEDragDrop(Data As MSComctlLib.DataObject, Effect As Long, Button As Integer, Shift As Integer, x As Single, y As Single)
ListView1.ListItems.Add ListView1.ListItems.Count + 1, , Data.GetData(1)
End Sub
备选方案 2 - 计算像素到 TWIPS 的转换
请记住,这仅在 VBA 中需要。您不需要在 .NET 中执行此操作,因为我相信它在 Event 和 HitTest 方法中都使用像素。
而不是像上面那样明确地将转换声明为 15:
Set MyNode = TreeView1.HitTest(x * 15, y * 15)
您可以结合使用 Windows API 调用和您自己的函数来计算它。方法如下。
首先,将Windows API调用和用户定义函数放在Module1中:
Public Declare Function GetDesktopWindow Lib "user32" () As Long
Public Declare Function GetDC Lib "user32" (ByVal hwnd As Long) As Long
Public Declare Function GetDeviceCaps Lib "gdi32" (ByVal hdc As Long, ByVal nIndex As Long) As Long
Public Declare Function ReleaseDC Lib "user32" (ByVal hwnd As Long, ByVal hdc As Long) As Long
Const LOGPIXELSX = 88
Const LOGPIXELSY = 90
Public Function TwipsPerPixelX() As Integer
Dim MyDesktopWindowHandle As Long, MyDesktopWindowDeviceContext As Long
Dim MyWidthOfScreen As Long, MyUsedToReleaseDeviceContext As Long
'Get the handle of the desktop window
MyDesktopWindowHandle = GetDesktopWindow()
'Get the desktop window's device context
MyDesktopWindowDeviceContext = GetDC(MyDesktopWindowHandle)
'Get the width of the screen
MyWidthOfScreen = GetDeviceCaps(MyDesktopWindowDeviceContext, LOGPIXELSX)
'Release the device context
MyUsedToReleaseDeviceContext = ReleaseDC(MyDesktopWindowHandle, MyDesktopWindowDeviceContext)
TwipsPerPixelX = 1440 / MyWidthOfScreen '1 inch is always 1440 twips
End Function
Public Function TwipsPerPixelY() As Integer
Dim MyDesktopWindowHandle As Long, MyDesktopWindowDeviceContext As Long
Dim MyHeightOfScreen As Long, MyUsedToReleaseDeviceContext As Long
'Get the handle of the desktop window
MyDesktopWindowHandle = GetDesktopWindow()
'Get the desktop window's device context
MyDesktopWindowDeviceContext = GetDC(MyDesktopWindowHandle)
'Get the width of the screen
MyHeightOfScreen = GetDeviceCaps(MyDesktopWindowDeviceContext, LOGPIXELSY)
'Release the device context
MyUsedToReleaseDeviceContext = ReleaseDC(MyDesktopWindowHandle, MyDesktopWindowDeviceContext)
TwipsPerPixelY = 1440 / MyHeightOfScreen '1 inch is always 1440 twips
End Function
然后将代码的HitTest部分改成如下:
Set TreeView1.SelectedItem = TreeView1.HitTest(x * TwipsPerPixelX, y * TwipsPerPixelY)
希望有帮助!
参考资料:
以下是帮助将其拼凑起来的参考资料,我必须在应得的地方给予表扬。
Creating a 'mouse over' effect on a VB TreeView node
http://forums.ni.com/t5/facebookforums/facebooksingletopicpage/facebook-app/417075545007603/message-uid/78682/tab/board/page/4806
http://vbcity.com/forums/t/49091.aspx
http://www.experts-exchange.com/questions/20497792/TwipsPerPixelX-Y-via-the-API-for-VBA.html