Drag & Drop innerhalb eines Listviews

    • Offizieller Beitrag

    Ich habe da ein Problem mit einem Listview und zwar möchte ich einzelne Einträge eines Listviews verschieben.
    Also innerhalb desselben Listviews z.B. Eintrag2 zwischen Eintrag7 und Eintrag8.

    Beispielscript:

    Spoiler anzeigen
    [autoit]


    #include <GUIConstantsEx.au3>
    Opt('GUIOnEventMode', 1)
    $hGui = GUICreate('test', 400, 500)
    GUISetOnEvent($GUI_EVENT_CLOSE, '_End')
    GUISetOnEvent($GUI_EVENT_DROPPED, '_Drop')
    $hListview1 = GUICtrlCreateListView('Playlist|Length', 5, 5, 390, 200)
    GUICtrlSetState(-1, $GUI_DROPACCEPTED)
    For $i = 0 To 10
    GUICtrlCreateListViewItem('Titel' & $i & '|' & Random(1, 6, 1), $hListview1)
    Next
    $hListview2 = GUICtrlCreateListView('Playlist|Length', 5, 215, 390, 200)
    GUICtrlSetState(-1, $GUI_DROPACCEPTED)
    For $i = 0 To 10
    GUICtrlCreateListViewItem('Titel' & $i & '|' & Random(1, 6, 1), $hListview2)
    Next

    [/autoit] [autoit][/autoit] [autoit]

    GUISetState()

    [/autoit] [autoit][/autoit] [autoit]

    While True
    Sleep(20)
    WEnd

    [/autoit] [autoit][/autoit] [autoit]

    Func _End()
    Exit
    EndFunc ;==>_End

    [/autoit] [autoit][/autoit] [autoit]

    Func _Drop()
    MsgBox(0, 0, @GUI_DropId)
    EndFunc ;==>_Drop

    [/autoit]

    Wenn ich von einem Listview zum anderen einen Eintrag verschiebe, dann öffnet sich die MsgBox, aber beim verschieben innerhalb eines Listviews nicht.
    Wie kann man das Problem lösen? Bin schon am verzweifeln...

  • Ich kann es nicht glauben !!!
    Oscar, Du bist am verzweifeln?

    Lieben Gruß,
    Alina

    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

    Geheime Information: ;)
    k3mrwmIBHejryPvylQSFieDF5f3VOnk6iLAVBGVhKQegrFuWr3iraNIblLweSW4WgqI0SrRbS7U5jI3sn50R4a15Cthu1bEr

  • Vielleicht so:

    Spoiler anzeigen
    [autoit]

    #cs ----------------------------------------------------------------------------

    AutoIt Version: 3.3.0.0
    Author: Burak Keskin

    Script Function:
    Template AutoIt script.

    #ce ----------------------------------------------------------------------------

    [/autoit] [autoit][/autoit] [autoit]

    ; Script Start - Add your code below here

    [/autoit] [autoit][/autoit] [autoit]

    #include <GuiConstantsEx.au3>
    #include <WindowsConstants.au3>
    #include <GuiListView.au3>
    #include <GuiImageList.au3>

    [/autoit] [autoit][/autoit] [autoit]

    Global $bDragging = False
    Global $iLast_Index = -1
    Global $a_Index[2]; From and to
    Global $iLastLinetop, $iLastLineLeft
    Global $drawing = False; to ensure mousemove doesn't cause more than one line to be drawn

    [/autoit] [autoit][/autoit] [autoit]

    $Main_GUI = GUICreate("Drag & Drop LV Item", 225, 400, -1, -1, BitOR($WS_THICKFRAME, $WS_SIZEBOX))

    [/autoit] [autoit][/autoit] [autoit]

    $ListView = GUICtrlCreateListView("Entry Name|Category", 5, 75, 195, 280, $LVS_SINGLESEL)
    $h_ListView = GUICtrlGetHandle($ListView)

    [/autoit] [autoit][/autoit] [autoit]

    _GUICtrlListView_SetColumnWidth($ListView, 0, 100)
    _GUICtrlListView_SetColumnWidth($ListView, 1, 100)

    [/autoit] [autoit][/autoit] [autoit]

    GUICtrlSendMsg($ListView, $LVM_SETEXTENDEDLISTVIEWSTYLE, $LVS_EX_GRIDLINES, $LVS_EX_GRIDLINES)
    GUICtrlSendMsg($ListView, $LVM_SETEXTENDEDLISTVIEWSTYLE, $LVS_EX_FULLROWSELECT, $LVS_EX_FULLROWSELECT)
    GUICtrlSendMsg($ListView, $LVM_SETEXTENDEDLISTVIEWSTYLE, $LVS_EX_CHECKBOXES, $LVS_EX_CHECKBOXES)

    [/autoit] [autoit][/autoit] [autoit]

    GUICtrlSendMsg($ListView, $LVM_SETEXTENDEDLISTVIEWSTYLE, $LVS_EX_SUBITEMIMAGES, $LVS_EX_SUBITEMIMAGES)

    [/autoit] [autoit][/autoit] [autoit]

    $h_ImageList = _GUIImageList_Create(20, 20, 5, 0, 4, $LVSIL_SMALL)

    [/autoit] [autoit][/autoit] [autoit]

    For $i = 0 To 10
    _GUIImageList_AddIcon($h_ImageList, @SystemDir & "\shell32.dll", $i)
    Next

    [/autoit] [autoit][/autoit] [autoit]

    _GUICtrlListView_SetImageList($h_ListView, $h_ImageList, $LVSIL_SMALL)

    [/autoit] [autoit][/autoit] [autoit]

    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

    [/autoit] [autoit][/autoit] [autoit]

    GUISetState()

    [/autoit] [autoit][/autoit] [autoit]

    GUIRegisterMsg($WM_NOTIFY, "WM_NOTIFY_EVENTS")
    GUIRegisterMsg($WM_LBUTTONUP, "WM_LBUTTONUP_EVENTS")
    GUIRegisterMsg($WM_MOUSEMOVE, "WM_MOUSEMOVE_EVENTS")

    [/autoit] [autoit][/autoit] [autoit]

    While 1
    Switch GUIGetMsg()
    Case $GUI_EVENT_CLOSE
    _GUIImageList_Destroy($h_ImageList)
    Exit
    EndSwitch
    WEnd

    [/autoit] [autoit][/autoit] [autoit]

    Func WM_LBUTTONUP_EVENTS($hWndGUI, $MsgID, $wParam, $lParam)
    $bDragging = False

    [/autoit] [autoit][/autoit] [autoit]

    DllCall("User32.dll", "int", "RedrawWindow", "hwnd", $h_ListView, "ptr", 0, "int", 0, "int", 5)
    $iLast_Index = -1

    [/autoit] [autoit][/autoit] [autoit]

    Local $aLV_Pos = ControlGetPos($hWndGUI, "", $ListView)

    [/autoit] [autoit][/autoit] [autoit]

    Local $iX = BitAND($lParam, 0xFFFF) - $aLV_Pos[0]
    Local $iY = BitShift($lParam, 16) - $aLV_Pos[1]

    [/autoit] [autoit][/autoit] [autoit]

    Local $struct_LVHITTESTINFO = DllStructCreate("int;int;uint;int;int;int")

    [/autoit] [autoit][/autoit] [autoit]

    DllStructSetData($struct_LVHITTESTINFO, 1, $iX)
    DllStructSetData($struct_LVHITTESTINFO, 2, $iY)

    [/autoit] [autoit][/autoit] [autoit]

    $a_Index[1] = GUICtrlSendMsg($ListView, $LVM_HITTEST, 0, DllStructGetPtr($struct_LVHITTESTINFO))
    Local $iFlags = DllStructGetData($struct_LVHITTESTINFO, 2)

    [/autoit] [autoit][/autoit] [autoit]

    ;// Out of the ListView?
    If $a_Index[1] == -1 Then Return $GUI_RUNDEFMSG

    [/autoit] [autoit][/autoit] [autoit]

    ;// Not in an item?
    If BitAND($iFlags, $LVHT_ONITEMLABEL) == 0 And BitAND($iFlags, $LVHT_ONITEMSTATEICON) == 0 Then Return $GUI_RUNDEFMSG

    [/autoit] [autoit][/autoit] [autoit]

    If $a_Index[0] <> $a_Index[1] Then
    ;ConsoleWrite($a_Index[0] & " ==> " & $a_Index[1] & @CRLF)
    _GUICtrlListView_CopyItem($h_ListView, $h_ListView, $a_Index[0], $a_Index[1], 1)
    EndIf

    [/autoit] [autoit][/autoit] [autoit]

    Return $GUI_RUNDEFMSG
    EndFunc ;==>WM_LBUTTONUP_EVENTS

    [/autoit] [autoit][/autoit] [autoit]

    Func WM_MOUSEMOVE_EVENTS($hWndGUI, $MsgID, $wParam, $lParam)
    If Not $bDragging Or $drawing Then Return $GUI_RUNDEFMSG

    [/autoit] [autoit][/autoit] [autoit]

    Local $aLV_Pos = ControlGetPos($hWndGUI, "", $ListView)

    [/autoit] [autoit][/autoit] [autoit]

    Local $iX = BitAND($lParam, 0xFFFF) - $aLV_Pos[0]
    Local $iY = BitShift($lParam, 16) - $aLV_Pos[1]

    [/autoit] [autoit][/autoit] [autoit]

    Local $struct_LVHITTESTINFO = DllStructCreate("int;int;uint;int;int;int")

    [/autoit] [autoit][/autoit] [autoit]

    DllStructSetData($struct_LVHITTESTINFO, 1, $iX)
    DllStructSetData($struct_LVHITTESTINFO, 2, $iY)

    [/autoit] [autoit][/autoit] [autoit]

    Local $iItem = GUICtrlSendMsg($ListView, $LVM_HITTEST, 0, DllStructGetPtr($struct_LVHITTESTINFO))
    If $iItem = -1 Then Return $GUI_RUNDEFMSG

    [/autoit] [autoit][/autoit] [autoit]

    If $iLast_Index = $iItem Then Return $GUI_RUNDEFMSG

    [/autoit] [autoit][/autoit] [autoit]

    If $iLast_Index > $iItem Then;Move up
    _GUICtrlListView_RedrawItems($ListView, $iItem, $iLast_Index)
    Else
    _GUICtrlListView_RedrawItems($ListView, $iLast_Index, $iItem - 1)
    EndIf

    [/autoit] [autoit][/autoit] [autoit]

    $iLast_Index = $iItem

    [/autoit] [autoit][/autoit] [autoit]

    Local $aLV_Pos = ControlGetPos($hWndGUI, "", $ListView)
    Local $iY = _GUICtrlListView_GetItemPositionY($ListView, $iItem)

    [/autoit] [autoit][/autoit] [autoit]

    If $iY <= 0 Then Return $GUI_RUNDEFMSG

    [/autoit] [autoit][/autoit] [autoit]

    _DrawLine($aLV_Pos[0], $iY, $aLV_Pos[2], 3, 0xFF0000, $h_ListView)
    EndFunc ;==>WM_MOUSEMOVE_EVENTS

    [/autoit] [autoit][/autoit] [autoit]

    Func WM_NOTIFY_EVENTS($hWndGUI, $MsgID, $wParam, $lParam)
    Local $tagNMHDR, $iEvent, $hwndFrom, $iCode, $iItem

    [/autoit] [autoit][/autoit] [autoit]

    $tagNMHDR = DllStructCreate("int;int;int;int", $lParam);NMHDR (hwndFrom, idFrom, code, Item)
    If @error Then Return $GUI_RUNDEFMSG

    [/autoit] [autoit][/autoit] [autoit]

    $iCode = DllStructGetData($tagNMHDR, 3)
    $iItem = DllStructGetData($tagNMHDR, 4)

    [/autoit] [autoit][/autoit] [autoit]

    Switch $wParam
    Case $ListView
    Switch $iCode
    Case $LVN_BEGINDRAG
    $a_Index[0] = $iItem
    $bDragging = True

    [/autoit] [autoit][/autoit] [autoit]

    _GUICtrlListView_SetItemSelected($ListView, $iItem, False)
    EndSwitch
    EndSwitch

    [/autoit] [autoit][/autoit] [autoit]

    Return $GUI_RUNDEFMSG
    EndFunc ;==>WM_NOTIFY_EVENTS

    [/autoit] [autoit][/autoit] [autoit]

    Func _GUICtrlListView_CopyItem($hWnd_Source, $hWnd_Destination, $iSrcIndex, $iDstIndex, $fDelFlag = False)
    Local $iInsert_Index
    Local $tItem = DllStructCreate($tagLVITEM)

    [/autoit] [autoit][/autoit] [autoit]

    Local $iCols = _GUICtrlListView_GetColumnCount($hWnd_Source)
    Local $iItems = _GUICtrlListView_GetItemCount($hWnd_Source)
    Local $iDest_Items = _GUICtrlListView_GetItemCount($hWnd_Destination)

    [/autoit] [autoit][/autoit] [autoit]

    _GUICtrlListView_BeginUpdate($hWnd_Source)
    If $hWnd_Destination <> $hWnd_Source Then _GUICtrlListView_BeginUpdate($hWnd_Destination)

    [/autoit] [autoit][/autoit] [autoit]

    DllStructSetData($tItem, "Mask", BitOR($LVIF_GROUPID, $LVIF_IMAGE, $LVIF_INDENT, $LVIF_PARAM, $LVIF_STATE))
    DllStructSetData($tItem, "Item", $iSrcIndex)
    DllStructSetData($tItem, "SubItem", 0)
    DllStructSetData($tItem, "StateMask", -1)

    [/autoit] [autoit][/autoit] [autoit]

    _GUICtrlListView_GetItemEx($hWnd_Source, $tItem)

    [/autoit] [autoit][/autoit] [autoit]

    If $iDstIndex > $iSrcIndex Then
    $iDstIndex += 1
    ElseIf $iSrcIndex > $iDstIndex Then
    $iSrcIndex += 1
    EndIf

    [/autoit] [autoit][/autoit] [autoit]

    $iInsert_Index = _GUICtrlListView_InsertItem($hWnd_Destination, _
    _GUICtrlListView_GetItemText($hWnd_Source, $iSrcIndex, 0), $iDstIndex, DllStructGetData($tItem, "Image"))

    [/autoit] [autoit][/autoit] [autoit]

    If BitAND(_GUICtrlListView_GetExtendedListViewStyle($hWnd_Source), $LVS_EX_CHECKBOXES) == $LVS_EX_CHECKBOXES Then
    If _GUICtrlListView_GetItemChecked($hWnd_Source, $iSrcIndex) Then _
    _GUICtrlListView_SetItemChecked($hWnd_Destination, $iInsert_Index)
    EndIf

    [/autoit] [autoit][/autoit] [autoit]

    For $i = 0 To $iCols - 1
    DllStructSetData($tItem, "Item", $iInsert_Index)
    DllStructSetData($tItem, "SubItem", $i)

    [/autoit] [autoit][/autoit] [autoit]

    _GUICtrlListView_GetItemEx($hWnd_Source, $tItem)

    [/autoit] [autoit][/autoit] [autoit]

    _GUICtrlListView_AddSubItem($hWnd_Destination, $iInsert_Index, _
    _GUICtrlListView_GetItemText($hWnd_Source, $iSrcIndex, $i), $i, DllStructGetData($tItem, "Image"))
    Next

    [/autoit] [autoit][/autoit] [autoit]

    If $fDelFlag Then _GUICtrlListView_DeleteItem($hWnd_Source, $iSrcIndex)

    [/autoit] [autoit][/autoit] [autoit]

    If $iDstIndex > $iSrcIndex Then $iDstIndex -= 1
    _GUICtrlListView_SetItemSelected($hWnd_Source, $iDstIndex)

    [/autoit] [autoit][/autoit] [autoit]

    _GUICtrlListView_EndUpdate($hWnd_Source)
    If $hWnd_Destination <> $hWnd_Source Then _GUICtrlListView_EndUpdate($hWnd_Destination)

    [/autoit] [autoit][/autoit] [autoit]

    _GUICtrlListView_RedrawItems($hWnd_Destination, $iSrcIndex, $iDstIndex)
    ;DllCall("User32.dll", "int", "RedrawWindow", "hwnd", $hWnd_Destination, "ptr", 0, "int", 0, "int", 5)
    EndFunc ;==>_GUICtrlListView_CopyItem

    [/autoit] [autoit][/autoit] [autoit]

    Func _DrawLine($iLeft, $iTop, $iWidth, $iHeight, $sColor, $hWnd = 0)
    $drawing = True
    $sColor = Hex("0x" & BitAND(BitShift(String(Binary($sColor)), 8), 0xFFFFFF));RGB2BGR

    [/autoit] [autoit][/autoit] [autoit]

    Local $hDC = DllCall("User32.dll", "int", "GetDC", "hwnd", $hWnd)
    Local $aPen = DllCall("GDI32.dll", "int", "CreatePen", "int", 0, "int", $iHeight, "int", $sColor)

    [/autoit] [autoit][/autoit] [autoit]

    DllCall("GDI32.dll", "int", "SelectObject", "int", $hDC[0], "int", $aPen[0])
    ConsoleWrite("drawline " & $iLastLineLeft & ', ' & $iLastLinetop & ', ' & $iLeft & ', ' & $iTop & @CRLF)
    If $iLastLinetop > -1 And $iLastLineLeft > -1 Then
    If $iLastLinetop <> $iTop Then; or $iLastLineLeft <> $iLeft Then
    Local $strRect = DllStructCreate("int[4]")

    [/autoit] [autoit][/autoit] [autoit]

    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", GUICtrlGetHandle($ListView), "int", 0, "int", 1)
    Sleep(50);seems to be needed to ensure redrawn before line is drawn
    EndIf
    EndIf

    [/autoit] [autoit][/autoit] [autoit]

    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)

    [/autoit] [autoit][/autoit] [autoit]

    DllCall("user32.dll", "int", "ReleaseDC", "hwnd", $hWnd, "int", $hDC[0])
    DllCall("GDI32.dll", "int", "DeleteObject", "int", $aPen[0])
    $drawing = False
    EndFunc ;==>_DrawLine

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit][/autoit] [autoit][/autoit] [autoit][/autoit] [autoit][/autoit] [autoit][/autoit] [autoit][/autoit] [autoit][/autoit] [autoit][/autoit] [autoit][/autoit] [autoit][/autoit] [autoit][/autoit] [autoit][/autoit] [autoit][/autoit] [autoit][/autoit] [autoit][/autoit] [autoit][/autoit] [autoit][/autoit] [autoit][/autoit] [autoit][/autoit] [autoit][/autoit] [autoit][/autoit] [autoit][/autoit] [autoit][/autoit] [autoit][/autoit] [autoit][/autoit] [autoit][/autoit] [autoit][/autoit] [autoit][/autoit]
    • Offizieller Beitrag

    So, zwei Stunden später...
    Yeah! Ich hab's hingekriegt! :D

    Spoiler anzeigen
    [autoit]


    #include <WindowsConstants.au3>
    #include <ListViewConstants.au3>
    #include <GuiListView.au3>
    #include <GUIConstantsEx.au3>
    Opt('GUIOnEventMode', 1)
    $hGui = GUICreate('test', 400, 300)
    GUISetOnEvent($GUI_EVENT_CLOSE, '_End')
    GUISetOnEvent($GUI_EVENT_PRIMARYUP, '_LVDrop')
    GUISetOnEvent($GUI_EVENT_PRIMARYDOWN, '_LVDrag')
    GUISetOnEvent($GUI_EVENT_MOUSEMOVE, '_LVMove')
    $hListview = GUICtrlCreateListView('Playlist|Length', 5, 5, 390, 200, Default, BitOR($WS_EX_CLIENTEDGE, $LVS_EX_FULLROWSELECT, $LVS_EX_DOUBLEBUFFER))
    GUICtrlSendMsg($hListview, $LVM_SETCOLUMNWIDTH, 0, 290)
    GUICtrlSendMsg($hListview, $LVM_SETCOLUMNWIDTH, 1, 60)
    GUICtrlSetState(-1, $GUI_DROPACCEPTED)
    For $i = 0 To 9
    GUICtrlCreateListViewItem('Titel' & $i & '|' & Random(100, 999, 1), $hListview)
    Next
    Global $iDropItem
    GUISetState()

    [/autoit] [autoit][/autoit] [autoit]

    While True
    Sleep(20)
    WEnd

    [/autoit] [autoit][/autoit] [autoit]

    Func _End()
    Exit
    EndFunc ;==>_End

    [/autoit] [autoit][/autoit] [autoit]

    Func _LVDrop()
    Local $aItem = _GUICtrlListView_HitTest(GUICtrlGetHandle($hListview))
    If $aItem[0] <> $iDropItem Then
    Local $aItemText = _GUICtrlListView_GetItemTextArray($hListview, $iDropItem)
    _GUICtrlListView_DeleteItem(GUICtrlGetHandle($hListview), $iDropItem)
    Local $InsItem = _GUICtrlListView_InsertItem($hListview, $aItemText[1], $aItem[0])
    _GUICtrlListView_SetItemText($hListview, $InsItem, $aItemText[2], 1)
    _GUICtrlListView_SetItemSelected($hListview, $InsItem)
    _GUICtrlListView_SetItemFocused($hListview, $InsItem)
    EndIf
    EndFunc ;==>_LVDrop

    [/autoit] [autoit][/autoit] [autoit]

    Func _LVDrag()
    Local $aItem = _GUICtrlListView_HitTest(GUICtrlGetHandle($hListview))
    $iDropItem = $aItem[0]
    EndFunc ;==>_LVDrag

    [/autoit] [autoit][/autoit] [autoit]

    Func _LVMove()
    Local $aInfo = GUIGetCursorInfo($hGui)
    If Not IsArray($aInfo) Then Return
    If $aInfo[2] Then
    Local $aItem = _GUICtrlListView_HitTest(GUICtrlGetHandle($hListview))
    _GUICtrlListView_SetItemSelected($hListview, -1, False)
    _GUICtrlListView_SetItemSelected($hListview, $aItem[0])
    EndIf
    EndFunc ;==>_LVMove

    [/autoit]

    Das ist zwar nicht das Schönste, aber mir reicht das. :)

  • Hallo Oscar,

    und was bitte gefällt dir daran nicht, Problem ist doch gelöst. Und schöner als mit Up- und Down-Buttons, mit denen man dann zigmal klicken muss, bis der Eintrag dort ist wo er hin soll.

    mfg (Auto)Bert