- Сообщения
- 8,673
- Репутация
- 2,484
Имеется функция/пример для перетаскивания пунктов в ListView:
Но я никак не додумаю, как это заставить работать с более чем одним пунктом. На данный момент в этом примере корректно(?) перетаскивается только один выделенный пункт.
Код:
#include <GUIConstantsEx.au3>
#include <WindowsConstants.au3>
#include <GUIListView.au3>
#include <GUIImageList.au3>
;
Global $iLast_Index = -1
Global $a_Index[2] ;From and to
Global $iLastLineTop, $iLastLineLeft
Global $iDragging = False
Global $iDrawing = False ;To ensure mousemove doesn't cause more than one line to be drawn
Global $iLButtonIsUp = False ;To ensure a correct redraw of ListView
$Main_GUI = GUICreate("Drag & Drop LV Item", 225, 400, -1, -1, BitOR($WS_THICKFRAME, $WS_SIZEBOX))
$ListView = GUICtrlCreateListView("Entry Name|Category", 5, 75, 195, 280, 0)
$h_ListView = GUICtrlGetHandle($ListView)
_GUICtrlListView_SetColumnWidth($ListView, 0, 100)
_GUICtrlListView_SetColumnWidth($ListView, 1, 90)
$nExStyle = BitOR($LVS_EX_GRIDLINES, $LVS_EX_FULLROWSELECT, $LVS_EX_SUBITEMIMAGES, $LVS_EX_CHECKBOXES)
GUICtrlSendMsg($ListView, $LVM_SETEXTENDEDLISTVIEWSTYLE, $nExStyle, $nExStyle)
$h_ImageList = _GUIImageList_Create(16, 16, 5, 1)
For $i = 0 To 10
_GUIImageList_AddIcon($h_ImageList, @SystemDir & "\shell32.dll", $i)
Next
_GUICtrlListView_SetImageList($h_ListView, $h_ImageList, $LVSIL_SMALL)
For $i = 0 To 9
GUICtrlCreateListViewItem("Name " & $i & "|Category " & $i, $ListView)
_GUICtrlListView_SetItemImage($h_ListView, $i, $i, 0); listview handle, index, subitem, image index
Next
GUISetState()
GUIRegisterMsg($WM_NOTIFY, "WM_NOTIFY_EVENTS")
GUIRegisterMsg($WM_LBUTTONUP, "WM_LBUTTONUP_EVENTS")
GUIRegisterMsg($WM_MOUSEMOVE, "WM_MOUSEMOVE_EVENTS")
While 1
Switch GUIGetMsg()
Case $GUI_EVENT_CLOSE
_GUIImageList_Destroy($h_ImageList)
Exit
EndSwitch
If $iLButtonIsUp Then
$iLButtonIsUp = False
DllCall("User32.dll", "int", "RedrawWindow", "hwnd", $h_ListView, "ptr", 0, "int", 0, "int", 5)
EndIf
WEnd
Func WM_LBUTTONUP_EVENTS($hWndGUI, $MsgID, $wParam, $lParam)
$iLButtonIsUp = True
$iDragging = False
$iDrawing = False
$iLast_Index = -1
Local $aLV_Pos = ControlGetPos($hWndGUI, "", $ListView)
Local $iX = BitAND($lParam, 0xFFFF) - $aLV_Pos[0]
Local $iY = BitShift($lParam, 16) - $aLV_Pos[1]
Local $struct_LVHITTESTINFO = DllStructCreate("int;int;uint;int;int;int")
DllStructSetData($struct_LVHITTESTINFO, 1, $iX)
DllStructSetData($struct_LVHITTESTINFO, 2, $iY)
$a_Index[1] = GUICtrlSendMsg($ListView, $LVM_HITTEST, 0, DllStructGetPtr($struct_LVHITTESTINFO))
Local $iFlags = DllStructGetData($struct_LVHITTESTINFO, 2)
;// Out of the ListView?
If $a_Index[1] = -1 Then $a_Index[1] = _GUICtrlListView_GetItemCount($h_ListView) ;Return $GUI_RUNDEFMSG
;// Not in an item?
;If BitAND($iFlags, $LVHT_ONITEMLABEL) = 0 And BitAND($iFlags, $LVHT_ONITEMSTATEICON) = 0 Then Return $GUI_RUNDEFMSG
If $a_Index[0] < $a_Index[1] Then
_GUICtrlListView_CopyItemsEx($h_ListView, $h_ListView, $a_Index[1] - 1, 1)
ElseIf $a_Index[0] > $a_Index[1] Then
_GUICtrlListView_CopyItemsEx($h_ListView, $h_ListView, $a_Index[1], 1)
EndIf
Return $GUI_RUNDEFMSG
EndFunc ;==>WM_LBUTTONUP_EVENTS
Func WM_MOUSEMOVE_EVENTS($hWndGUI, $MsgID, $wParam, $lParam)
If Not $iDragging Or $iDrawing Then Return $GUI_RUNDEFMSG
Local $aLV_Pos = ControlGetPos($hWndGUI, "", $ListView)
Local $iX = BitAND($lParam, 0xFFFF) - $aLV_Pos[0]
Local $iY = BitShift($lParam, 16) - $aLV_Pos[1]
Local $struct_LVHITTESTINFO = DllStructCreate("int;int;uint;int;int;int")
DllStructSetData($struct_LVHITTESTINFO, 1, $iX)
DllStructSetData($struct_LVHITTESTINFO, 2, $iY)
Local $iItem = GUICtrlSendMsg($ListView, $LVM_HITTEST, 0, DllStructGetPtr($struct_LVHITTESTINFO))
If $iItem = -1 Then $iItem = _GUICtrlListView_GetItemCount($h_ListView) ;Return $GUI_RUNDEFMSG
If $iLast_Index = $iItem Then Return $GUI_RUNDEFMSG
If $iLast_Index > $iItem Then ;Move up
_GUICtrlListView_RedrawItems($h_ListView, $iItem, $iLast_Index)
Else
_GUICtrlListView_RedrawItems($h_ListView, $iLast_Index, $iItem - 1)
EndIf
$iLast_Index = $iItem
Local $aLV_Pos = ControlGetPos($hWndGUI, "", $ListView)
Local $iY = _GUICtrlListView_GetItemPositionY($h_ListView, $iItem)
If $iY <= 0 Then Return $GUI_RUNDEFMSG
_DrawLine($aLV_Pos[0], $iY, $aLV_Pos[2], 2.5, 0x000000, $h_ListView)
EndFunc ;==>WM_MOUSEMOVE_EVENTS
Func WM_NOTIFY_EVENTS($hWndGUI, $MsgID, $wParam, $lParam)
Local $tagNMHDR, $iEvent, $hwndFrom, $iCode, $iItem
$tagNMHDR = DllStructCreate("int;int;int;int", $lParam) ;NMHDR (hwndFrom, idFrom, code, Item)
If @error Then Return $GUI_RUNDEFMSG
$iCode = DllStructGetData($tagNMHDR, 3)
$iItem = DllStructGetData($tagNMHDR, 4)
Switch $wParam
Case $ListView
Switch $iCode
Case $LVN_BEGINDRAG
$a_Index[0] = $iItem
$iDragging = True
;_GUICtrlListView_SetItemSelected($ListView, $iItem, False)
EndSwitch
EndSwitch
Return $GUI_RUNDEFMSG
EndFunc ;==>WM_NOTIFY_EVENTS
;A try to make a multiple selection support for moved items
Func _GUICtrlListView_CopyItemsEx($hWnd_Source, $hWnd_Destination, $iDstIndex, $fDelFlag = False)
Local $a_indices, $tItem = DllStructCreate($tagLVITEM), $iIndex
Local $cols = _GUICtrlListView_GetColumnCount($hWnd_Source)
Local $items = _GUICtrlListView_GetItemCount($hWnd_Source)
_GUICtrlListView_BeginUpdate($hWnd_Source)
_GUICtrlListView_BeginUpdate($hWnd_Destination)
If BitAND(_GUICtrlListView_GetExtendedListViewStyle($hWnd_Source), $LVS_EX_CHECKBOXES) == $LVS_EX_CHECKBOXES Then
For $i = 0 To $items - 1
If _GUICtrlListView_GetItemChecked($hWnd_Source, $i) Then
If IsArray($a_indices) Then
ReDim $a_indices[UBound($a_indices) + 1]
Else
Local $a_indices[2]
EndIf
$a_indices[0] = $a_indices[0] + 1
$a_indices[UBound($a_indices) - 1] = $i
EndIf
Next
If UBound($a_indices) > 1 Then
For $i = 1 To $a_indices[0]
DllStructSetData($tItem, "Mask", BitOR($LVIF_GROUPID, $LVIF_IMAGE, $LVIF_INDENT, $LVIF_PARAM, $LVIF_STATE))
DllStructSetData($tItem, "Item", $a_indices[$i])
DllStructSetData($tItem, "SubItem", 0)
DllStructSetData($tItem, "StateMask", -1)
_GUICtrlListView_GetItemEx($hWnd_Source, $tItem)
$iIndex = _GUICtrlListView_InsertItem($hWnd_Destination, _
_GUICtrlListView_GetItemText($hWnd_Source, $a_indices[$i], 0), $iDstIndex, DllStructGetData($tItem, "Image"))
_GUICtrlListView_SetItemChecked($hWnd_Destination, $iIndex)
$iDstIndex += 1
For $x = 1 To $cols - 1
DllStructSetData($tItem, "Item", $a_indices[$i])
DllStructSetData($tItem, "SubItem", $x)
_GUICtrlListView_GetItemEx($hWnd_Source, $tItem)
_GUICtrlListView_AddSubItem($hWnd_Destination, $iIndex, _
_GUICtrlListView_GetItemText($hWnd_Source, $a_indices[$i], $x), $x, DllStructGetData($tItem, "Image"))
Next
_GUICtrlListView_SetItemSelected($hWnd_Source, $iIndex, True)
Next
If $fDelFlag Then
For $i = $a_indices[0] To 1 Step -1
_GUICtrlListView_DeleteItem($hWnd_Source, $a_indices[$i])
Next
EndIf
EndIf
EndIf
If _GUICtrlListView_GetSelectedCount($hWnd_Source) Then
$a_indices = _GUICtrlListView_GetSelectedIndices($hWnd_Source, 1)
For $i = 1 To $a_indices[0]
$i_Index = $a_indices[$i]
DllStructSetData($tItem, "Mask", BitOR($LVIF_GROUPID, $LVIF_IMAGE, $LVIF_INDENT, $LVIF_PARAM, $LVIF_STATE))
DllStructSetData($tItem, "Item", $i_Index)
DllStructSetData($tItem, "SubItem", 0)
DllStructSetData($tItem, "StateMask", -1)
_GUICtrlListView_GetItemEx($hWnd_Source, $tItem)
$iIndex = _GUICtrlListView_InsertItem($hWnd_Destination, _
_GUICtrlListView_GetItemText($hWnd_Source, $i_Index, 0), $iDstIndex, DllStructGetData($tItem, "Image"))
$iDstIndex += 1
For $x = 1 To $cols - 1
DllStructSetData($tItem, "Item", $i_Index)
DllStructSetData($tItem, "SubItem", $x)
_GUICtrlListView_GetItemEx($hWnd_Source, $tItem)
_GUICtrlListView_AddSubItem($hWnd_Destination, $iIndex, _
_GUICtrlListView_GetItemText($hWnd_Source, $i_Index, $x), $x, DllStructGetData($tItem, "Image"))
Next
_GUICtrlListView_SetItemSelected($hWnd_Source, $iIndex, True)
Next
If $fDelFlag Then
For $i = $a_indices[0] To 1 Step -1
_GUICtrlListView_DeleteItem($hWnd_Source, $a_indices[$i])
Next
EndIf
EndIf
_GUICtrlListView_EndUpdate($hWnd_Source)
_GUICtrlListView_EndUpdate($hWnd_Destination)
EndFunc
Func _DrawLine($iLeft, $iTop, $iWidth, $iHeight, $sColor, $hWnd = 0)
$iDrawing = True
$sColor = Hex("0x" & BitAND(BitShift(String(Binary($sColor)), 8), 0xFFFFFF)) ;RGB2BGR
Local $hDC = DllCall("User32.dll", "int", "GetDC", "hwnd", $hWnd)
Local $aPen = DllCall("GDI32.dll", "int", "CreatePen", "int", 0, "int", $iHeight, "int", $sColor)
DllCall("GDI32.dll", "int", "SelectObject", "int", $hDC[0], "int", $aPen[0])
If $iLastLineTop > -1 And $iLastLineLeft > -1 Then
If $iLastLineTop <> $iTop Then ; or $iLastLineLeft <> $iLeft Then
;Local $strRect = DllStructCreate("int[4]")
;DllStructSetData($strRect, 1, 5)
;DllStructSetData($strRect, 2, 75)
;DllStructSetData($strRect, 3, 198 + 5)
;DllStructSetData($strRect, 4, 280 + 75)
;Local $pRect = DllStructGetPtr($strRect)
$iLastLineLeft = $iLeft
$iLastLineTop = $iTop
DllCall("user32.dll", "int", "InvalidateRect", "hwnd", $hWnd, "int", 0, "int", 1)
Sleep(10) ;seems to be needed to ensure redrawn before line is drawn
EndIf
EndIf
DllCall("GDI32.dll", "int", "MoveToEx", "hwnd", $hDC[0], "int", $iLeft, "int", $iTop, "int", 0)
DllCall("GDI32.dll", "int", "LineTo", "hwnd", $hDC[0], "int", $iLeft + $iWidth, "int", $iTop)
DllCall("user32.dll", "int", "ReleaseDC", "hwnd", $hWnd, "int", $hDC[0])
DllCall("GDI32.dll", "int", "DeleteObject", "int", $aPen[0])
$iDrawing = False
EndFunc ;==>_DrawLine
Но я никак не додумаю, как это заставить работать с более чем одним пунктом. На данный момент в этом примере корректно(?) перетаскивается только один выделенный пункт.