我正在尝试将ListView控件用于拖放事件。我想将项目从位置1拖到其他位置...例如,位置5(没有子项目)。但是当我这样做时,它什么也没做。但是,实际上,当我单步执行代码时,remove
方法会删除该项目。但是它直接放回原处,因此看起来什么也没做。我需要根据here添加API,因为它总是将其放在第一位。
在研究和添加API(我认为是问题)之前,我从here获得了代码,并尝试根据自己的特定需求对其进行定制,但是我无法使其正常工作。我正在运行32位Excel。
全局常量和句柄
'Windows API Constants
Public Const LOGPIXELSX = 88
Public Const LOGPIXELSY = 90
'Windows API Function Declarations
'Get a handle to the Device Context (a drawing layer) for a window
Public Declare Function GetDC Lib "user32" (ByVal hWnd As Long) As Long
'Get the capabilities of a device, from its Device Context
Public Declare Function GetDeviceCaps Lib "gdi32" (ByVal hDC As Long, _
ByVal nIndex As Long) As Long
'Release the handle to the Device Context, to tidy up
Public Declare Function ReleaseDC Lib "user32" (ByVal hWnd As Long, _
ByVal hDC As Long) As Long
拖放事件
Private Sub lvSortableColumn_OLEDragDrop(Data As MSComctlLib.DataObject, Effect As Long, Button As Integer, Shift As Integer, x As Single, y As Single)
Dim item As MSComctlLib.ListItem
Dim lngXPixelsPerInch As Long, lngYPixelsPerInch As Long
Dim lngDeviceHandle As Long
'We must determine the Pixels per Inch for the display device.
lngDeviceHandle = GetDC(0)
lngXPixelsPerInch = GetDeviceCaps(lngDeviceHandle, LOGPIXELSX)
lngYPixelsPerInch = GetDeviceCaps(lngDeviceHandle, LOGPIXELSY)
ReleaseDC 0, lngDeviceHandle
LVDragDropSingle lvSortableColumn, x * 1440 / lngXPixelsPerInch, y * 1440 / lngYPixelsPerInch
End Sub
过程
Public Sub LVDragDropSingle(ByRef lvList As ListView, ByVal x As Single, ByVal y As Single)
'Item being dropped
Dim objDrag As ListItem
'Item being dropped on
Dim objDrop As ListItem
'Item being readded to the list
Dim objNew As ListItem
'Drop position
Dim intIndex As Integer
'Retrieve the original items
Set objDrop = lvList.HitTest(x, y)
Set objDrag = lvList.SelectedItem
If (objDrop Is Nothing) Or (objDrag Is Nothing) Then
Set lvList.DropHighlight = Nothing
Set objDrop = Nothing
Set objDrag = Nothing
Exit Sub
End If
'Retrieve the drop position
intIndex = objDrop.Index
'Remove the dragged item
lvList.ListItems.Remove objDrag.Index
'Add it back into the dropped position
'Seems to fail on this line*****
Set objNew = lvList.ListItems.Add(intIndex, objDrag.Key, objDrag.Text) ', objDrag.Icon, objDrag.SmallIcon)
'Reselect the item
objNew.Selected = True
'Destroy all objects
Set objNew = Nothing
Set objDrag = Nothing
Set objDrop = Nothing
Set lvList.DropHighlight = Nothing
End Sub
编辑
在我的赏金用尽之前,可能需要另外提供一条信息。如果在其中一个事件中停止,我会注意到当我拖动一个项目时,它会立即突出显示第一个项目。我认为这可能就是为什么它不起作用的原因。它在其他用户窗体上的其他ListView中执行相同的操作。例如,如果最终用户单击某个项目,则该项目将突出显示。但是,如果他直接检查复选框而不单击实际项目,则会突出显示一个随机项目(通常是同一项目)。 VBA中的ListView控件有一些非常奇怪的行为(在线上有些人指出)。
答案 0 :(得分:0)
@Brian我使您的代码以某种粗略的方式工作
首先将Set objNew = lvList.ListItems.Add(intIndex, objDrag.Key, objDrag.Text)
更改为lvList.ListItems.Add intIndex, objDrag.Key, objDrag.Text
使其生效。最后还添加了LvList.refresh
。
然后将X和Y乘以15,使drophighlight
以某种粗略的方式工作。
我还用了(20个要点来表示)
Xp = Application.ActiveWindow.PointsToScreenPixelsX(X * 20)
Yp = Application.ActiveWindow.PointsToScreenPixelsY(Y * 20)
,并将Xp和Yp用于HitTest。它给出了更接近的结果(但仍然不完全是)。 Xp和Yp并未声明,仅用作变体。声明Xp Yp为single将会停止转换结果为0,因为hittest X Y为single并且PointstoScreen
为Long。 Csng()
无法正常工作。我的显示器是1366 X 768。
以下是我的观察(程序中仍未使用)
我成功使用Private Declare Function GetSystemMetrics Lib "user32" (ByVal whichMetric As Long) As Long
来获取监视器宽度等。无法使gdi32正常工作。
Xw = Application.ActiveWindow.UsableWidth
Yh = Application.ActiveWindow.UsableHeight
带入1009.5和399。不知道什么是单位
Edit2:我忘记提及了,我直接在OLEDragDrop事件中使用了您的过程代码。我还使用了OLEDragOver事件
Xp = Application.ActiveWindow.PointsToScreenPixelsX(X * 20)
Yp = Application.ActiveWindow.PointsToScreenPixelsY(Y * 20)
Set lvList.DropHighlight = lvList.HitTest(Xp, Yp)
If lvList.DropHighlight Is Nothing Then
Set lvList.DropHighlight = lvList.ListItems(lvList.ListItems.Count)
End If