Что нового

ListView Перемещение строк Drag-and-drop

pvnn

Осваивающий
Сообщения
305
Репутация
32
Всем доброго времени суток.
Сделал Drag-and-drop так:
1. Начало Drag&Drop отслеживаю в сообщении WM_NOTIFY, LVN_BEGINDRAG
2. Там же (LVN_BEGINDRAG) отслеживаю отжатие левой кнопки мыши
3. Определяю выделенную строку и делаю перемещение
Работает - перемещает строку выше указанной мышкой строки
Но это как-то "топорно" выглядит
Хотелось бы при зажатой кнопки мыши и перемещению по ListView видеть полоску разделителя и вставлять строку именно туда.
Как это можно реализовать?

Код:
#include <GUIConstantsEx.au3>
#include <WindowsConstants.au3>
#include <GuiListView.au3>
#include <Misc.au3>
#include <Array.au3>
#include <GuiImageList.au3>

Global $aItems[0]
Global $AlertDrag=0, $IndexDragItem=-1
AutoItSetOption ('MouseCoordMode',2)

$Form1 = GUICreate("Form1", 420, 449, 192, 114)
; ListView
 $hListView = GUICtrlCreateListView("", 10, 30, 400, 410, BitOR($LVS_REPORT,$LVS_SHOWSELALWAYS))
 _GUICtrlListView_SetExtendedListViewStyle($hListView, BitOR($LVS_EX_GRIDLINES, $LVS_EX_FULLROWSELECT))
_GUICtrlListView_AddColumn($hListView, "Название",400)
 	For $i=1 To 10
		_ArrayAdd($aItems,'Название '&$i)
	Next
; Заполнить ListView
FillListView()

GUIRegisterMsg($WM_NOTIFY, "WM_NOTIFY")
GUISetState(@SW_SHOW)


While 1
	Alert()
	$nMsg = GUIGetMsg()
	Switch $nMsg
		Case $GUI_EVENT_CLOSE
			Exit

	EndSwitch
WEnd

; Заполнить ListView
Func FillListView()
	_GUICtrlListView_DeleteAllItems($hListView) ; Удалить все строки
 	For $i=0 To UBound($aItems)-1
		GUICtrlCreateListViewItem($aItems[$i], $hListView)
	Next
EndFunc


Func Alert()
	; Если Drag&Drop
	If $AlertDrag<>0 Then
		$IndexListView=Number(_GUICtrlListView_GetSelectedIndices($hListView)) ; Индекс выделенных строк
		If $IndexListView<>$IndexDragItem Then
			$Text=_GUICtrlListView_GetItemText($hListView,$IndexListView)
			If $IndexDragItem =-1 Then
				ConsoleWrite(@CRLF&' выделен: '&$IndexListView&' заменить индекс: '&$IndexDragItem)
				_ArrayAdd($aItems,$Text)
				_ArrayDelete($aItems,$IndexListView)
			ElseIf 	$IndexListView=0 And $IndexDragItem=1 Then
				_ArraySwap($aItems,0,1)
			ElseIf 	$IndexListView>$IndexDragItem Then
				_ArrayDelete($aItems,$IndexListView)
				_ArrayInsert($aItems,$IndexDragItem, $Text )
			Else
				ConsoleWrite(@CRLF&' выделен: '&$IndexListView&' заменить индекс: '&$IndexDragItem)
				_ArrayInsert($aItems,$IndexDragItem, $Text )
				_ArrayDelete($aItems,$IndexListView)
			EndIf
			FillListView()
		EndIf
;~ 					ConsoleWrite(@CRLF&'Отпуск')
		$AlertDrag=0
		Return
	EndIf
EndFunc


Func WM_NOTIFY($hWnd, $iMsg, $iwParam, $ilParam)
 Local $hWndFrom,  $iCode, $tNMHDR, $hWndListView, $tInfo

    $hWndListView = $hListView
    If Not IsHWnd($hListView) Then $hWndListView = GUICtrlGetHandle($hListView)

    $tNMHDR = DllStructCreate($tagNMHDR, $ilParam)
    $hWndFrom = HWnd(DllStructGetData($tNMHDR, "hWndFrom"))
    $iCode = DllStructGetData($tNMHDR, "Code")
    $tInfo = DllStructCreate($tagNMITEMACTIVATE, $ilParam)
    $iIndex = DllStructGetData($tInfo, "Index")

    Switch $hWndFrom
		; ListView
        Case $hWndListView
            Switch $iCode
				Case $LVN_HOTTRACK ; Перемещение мыши
					$aMousePos=MouseGetPos()
					$aItem=_GUICtrlListView_SubItemHitTest($hListView,$aMousePos[0],$aMousePos[1]-30)
					If Not @error Then ConsoleWrite(@CRLF&$aMousePos[0]&'x'&$aMousePos[1]&' Индекс строки = '&$aItem[0])

				Case $LVN_BEGINDRAG
					; Отследить отжатие левой клавиши мыши
			        While _IsPressed('01')
						Sleep(5)
					WEnd
					$IndexDragItem=_GUICtrlListView_GetHotItem($hListView)
					$AlertDrag=1
			EndSwitch
	EndSwitch
	Return $GUI_RUNDEFMSG
EndFunc
 

joiner

Модератор
Локальный модератор
Сообщения
3,556
Репутация
628
Код:
#include <GUIConstantsEx.au3>
#include <WindowsConstants.au3>
#include <GuiListView.au3>
#include <Misc.au3>
#include <Array.au3>
#include <GuiImageList.au3>

Global $aItems[0], $flDG, $tmpS = -1, $textDG = ''
Global $AlertDrag = 0, $IndexDragItem = -1
AutoItSetOption('MouseCoordMode', 2)

$Form1 = GUICreate("Form1", 420, 449, 192, 114)
; ListView
Global $hListView = GUICtrlCreateListView("", 10, 30, 400, 410, BitOR($LVS_REPORT, $LVS_SHOWSELALWAYS))
_GUICtrlListView_SetExtendedListViewStyle($hListView, BitOR($LVS_EX_GRIDLINES, $LVS_EX_FULLROWSELECT))
_GUICtrlListView_AddColumn($hListView, "Название", 400)
For $i = 1 To 10
	_ArrayAdd($aItems, 'Название ' & $i)
Next
; Заполнить ListView
FillListView()

GUIRegisterMsg($WM_NOTIFY, "WM_NOTIFY")
GUISetState(@SW_SHOW)

Local $aMousePos, $aItem
While 1
	If $flDG Then
		$flDG = 0
		While _IsPressed('01')
			Sleep(5)
			$aMousePos = MouseGetPos()
			$aItem = _GUICtrlListView_SubItemHitTest($hListView, $aMousePos[0], $aMousePos[1] - 30)
			If $aItem[0] = $tmpS And $aItem[0] > -1 Then
				ContinueLoop
			ElseIf $aItem[0] <> $tmpS And $aItem[0] > -1 Then
				_GUICtrlListView_SetItemSelected($hListView, $tmpS, 0, 0)
				_GUICtrlListView_SetItemSelected($hListView, $aItem[0], 1, 1)
			EndIf
			$tmpS = $aItem[0]
		WEnd
		Alert()
	EndIf
	$nMsg = GUIGetMsg()
	Switch $nMsg
		Case $GUI_EVENT_CLOSE
			Exit

	EndSwitch
WEnd

; Заполнить ListView
Func FillListView()
	_GUICtrlListView_DeleteAllItems($hListView) ; Удалить все строки
	For $i = 0 To UBound($aItems) - 1
		GUICtrlCreateListViewItem($aItems[$i], $hListView)
	Next
EndFunc   ;==>FillListView


Func Alert()
	If $tmpS = -1 Then
		_ArrayDelete($aItems, $IndexDragItem)
		_ArrayAdd($aItems, $textDG)
	Else
		If Number($tmpS - $IndexDragItem) = 1 Then
			_ArraySwap($aItems, $tmpS, $IndexDragItem)
		Else
			_ArrayDelete($aItems, $IndexDragItem)
			_ArrayInsert($aItems, $tmpS, $textDG)
		EndIf
	EndIf
	FillListView()
	$flDG = 0
	$tmpS = -1
	$textDG = ''
	$AlertDrag = 0
	$IndexDragItem = -1
EndFunc   ;==>Alert


Func WM_NOTIFY($hWnd, $iMsg, $iwParam, $ilParam)
	Local $hWndFrom, $iCode, $tNMHDR, $hWndListView, $tInfo, $aMousePos, $aItem

	$hWndListView = $hListView
	If Not IsHWnd($hListView) Then $hWndListView = GUICtrlGetHandle($hListView)

	$tNMHDR = DllStructCreate($tagNMHDR, $ilParam)
	$hWndFrom = HWnd(DllStructGetData($tNMHDR, "hWndFrom"))
	$iCode = DllStructGetData($tNMHDR, "Code")
	$tInfo = DllStructCreate($tagNMITEMACTIVATE, $ilParam)
	$iIndex = DllStructGetData($tInfo, "Index")

	Switch $hWndFrom
		; ListView
		Case $hWndListView
			Switch $iCode
				Case $LVN_HOTTRACK
;~ 					$aMousePos = MouseGetPos()
;~ 					$aItem = _GUICtrlListView_SubItemHitTest($hListView, $aMousePos[0], $aMousePos[1] - 30)
;~ 					If Not @error Then ConsoleWrite(@CRLF & $aMousePos[0] & 'x' & $aMousePos[1] & ' Индекс строки = ' & $aItem[0])

				Case $LVN_BEGINDRAG
					$aMousePos = MouseGetPos()
					$aItem = _GUICtrlListView_SubItemHitTest($hListView, $aMousePos[0], $aMousePos[1] - 30)
					$IndexDragItem = $aItem[0]
					$tmpS = $aItem[0]
					$flDG = 1
					$textDG = _GUICtrlListView_GetItemText($hListView, $aItem[0])
			EndSwitch
	EndSwitch
	Return $GUI_RUNDEFMSG
EndFunc   ;==>WM_NOTIFY
 
Автор
P

pvnn

Осваивающий
Сообщения
305
Репутация
32
Tempo, а как данную UDF подружить с WM_NOTIFY:
Например, помимо drag and drop, я захочу отследить другие события, например нажатие пр.клавиши мыши итд...
Как только я делаю:
Код:
GUIRegisterMsg($WM_NOTIFY, "WM_NOTIFY")

drag and drop перестает работать


Код:
#include <GUIConstantsEx.au3>
#include <WindowsConstants.au3>
#include <GuiListView.au3>
#include <Misc.au3>
#include <Array.au3>
#include <GuiImageList.au3>
#include "GUIListViewEx.au3"

Global $aItems[0]
Global $AlertDrag=0, $IndexDragItem=-1
AutoItSetOption ('MouseCoordMode',2)

$Form1 = GUICreate("Form1", 420, 449, 192, 114)
; ListView
 $hListView = GUICtrlCreateListView("", 10, 30, 400, 410, BitOR($LVS_REPORT,$LVS_SHOWSELALWAYS))
 _GUICtrlListView_SetExtendedListViewStyle($hListView, BitOR($LVS_EX_GRIDLINES, $LVS_EX_FULLROWSELECT))
_GUICtrlListView_AddColumn($hListView, "Название",400)
    For $i=1 To 10
        _ArrayAdd($aItems,'Название '&$i)
    Next
; Заполнить ListView
FillListView()

_GUIListViewEx_MsgRegister()

GUIRegisterMsg($WM_NOTIFY, "WM_NOTIFY")

GUISetState(@SW_SHOW)


While 1
    $nMsg = GUIGetMsg()
    Switch $nMsg
        Case $GUI_EVENT_CLOSE
            Exit

    EndSwitch
WEnd

; Заполнить ListView
Func FillListView()
    _GUICtrlListView_DeleteAllItems($hListView) ; Удалить все строки
    For $i=0 To UBound($aItems)-1
        GUICtrlCreateListViewItem($aItems[$i], $hListView)
    Next
	$Init_Index = _GUIListViewEx_Init($hListView, '', 0, 0xFF0000, True,1) ; Инициализация. Цвет разделителя
EndFunc




Func WM_NOTIFY($hWnd, $iMsg, $iwParam, $ilParam)
 Local $hWndFrom,  $iCode, $tNMHDR, $hWndListView, $tInfo

    $hWndListView = $hListView
    If Not IsHWnd($hListView) Then $hWndListView = GUICtrlGetHandle($hListView)

    $tNMHDR = DllStructCreate($tagNMHDR, $ilParam)
    $hWndFrom = HWnd(DllStructGetData($tNMHDR, "hWndFrom"))
    $iCode = DllStructGetData($tNMHDR, "Code")
    $tInfo = DllStructCreate($tagNMITEMACTIVATE, $ilParam)
    $iIndex = DllStructGetData($tInfo, "Index")

    Switch $hWndFrom
        ; ListView
        Case $hWndListView
            Switch $iCode
				Case $NM_RCLICK
					ConsoleWrite(@CRLF&'test')
            EndSwitch
    EndSwitch
    Return $GUI_RUNDEFMSG
EndFunc
 

Tempo

AutoIT Гуру
Сообщения
616
Репутация
205
pvnn, этот UDF и есть обработчик сообщений так что вам нужно редактировать именно его. Какие именно сообщения он обрабатывает вы можете посмотреть в самой функции _GUIListViewEx_MsgRegister()


Добавлено:
Сообщение автоматически объединено:

Но так как конкретных целей вы не озвучили может быть будет достаточно функций что идут в наборе. Например установить клавишу редактирования можно с помощью _GUIListViewEx_SetEditKey
 
Автор
P

pvnn

Осваивающий
Сообщения
305
Репутация
32
Tempo
Но так как конкретных целей вы не озвучили
Как раз озвучил, как мне отследить нажатие правой клавиши мыши на ListView?
В дальнейшем я хотел повесить контекстное меню через UDF ModernMenuRaw

Получается, что drag and drop работает, но события других элементов на форме я не смогу отследить без правки самой UDF _GUIListViewEx_MsgRegister()?

Хотя вот здесь автор UDF https://www.autoitscript.com/forum/topic/182492-guilistviewex-new-version-22-feb-18/?page=6 говорит:
do not register $WM_NOTIFY using the UDF function (set the relevant parameter of _GUIListViewEx_MsgRegister to False) and then call the UDF handler function (_GUIListViewEx_WM_NOTIFY_Handler) from within your own handler
не регистрируйте $WM_NOTIFY с помощью функции UDF (установите соответствующий параметр _GUIListViewEx_MsgRegister на False), а затем вызовите функцию обработчика UDF (_GUIListViewEx_WM_NOTIFY_Handler) изнутри вашего собственного обработчика.



Добавлено:
Сообщение автоматически объединено:

Все разобрался
Вот рабочий пример:
Код:
#include <GUIConstantsEx.au3>
#include <WindowsConstants.au3>
#include <GuiListView.au3>
#include <Misc.au3>
#include <Array.au3>
#include <GuiImageList.au3>
#include "GUIListViewEx.au3"

Global $aItems[0]
Global $AlertDrag=0, $IndexDragItem=-1
AutoItSetOption ('MouseCoordMode',2)

$Form1 = GUICreate("Form1", 420, 449, 192, 114)
; ListView
 $hListView = GUICtrlCreateListView("", 10, 30, 400, 410, BitOR($LVS_REPORT,$LVS_SHOWSELALWAYS))
 _GUICtrlListView_SetExtendedListViewStyle($hListView, BitOR($LVS_EX_GRIDLINES, $LVS_EX_FULLROWSELECT))
_GUICtrlListView_AddColumn($hListView, "Название",400)
    For $i=1 To 10
        _ArrayAdd($aItems,'Название '&$i)
    Next
; Заполнить ListView
FillListView()

_GUIListViewEx_MsgRegister(False)

GUIRegisterMsg($WM_NOTIFY, "WM_NOTIFY")

GUISetState(@SW_SHOW)


While 1
    $nMsg = GUIGetMsg()
    Switch $nMsg
        Case $GUI_EVENT_CLOSE
            Exit

    EndSwitch
WEnd

; Заполнить ListView
Func FillListView()
    _GUICtrlListView_DeleteAllItems($hListView) ; Удалить все строки
    For $i=0 To UBound($aItems)-1
        GUICtrlCreateListViewItem($aItems[$i], $hListView)
    Next
    $Init_Index = _GUIListViewEx_Init($hListView, '', 0, 0xFF0000, True,1) ; Инициализация. Цвет разделителя
EndFunc




Func WM_NOTIFY($hWnd, $iMsg, $iwParam, $ilParam)
 Local $hWndFrom,  $iCode, $tNMHDR, $hWndListView, $tInfo

    ;Parameters to the UDF handler as you received in your WM_NOTIFY handler:
    _GUIListViewEx_WM_NOTIFY_Handler($hWnd, $iMsg, $iwParam, $ilParam)

    $hWndListView = $hListView
    If Not IsHWnd($hListView) Then $hWndListView = GUICtrlGetHandle($hListView)

    $tNMHDR = DllStructCreate($tagNMHDR, $ilParam)
    $hWndFrom = HWnd(DllStructGetData($tNMHDR, "hWndFrom"))
    $iCode = DllStructGetData($tNMHDR, "Code")
    $tInfo = DllStructCreate($tagNMITEMACTIVATE, $ilParam)
    $iIndex = DllStructGetData($tInfo, "Index")

    Switch $hWndFrom
        ; ListView
        Case $hWndListView
            Switch $iCode
                Case $NM_RCLICK
                    ConsoleWrite(@CRLF&'test')
            EndSwitch
    EndSwitch
    Return $GUI_RUNDEFMSG
EndFunc

Всем спасибо за помощь
 
Верх