ListView Items mit drag&drop sortieren - arbeitet ungenau und gibt falsche Werte

  • Hallo zusammen,

    ich habe in einem 2spaltigem ListView 15 MP3-Titel mit Größe dargestellt. Dies Einträge möchte ich mit drag&drop sortieren. Also nich alphabetisch. Da in der Liste nur der Titel selbst angezeigt wird, habe ich Pfad und Titel in einem Array gespeichert. Ich muß also bei einer Änderung im ListView diese in das Array übertragen.
    Dabei passiert nun folgendes:
    1. Ich ziehe Item1 (001.mp3) auf Item15(015.mp3) -> ListView klappt, Prüfung des Array - auch i.O.
    2. Ich ziehe Item1 (002.mp3) auf Item15(001.mp3) -> ListView klappt, Prüfung des Array - auch i.O
    3. Ich ziehe Item1 (003.mp3) auf Item14(001.mp3) -> ListView klappt manchmal, Prüfung des Array > Item1 ist nicht an Stelle von Item14, sondern auf Item13. Und manchmal nimmt er optisch das Item1, verschiebt aber dann das Item2

    Ich sitz nun schon ein paar Stunden an dem Problem und finde keine Lösung.

    Hier das Script zur Funktion ... lauffähig...

    Spoiler anzeigen
    [autoit]


    #include <GUIConstantsEx.au3>
    #include <WindowsConstants.au3>
    #include <GUIListView.au3>
    #include <Array.au3>

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

    Global $aDateien[0], $iDropItem

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

    $vScrHoehe=@DesktopHeight-100
    $h_GUI = GUICreate(" Der DateiZufäller - Sortieren",500,$vScrHoehe,@DesktopWidth-500,5,-1,$WS_EX_ACCEPTFILES)

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

    $Text=GUICtrlCreateLabel("Wähle die Dateien aus, die Du nutzen möchtest !"&@CR&"Ziehe sie einfach von Deiner Dateiverwaltung in die Tabelle.",20,10,660,50)
    GUICtrlSetFont(-1,14,"","","Times New Roman")
    GUICtrlSetColor(-1,0xFF0000)

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

    $Liste=GUICtrlCreateListView ("",20,60,460,$vScrHoehe-155,Default,BitOR($WS_EX_CLIENTEDGE,$LVS_EX_FULLROWSELECT, $LVS_EX_DOUBLEBUFFER)) ;$LVS_EX_HEADERDRAGDROP
    GUICtrlSetFont(-1,14,"","","Times New Roman")

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

    _GUICtrlListView_AddColumn($Liste, "Musikdatei", 373) ; Spaltenkopf & Breite festlegen
    _GUICtrlListView_AddColumn($Liste, "Größe", 75)

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

    GUICtrlSendMsg($Liste, $LVM_SETEXTENDEDLISTVIEWSTYLE, $LVS_EX_GRIDLINES,$LVS_ICON-1)
    GUICtrlSetState($Liste, $GUI_DROPACCEPTED)
    GUICtrlSetState($Liste,$LVS_EX_TRACKSELECT)

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

    $Gesamt=GUICtrlCreateLabel("gesamt: ",20,830,52,20)
    GUICtrlSetFont(-1,14,"","","Times New Roman")
    $gesGB=GUICtrlCreateLabel("",250,830,145,30)
    GUICtrlSetFont(-1,14,"","","Times New Roman")

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

    $Auswahl=GUICtrlCreateButton("Auswahl vollständig ?",20,$vScrHoehe-60,170,40)
    GUICtrlSetFont(-1,14,"","","Times New Roman")
    GUICtrlSetState($Auswahl,$GUI_DISABLE)

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

    $Start=GUICtrlCreateButton("Start",255,$vScrHoehe-60,100,40)
    GUICtrlSetFont(-1,16,"","","Times New Roman")
    GUICtrlSetState(-1,$GUI_HIDE)

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

    $Ende=GUICtrlCreateButton("Beenden",375,$vScrHoehe-60,100,40)
    GUICtrlSetFont(-1,12,"","","Times New Roman")

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

    GUISetState()

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

    GUICtrlSetData($Text,"Sortiere jetzt Deine dateien !"&@CR&"Einfach anklicken und an die richtige Stelle ziehen.")
    GUICtrlDelete($Auswahl)
    GUICtrlSetState($Start,$GUI_SHOW)

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

    ; eigentlich Funktion zum Befüllen von ListView per d&d - hier eine Schleife zum Befüllen mit 15 Werten

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

    For $vI= 0 to 14
    $vText=StringFormat("%03s",$vI+1)&".mp3"
    GUICtrlCreateListViewItem($vText&"|"&StringFormat("%.2f",($vI+1)*Random(1.3,2.9))&"MB", $Liste)
    _ArrayAdd($aDateien,$vText)
    Next

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

    While 1
    $nMsg = GUIGetMsg()
    Switch $nMsg
    Case $GUI_EVENT_PRIMARYUP
    _LVDrop()
    case $GUI_EVENT_PRIMARYDOWN
    _LVDrag()
    Case $GUI_EVENT_MOUSEMOVE
    _LVMove()
    Case $Start
    ExitLoop
    Case $GUI_EVENT_CLOSE, $Ende
    Exit
    EndSwitch
    WEnd

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

    Exit
    ;-----------------------------------------------------------------------------------------------------------------------------------------------
    ; LiestView sortieren mit d&d
    Func _LVDrop()
    Local $aItem = _GUICtrlListView_HitTest(GUICtrlGetHandle($Liste))
    ;_ArrayDisplay($aItem)
    If $aItem[0] <> $iDropItem Then

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

    If $aItem[0] >-1 And $iDropItem >-1 Then
    Local $vText=$aDateien[$iDropItem]
    If $aItem[0]=UBound($aDateien)-1 Then
    _ArrayAdd($aDateien,$aDateien[$iDropItem])
    Else
    _ArrayInsert($aDateien,$aItem[0],$aDateien[$iDropItem])
    EndIf
    _ArrayDelete($aDateien,$iDropItem)
    ;_ArrayDisplay($aDateien,"$aDateien")
    EndIf
    Local $aItemText = _GUICtrlListView_GetItemTextArray($Liste, $iDropItem)

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

    ;_ArrayDisplay($aItemText,"$aItemText")
    _GUICtrlListView_DeleteItem(GUICtrlGetHandle($Liste), $iDropItem)
    Local $InsItem = _GUICtrlListView_InsertItem($Liste, $aItemText[1], $aItem[0])
    _GUICtrlListView_SetItemText($Liste, $InsItem, $aItemText[2], 1)
    _GUICtrlListView_SetItemSelected($Liste, $InsItem)
    _GUICtrlListView_SetItemFocused($Liste, $InsItem)
    EndIf
    _ArrayDisplay($aDateien,"$aDateien")
    EndFunc ;==>_LVDrop

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

    Func _LVDrag()
    Local $aItem = _GUICtrlListView_HitTest(GUICtrlGetHandle($Liste))
    $iDropItem = $aItem[0] ;das angeklickte Item
    EndFunc ;==>_LVDrag

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

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

    [/autoit]

    Hat Jemand ne Idee, wo hier der Wurm drin ist ???

    Vorab schon mal Danke.....

    Wenn Du's eilig hast - geh langsam...

  • So, ich hab den Fehler nun gefunden . Das Verschieben der Einträge im Array war nicht richtig durchdacht.

    Es gibt also drei verschiedene Situationen, die auftreten können.
    1. Verschieben bis an Ende -> gelöst mit _ArrayAdd
    2. Verschieben innerhalb des ListView (also nicht bis ans Ende) von oben nach unten -> glöst mit _ArrayInsert
    3. Verschieben innerhalb des ListView (also nicht bis ans Ende) von unten nach oben -> glöst mit _ArrayInsert
    Bei 2. und 3. muß dann der zu löschende Eintrag korregiert werden.

    Was bleibt ist der Effekt, daß ich z.B. das 1. Item im ListView anklicke und verschiebe. Optisch sehe ich das auch.
    Nach Abschluß der Prozedur wurde aber das 2. Item verschoben. Im ListView, wie im Array stimmen die Einträge,
    genau so als hätte ich ursprünglich das 2. Item ausgewählt.

    Was mich zu dem Schluß kommen läst, das die Position der Maus nicht richtig ausgelesen wird!

    Gibts dafür eine bessere Lösung ??

    Hier noch mal zur Info das Script:

    Spoiler anzeigen


    #include <GUIConstantsEx.au3>
    #include <WindowsConstants.au3>
    #include <GUIListView.au3>
    #include <Array.au3>

    Global $aDateien[0], $iDropItem

    $vScrHoehe=@DesktopHeight-100
    $h_GUI = GUICreate(" Zeit für MP3 - Sortieren",500,$vScrHoehe,@DesktopWidth-500,5,-1,$WS_EX_ACCEPTFILES)

    $Text=GUICtrlCreateLabel("Wähle die Dateien aus, die Du nutzen möchtest !"&@CR&"Ziehe sie einfach von Deiner Dateiverwaltung in die Tabelle.",20,10,660,50)
    GUICtrlSetFont(-1,14,"","","Times New Roman")
    GUICtrlSetColor(-1,0xFF0000)

    $Liste=GUICtrlCreateListView ("",20,60,460,$vScrHoehe-155,Default,BitOR($WS_EX_CLIENTEDGE,$LVS_EX_FULLROWSELECT, $LVS_EX_DOUBLEBUFFER)) ;$LVS_EX_HEADERDRAGDROP
    GUICtrlSetFont(-1,14,"","","Times New Roman")

    _GUICtrlListView_AddColumn($Liste, "Musikdatei", 373) ; Spaltenkopf & Breite festlegen
    _GUICtrlListView_AddColumn($Liste, "Größe", 75)

    GUICtrlSendMsg($Liste, $LVM_SETEXTENDEDLISTVIEWSTYLE, $LVS_EX_GRIDLINES,$LVS_ICON-1)
    GUICtrlSetState($Liste, $GUI_DROPACCEPTED)
    GUICtrlSetState($Liste,$LVS_EX_TRACKSELECT)

    $Gesamt=GUICtrlCreateLabel("gesamt: ",20,830,52,20)
    GUICtrlSetFont(-1,14,"","","Times New Roman")
    $gesGB=GUICtrlCreateLabel("",250,830,145,30)
    GUICtrlSetFont(-1,14,"","","Times New Roman")

    $Auswahl=GUICtrlCreateButton("Auswahl vollständig ?",20,$vScrHoehe-60,170,40)
    GUICtrlSetFont(-1,14,"","","Times New Roman")
    GUICtrlSetState($Auswahl,$GUI_DISABLE)

    $Start=GUICtrlCreateButton("Start",255,$vScrHoehe-60,100,40)
    GUICtrlSetFont(-1,16,"","","Times New Roman")
    GUICtrlSetState(-1,$GUI_HIDE)

    $Ende=GUICtrlCreateButton("Beenden",375,$vScrHoehe-60,100,40)
    GUICtrlSetFont(-1,12,"","","Times New Roman")

    GUISetState()

    GUICtrlSetData($Text,"Sortiere jetzt Deine dateien !"&@CR&"Einfach anklicken und an die richtige Stelle ziehen.")
    GUICtrlDelete($Auswahl)
    GUICtrlSetState($Start,$GUI_SHOW)

    ; eigentlich Funktion zum Befüllen von ListView per d&d - hier eine Schleife zum Befüllen mit 15 Werten

    For $vI= 0 to 14
    $vText=StringFormat("%03s",$vI+1)&".mp3"
    GUICtrlCreateListViewItem($vText&"|"&StringFormat("%.2f",($vI+1)*Random(1.3,2.9))&"MB", $Liste)
    _ArrayAdd($aDateien,$vText)
    Next
    ConsoleWrite("$iDropItem"&@CR&"Wert-$iDropItem""$aItem[0]"&@TAB&"Wert-$aItem[0]"&@CR)

    While 1
    $nMsg = GUIGetMsg()
    Switch $nMsg
    Case $GUI_EVENT_PRIMARYUP
    _LVDrop()
    case $GUI_EVENT_PRIMARYDOWN
    _LVDrag()
    Case $GUI_EVENT_MOUSEMOVE
    _LVMove()
    Case $Start
    ExitLoop
    Case $GUI_EVENT_CLOSE, $Ende
    Exit
    EndSwitch
    WEnd

    Exit
    ;-----------------------------------------------------------------------------------------------------------------------------------------------
    ; LiestView sortieren mit d&d
    Func _LVDrop()
    Local $aItem = _GUICtrlListView_HitTest(GUICtrlGetHandle($Liste))
    ;_ArrayDisplay($aItem)

    ConsoleWrite(" "&$iDropItem&" ("&$aDateien[$iDropItem]&") verschieben auf: "&$aItem[0]&@TAB&_GUICtrlListView_GetItemText($Liste,$aItem[0])&@CR)

    If $aItem[0] <> $iDropItem Then

    If $aItem[0] >-1 And $iDropItem >-1 Then
    Local $vText=$aDateien[$iDropItem]
    If $aItem[0]=UBound($aDateien)-1 Then
    _ArrayAdd($aDateien,$aDateien[$iDropItem])
    _ArrayDelete($aDateien,$iDropItem)
    Elseif $iDropItem < $aItem[0] Then
    _ArrayInsert($aDateien,$aItem[0]+1,$aDateien[$iDropItem])
    _ArrayDisplay($aDateien,"nach Insert Quelle ist kleiner")
    _ArrayDelete($aDateien,$iDropItem)
    _ArrayDisplay($aDateien,"nach Insert kleiner")
    Elseif $iDropItem > $aItem[0] Then
    _ArrayInsert($aDateien,$aItem[0],$aDateien[$iDropItem])
    _ArrayDisplay($aDateien,"nach Insert Quelle ist größer")
    _ArrayDelete($aDateien,$iDropItem+1)
    _ArrayDisplay($aDateien,"nach Insert größer")
    EndIf
    ;_ArrayDelete($aDateien,$iDropItem)
    ;_ArrayDisplay($aDateien,"$aDateien")
    EndIf
    Local $aItemText = _GUICtrlListView_GetItemTextArray($Liste, $iDropItem)

    ;_ArrayDisplay($aItemText,"$aItemText")
    _GUICtrlListView_DeleteItem(GUICtrlGetHandle($Liste), $iDropItem)
    Local $InsItem = _GUICtrlListView_InsertItem($Liste, $aItemText[1], $aItem[0])
    _GUICtrlListView_SetItemText($Liste, $InsItem, $aItemText[2], 1)
    _GUICtrlListView_SetItemSelected($Liste, $InsItem)
    _GUICtrlListView_SetItemFocused($Liste, $InsItem)
    EndIf
    _ArrayDisplay($aDateien,"$aDateien")
    EndFunc ;==>_LVDrop

    Func _LVDrag()
    Local $aItem = _GUICtrlListView_HitTest(GUICtrlGetHandle($Liste))
    $iDropItem = $aItem[0] ;das angeklickte Item
    EndFunc ;==>_LVDrag

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

    Wenn Du's eilig hast - geh langsam...

    • Offizieller Beitrag

    Die Array Befehle brauchst du garnicht.
    Einfach ein ListView mit der Anzahl der Subitems des Arrays erstellen und die Columns, welche du nicht anzeigen willst verstecken. ;)
    Einfach _GUICtrlListView_SetColumnWidth benutzen und die Columnbreite auf 0 setzen.
    Oder du benutzt gleich _GUICtrlListView_HideColumn um die Spalten zu verstecken.
    Ein extra Array brauchtst du also nicht , weil die Daten ja in der richtigen Reihenfolge in deinem ListView liegen.

    • Offizieller Beitrag

    Zum sortieren mittels Drag & Drop habe ich mal das hier geschrieben:

    Spoiler anzeigen
    [autoit]


    #include <GUIConstantsEx.au3>
    #include <GuiListView.au3>
    #include <WindowsConstants.au3>

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

    Opt('GUIOnEventMode', 1)

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

    $hGui = GUICreate('ListView Drag&Drop', 240, 280)
    GUISetOnEvent($GUI_EVENT_CLOSE, '_CloseGui')

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

    $hListView = GUICtrlCreateListView('AAA|BBB|CCC', 10, 10, 220, 260)
    $hWndListView = GUICtrlGetHandle($hListView)

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

    For $i = 0 To 19
    GUICtrlCreateListViewItem(StringFormat('%s|%s|%s', Chr(Random(65, 90, 1)) & Chr(Random(97, 122, 1)), Chr(Random(65, 90, 1)), Random(0, 9, 1)), $hListView)
    Next

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

    GUISetState()
    GUIRegisterMsg($WM_NOTIFY, '_DragListView')

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

    WinWaitClose($hGui)

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

    Func _CloseGui()
    GUIDelete($hGui)
    EndFunc ;==>_End

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

    Func _DragListView($hWnd, $iMsg, $iwParam, $ilParam)
    #forceref $hWnd, $iwParam
    Local Static $iStartIndex = -1, $iEndIndex = -1, $sItemText = "", $fLVDrag = False
    Switch $iMsg
    Case $WM_MOUSEMOVE
    Local $aHit = _GUICtrlListView_HitTest($hWndListView)
    If IsArray($aHit) Then _GUICtrlListView_SetItemFocused($hWndListView, $aHit[0])
    Case $WM_NOTIFY
    Local $tNMHDR, $hWndFrom, $iCode, $iNewItem, $tNMLISTVIEW
    $tNMHDR = DllStructCreate($tagNMHDR, $ilParam)
    $hWndFrom = HWnd(DllStructGetData($tNMHDR, 'hWndFrom'))
    $iCode = DllStructGetData($tNMHDR, 'Code')
    Switch $hWndFrom
    Case $hWndListView
    Switch $iCode
    Case $LVN_BEGINDRAG
    If Not $fLVDrag Then
    $tNMLISTVIEW = DllStructCreate($tagNMLISTVIEW, $ilParam)
    $iStartIndex = DllStructGetData($tNMLISTVIEW, 'Item')
    $sItemText = _GUICtrlListView_GetItemTextString($hWndListView, $iStartIndex)
    $fLVDrag = True
    GUIRegisterMsg($WM_MOUSEMOVE, '_DragListView')
    EndIf
    Case $LVN_HOTTRACK
    If $fLVDrag Then
    $tNMLISTVIEW = DllStructCreate($tagNMLISTVIEW, $ilParam)
    $iEndIndex = DllStructGetData($tNMLISTVIEW, 'Item')
    $fLVDrag = False
    GUIRegisterMsg($WM_MOUSEMOVE, '')
    Select
    Case $iStartIndex < $iEndIndex
    $iNewItem = _GUICtrlListView_InsertItem($hWndListView, "", $iEndIndex + 1)
    _GUICtrlListView_SetItemText($hWndListView, $iNewItem, $sItemText, -1)
    _GUICtrlListView_SetItemSelected($hWndListView, $iNewItem, True, True)
    _GUICtrlListView_DeleteItem($hWndListView, $iStartIndex)
    Case $iStartIndex > $iEndIndex
    _GUICtrlListView_DeleteItem($hWndListView, $iStartIndex)
    $iNewItem = _GUICtrlListView_InsertItem($hWndListView, "", $iEndIndex)
    _GUICtrlListView_SetItemText($hWndListView, $iNewItem, $sItemText, -1)
    _GUICtrlListView_SetItemSelected($hWndListView, $iNewItem, True, True)
    EndSelect
    EndIf
    EndSwitch
    EndSwitch
    EndSwitch
    Return $GUI_RUNDEFMSG
    EndFunc ;==>_DragListView

    [/autoit]