ListView控件拖放

时间:2018-10-08 14:46:51

标签: excel vba excel-vba

我正在尝试将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控件有一些非常奇怪的行为(在线上有些人指出)。

1 个答案:

答案 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