ListView - Editieren aller SubItems

    • Offizieller Beitrag

    Hi,
    in einem Listview lassen sich mit dem Style $LVS_EDITLABELS Einträge on-the-fly editieren. Dies gilt aber nur für die Einträge in Spalte 0.
    Mit der folgenden Methode lassen sich alle SubItem sofort editieren. In der zuständigen Funktion verwende ich OnEventMode. Ich habe es aber so geschrieben, dass nur für die Ausführung der Funktion in den OnEventMode geschaltet wird, anschließend wird wieder in den vorherigen Modus zurückgeschaltet (Für all jene, die sich noch immer mit GUIGetMsg rumplagen möchten :D ).
    Das Bsp. habe ich daher auch mal im GetMsgMode erstellt.
    Um den Editiermodus nutzen zu können, darf $LVS_EDITLABELS hier nicht gesetzt sein.

    - mit Doppelklick öffnet sich genau über der angeklickten Spalte ein Editfenster mit dem Inhalt des SubItem
    - der untere Rand des Editfensters liegt an der Mauszeigerspitze
    - das Eingabefeld paßt sich der Breite der zugehörigen Spalte an
    - ist das Fenster so verschoben, dass eine Spalte nach links/rechts über den Desktop hinausragt, wird das Editfenster am Bildschirmrand, statt mittig über der Spalte positioniert
    - der geänderte Inhalt des Fensters wird mit ENTER übernommen und in das SubItem geschrieben
    - findet keine Änderung statt muß das Fenster mit ESC geschlossen werden
    - während des Editierens werden im Fenstertitel Zeilennummer und Spaltenname des editierten SubItem angezeigt

    Bsp. Edit SubItems
    [autoit]

    #include<StaticConstants.au3>
    #include<GUIConstantsEx.au3>
    #include<ListViewConstants.au3>
    #include<StructureConstants.au3>
    #include<WindowsConstants.au3>
    #include <GUIListView.au3>

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

    Global $currentItem[2], $title, $currentOpt[2] = ["none"]

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

    $GUI = GUICreate('test')
    $hListView = GUICtrlCreateListView('Spalte1|Spalte2|Spalte3', 10, 10, 300, 200, $LVS_REPORT)
    _GUICtrlListView_SetColumnWidth($hListView, 0, 70)
    _GUICtrlListView_SetColumnWidth($hListView, 1, 60)
    _GUICtrlListView_SetColumnWidth($hListView, 2, $LVSCW_AUTOSIZE_USEHEADER )
    For $i = 1 To 9
    GUICtrlCreateListViewItem('Z. ' & $i & ' - Sp. 1|Z. ' & $i & ' - Sp. 2|Z. ' & $i & ' - Sp. 3', $hListView)
    Next

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

    $EditBox = GUICreate('', 200, 30, -1, -1, BitOR($WS_POPUP,$WS_BORDER), $WS_EX_TOPMOST)
    $hEdit = GUICtrlCreateInput('', 5, 5, 190, 20, $SS_CENTER)
    HotKeySet('{ESC}', '_EscEdit')

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

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

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

    While True
    $msg = GUIGetMsg()
    If $msg = $GUI_EVENT_CLOSE Then Exit
    WEnd

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

    Func _LeftDblClick($Info)
    If $Info[3] = -1 Then Return
    If $currentOpt[0] = "none" Then
    $currentOpt[0] = Opt('GUICoordMode', 1)
    $currentOpt[1] = Opt("GUIOnEventMode", 1)
    EndIf
    GUICtrlSetOnEvent($hEdit, '_EditEnter')
    _GUICtrlListView_SetSelectedColumn($Info[1], $Info[4])
    $title = WinGetTitle($GUI)
    Local $mouse = MouseGetPos(), $posEdit = WinGetPos($EditBox)
    Local $posGUI = WinGetPos($GUI), $posLV = ControlGetPos($GUI, '', $hListView)
    Local $colInfo = _GUICtrlListView_GetColumn($Info[1], $Info[4]), $sumWidth = 0, $tmp
    WinSetTitle($GUI, '', 'Editiere: Zeile ' & $Info[3]+1 & ', ' & $colInfo[5])
    For $i = 0 To $Info[4]
    $tmp = _GUICtrlListView_GetColumn($Info[1], $i)
    $sumWidth += $tmp[4]
    Next
    $sumWidth -= $colInfo[4]
    Local $xPos = $posGUI[0]+$posLV[0]+$sumWidth
    If $xPos+$colInfo[4]+10 > @DesktopWidth Then $xPos = @DesktopWidth - ($colInfo[4] + 10)
    If $xPos < 0 Then $xPos = 0
    WinMove($EditBox, '', $xPos, $mouse[1]-$posEdit[3], $colInfo[4]+10)
    GUICtrlSetData($hEdit, _GUICtrlListView_GetItemText($Info[1], $Info[3], $Info[4]))
    $currentItem[0] = $Info[3]
    $currentItem[1] = $Info[4]
    GUISetState(@SW_SHOW, $EditBox)
    EndFunc

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

    Func _EscEdit()
    WinSetTitle($GUI, '', $title)
    Opt('GUICoordMode', $currentOpt[0])
    Opt("GUIOnEventMode", $currentOpt[1])
    $currentOpt[0] = "none"
    GUISetState(@SW_HIDE, $EditBox)
    EndFunc

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

    Func _EditEnter()
    WinSetTitle($GUI, '', $title)
    Opt('GUICoordMode', $currentOpt[0])
    Opt("GUIOnEventMode", $currentOpt[1])
    $currentOpt[0] = "none"
    _GUICtrlListView_SetItemText($hListView, $currentItem[0], GUICtrlRead($hEdit), $currentItem[1])
    GUISetState(@SW_HIDE, $EditBox)
    EndFunc

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

    Func WM_NOTIFY($hWnd, $iMsg, $iwParam, $ilParam)
    Local $hWndFrom, $iIDFrom, $iCode, $tNMHDR, $hWndListView
    $hWndListView = $hListView ; ID des LV
    If Not IsHWnd($hListView) Then $hWndListView = GUICtrlGetHandle($hListView) ; ID des LV
    $tNMHDR = DllStructCreate($tagNMHDR, $ilParam)
    $hWndFrom = HWnd(DllStructGetData($tNMHDR, "hWndFrom"))
    $iIDFrom = DllStructGetData($tNMHDR, "IDFrom")
    $iCode = DllStructGetData($tNMHDR, "Code")
    Switch $hWndFrom
    Case $hWndListView
    Switch $iCode
    Case $NM_DBLCLK
    Local $tInfo = DllStructCreate($tagNMITEMACTIVATE, $ilParam)
    Local $aInfo[5] = [$hWndFrom, $iIDFrom, $iCode, DllStructGetData($tInfo, "Index"), _
    DllStructGetData($tInfo, "SubItem")]
    _LeftDblClick($aInfo)
    EndSwitch
    EndSwitch
    Return $GUI_RUNDEFMSG
    EndFunc ;==>WM_NOTIFY

    [/autoit]

    Hier mal eine alternative Variante, die EditBox kann bei nichtgeändertem Inhalt jetzt auch mit ENTER verlassen werden.

    Spoiler anzeigen
    [autoit]

    #include<StaticConstants.au3>
    #include<GUIConstantsEx.au3>
    #include<ListViewConstants.au3>
    #include<StructureConstants.au3>
    #include<WindowsConstants.au3>
    #include <GUIListView.au3>

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

    Global $currentItem[2], $title, $currentOpt[2] = ["none"]

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

    $GUI = GUICreate('test')
    $hListView = GUICtrlCreateListView('Spalte1|Spalte2|Spalte3', 10, 10, 300, 200, $LVS_REPORT)
    _GUICtrlListView_SetColumnWidth($hListView, 0, 70)
    _GUICtrlListView_SetColumnWidth($hListView, 1, 60)
    _GUICtrlListView_SetColumnWidth($hListView, 2, $LVSCW_AUTOSIZE_USEHEADER )
    For $i = 1 To 9
    GUICtrlCreateListViewItem('Z. ' & $i & ' - Sp. 1|Z. ' & $i & ' - Sp. 2|Z. ' & $i & ' - Sp. 3', $hListView)
    Next

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

    $EditBox = GUICreate('', 200, 30, -1, -1, BitOR($WS_POPUP,$WS_BORDER), $WS_EX_TOPMOST)
    $dummy = GUICtrlCreateDummy()
    $hEdit = GUICtrlCreateInput('', 5, 5, 190, 20, $SS_CENTER)
    HotKeySet('{ESC}', '_EscEdit')
    Global $AccelKeys[1][2]=[["{ENTER}", $dummy]]
    GUICtrlSetOnEvent($dummy, "_EditEnter")
    GUISetAccelerators($AccelKeys)

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

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

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

    While True
    $msg = GUIGetMsg()
    If $msg = $GUI_EVENT_CLOSE Then Exit
    WEnd

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

    Func _LeftDblClick($Info)
    If $Info[3] = -1 Then Return
    If $currentOpt[0] = "none" Then
    $currentOpt[0] = Opt('GUICoordMode', 1)
    $currentOpt[1] = Opt("GUIOnEventMode", 1)
    EndIf
    GUICtrlSetOnEvent($hEdit, '_EditEnter')
    _GUICtrlListView_SetSelectedColumn($Info[1], $Info[4])
    $title = WinGetTitle($GUI)
    Local $mouse = MouseGetPos(), $posEdit = WinGetPos($EditBox)
    Local $posGUI = WinGetPos($GUI), $posLV = ControlGetPos($GUI, '', $hListView)
    Local $colInfo = _GUICtrlListView_GetColumn($Info[1], $Info[4]), $sumWidth = 0, $tmp
    WinSetTitle($GUI, '', 'Editiere: Zeile ' & $Info[3]+1 & ', ' & $colInfo[5])
    For $i = 0 To $Info[4]
    $tmp = _GUICtrlListView_GetColumn($Info[1], $i)
    $sumWidth += $tmp[4]
    Next
    $sumWidth -= $colInfo[4]
    Local $xPos = $posGUI[0]+$posLV[0]+$sumWidth
    If $xPos+$colInfo[4]+10 > @DesktopWidth Then $xPos = @DesktopWidth - ($colInfo[4] + 10)
    If $xPos < 0 Then $xPos = 0
    WinMove($EditBox, '', $xPos, $mouse[1]-$posEdit[3], $colInfo[4]+10)
    GUICtrlSetData($hEdit, _GUICtrlListView_GetItemText($Info[1], $Info[3], $Info[4]))
    $currentItem[0] = $Info[3]
    $currentItem[1] = $Info[4]
    GUISetState(@SW_SHOW, $EditBox)
    EndFunc

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

    Func _EscEdit()
    WinSetTitle($GUI, '', $title)
    Opt('GUICoordMode', $currentOpt[0])
    Opt("GUIOnEventMode", $currentOpt[1])
    $currentOpt[0] = "none"
    GUISetState(@SW_HIDE, $EditBox)
    EndFunc

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

    Func _EditEnter()
    WinSetTitle($GUI, '', $title)
    Opt('GUICoordMode', $currentOpt[0])
    Opt("GUIOnEventMode", $currentOpt[1])
    $currentOpt[0] = "none"
    _GUICtrlListView_SetItemText($hListView, $currentItem[0], GUICtrlRead($hEdit), $currentItem[1])
    GUISetState(@SW_HIDE, $EditBox)
    EndFunc

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

    Func WM_NOTIFY($hWnd, $iMsg, $iwParam, $ilParam)
    Local $hWndFrom, $iIDFrom, $iCode, $tNMHDR, $hWndListView
    $hWndListView = $hListView ; ID des LV
    If Not IsHWnd($hListView) Then $hWndListView = GUICtrlGetHandle($hListView) ; ID des LV
    $tNMHDR = DllStructCreate($tagNMHDR, $ilParam)
    $hWndFrom = HWnd(DllStructGetData($tNMHDR, "hWndFrom"))
    $iIDFrom = DllStructGetData($tNMHDR, "IDFrom")
    $iCode = DllStructGetData($tNMHDR, "Code")
    Switch $hWndFrom
    Case $hWndListView
    Switch $iCode
    Case $NM_DBLCLK
    Local $tInfo = DllStructCreate($tagNMITEMACTIVATE, $ilParam)
    Local $aInfo[5] = [$hWndFrom, $iIDFrom, $iCode, DllStructGetData($tInfo, "Index"), _
    DllStructGetData($tInfo, "SubItem")]
    _LeftDblClick($aInfo)
    EndSwitch
    EndSwitch
    Return $GUI_RUNDEFMSG
    EndFunc ;==>WM_NOTIFY

    [/autoit]
  • nettes Script :P es gibt aber glaube ich ein Problem.
    Nach dem Editieren ist kein Schliessen des Programms mehr möglich.
    Genommen habe ich das Script aus dem Spoiler und gestartet über Scite + F5

    Achtung Anfänger! :whistling:

    Betrachten des Quellcodes auf eigene Gefahr, bei Übelkeit,Erbrechen,Kopfschmerzen übernehme ich keine Haftung. 8o

  • Es funktioniert schon. Nur wenn man 2 mal doppelklickt, wird der Event-Mode einfach überschrieben undnicht mehr zurückgesetzt. Da muss noch eine Abfrage rein, z.B.:

    Spoiler anzeigen
    [autoit]

    #include<StaticConstants.au3>
    #include<GUIConstantsEx.au3>
    #include<ListViewConstants.au3>
    #include<StructureConstants.au3>
    #include<WindowsConstants.au3>
    #include <GUIListView.au3>

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

    Global $currentItem[2], $title, $currentOpt[2] = ["none"]

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

    $GUI = GUICreate('test')
    $hListView = GUICtrlCreateListView('Spalte1|Spalte2|Spalte3', 10, 10, 300, 200, $LVS_REPORT)
    _GUICtrlListView_SetColumnWidth($hListView, 0, 70)
    _GUICtrlListView_SetColumnWidth($hListView, 1, 60)
    _GUICtrlListView_SetColumnWidth($hListView, 2, $LVSCW_AUTOSIZE_USEHEADER )
    For $i = 1 To 9
    GUICtrlCreateListViewItem('Z. ' & $i & ' - Sp. 1|Z. ' & $i & ' - Sp. 2|Z. ' & $i & ' - Sp. 3', $hListView)
    Next

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

    $EditBox = GUICreate('', 200, 30, -1, -1, BitOR($WS_POPUP,$WS_BORDER), $WS_EX_TOPMOST)
    $hEdit = GUICtrlCreateInput('', 5, 5, 190, 20, $SS_CENTER)
    HotKeySet('{ESC}', '_EscEdit')

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

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

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

    While True
    $msg = GUIGetMsg()
    If $msg = $GUI_EVENT_CLOSE Then Exit
    WEnd

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

    Func _LeftDblClick($Info)
    If $Info[3] = -1 Then Return
    If $currentOpt[0] = "none" Then
    $currentOpt[0] = Opt('GUICoordMode', 1)
    $currentOpt[1] = Opt("GUIOnEventMode", 1)
    EndIf
    GUICtrlSetOnEvent($hEdit, '_EditEnter')
    _GUICtrlListView_SetSelectedColumn($Info[1], $Info[4])
    $title = WinGetTitle($GUI)
    Local $mouse = MouseGetPos(), $posEdit = WinGetPos($EditBox)
    Local $posGUI = WinGetPos($GUI), $posLV = ControlGetPos($GUI, '', $hListView)
    Local $colInfo = _GUICtrlListView_GetColumn($Info[1], $Info[4]), $sumWidth = 0, $tmp
    WinSetTitle($GUI, '', 'Editiere: Zeile ' & $Info[3]+1 & ', ' & $colInfo[5])
    For $i = 0 To $Info[4]
    $tmp = _GUICtrlListView_GetColumn($Info[1], $i)
    $sumWidth += $tmp[4]
    Next
    $sumWidth -= $colInfo[4]
    Local $xPos = $posGUI[0]+$posLV[0]+$sumWidth
    If $xPos+$colInfo[4]+10 > @DesktopWidth Then $xPos = @DesktopWidth - ($colInfo[4] + 10)
    If $xPos < 0 Then $xPos = 0
    WinMove($EditBox, '', $xPos, $mouse[1]-$posEdit[3], $colInfo[4]+10)
    GUICtrlSetData($hEdit, _GUICtrlListView_GetItemText($Info[1], $Info[3], $Info[4]))
    $currentItem[0] = $Info[3]
    $currentItem[1] = $Info[4]
    GUISetState(@SW_SHOW, $EditBox)
    EndFunc

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

    Func _EscEdit()
    WinSetTitle($GUI, '', $title)
    Opt('GUICoordMode', $currentOpt[0])
    Opt("GUIOnEventMode", $currentOpt[1])
    $currentOpt[0] = "none"
    GUISetState(@SW_HIDE, $EditBox)
    EndFunc

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

    Func _EditEnter()
    WinSetTitle($GUI, '', $title)
    Opt('GUICoordMode', $currentOpt[0])
    Opt("GUIOnEventMode", $currentOpt[1])
    $currentOpt[0] = "none"
    _GUICtrlListView_SetItemText($hListView, $currentItem[0], GUICtrlRead($hEdit), $currentItem[1])
    GUISetState(@SW_HIDE, $EditBox)
    EndFunc

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

    Func WM_NOTIFY($hWnd, $iMsg, $iwParam, $ilParam)
    Local $hWndFrom, $iIDFrom, $iCode, $tNMHDR, $hWndListView
    $hWndListView = $hListView ; ID des LV
    If Not IsHWnd($hListView) Then $hWndListView = GUICtrlGetHandle($hListView) ; ID des LV
    $tNMHDR = DllStructCreate($tagNMHDR, $ilParam)
    $hWndFrom = HWnd(DllStructGetData($tNMHDR, "hWndFrom"))
    $iIDFrom = DllStructGetData($tNMHDR, "IDFrom")
    $iCode = DllStructGetData($tNMHDR, "Code")
    Switch $hWndFrom
    Case $hWndListView
    Switch $iCode
    Case $NM_DBLCLK
    Local $tInfo = DllStructCreate($tagNMITEMACTIVATE, $ilParam)
    Local $aInfo[5] = [$hWndFrom, $iIDFrom, $iCode, DllStructGetData($tInfo, "Index"), _
    DllStructGetData($tInfo, "SubItem")]
    _LeftDblClick($aInfo)
    EndSwitch
    EndSwitch
    Return $GUI_RUNDEFMSG
    EndFunc ;==>WM_NOTIFY

    [/autoit]
    • Offizieller Beitrag

    Kann das Problem nicht nachvollziehen.
    Wenn SubItem zum Editieren geöffnet wird:
    - es wurde nichts geändert ==> Schließen mit ESC
    - Daten geändert ==> Schließen mit ENTER
    GUI wird normal mit Klick auf |X| beendet.

    Edit: progandys Beitrag erschien, als ich schrieb. :D
    Danke, aber man muß wirklich an jede noch so blödsinnige Aktion der User denken. :whistling:

    • Offizieller Beitrag

    Warum schließt sich eigentlich das Editfenster nicht, wenn man einfach Enter drückt. Ich meine ohne was geändert zu haben . Liegt das am OnEventMode ? Hat jetzt nichts mit der Funktion des Scriptes an sich zu tun. Würde mich aber Interessieren .

    • Offizieller Beitrag

    Ich wollte eine Unterscheidung, damit nur in das SubItem geschrieben wird, wenn etwas verändert wurde. Ich könnte natürlich einen vorher-nachher Vergleich ausführen. Wollte aber, dass nur bewußt gespeichert wird und eine Möglichkeit besteht ohne Änderung das Edit zu verlassen (ESC).

    • Offizieller Beitrag

    Das verstehe ich . Was mein Anliegen war, gibt es eine Möglichkeit das die Input auf ein einfaches Return reagiert? Normalerweise verhällt sich die Input ja immer so ,das sie erst auf Return reagiert wenn der Inhalt sich geändert hat . Ich weiß das gehört jetzt nicht in den thread , aber will nicht einen neuen eröffnen .

    • Offizieller Beitrag

    Hab mir schon gedacht, das es da keine einfache Möglichkeit gibt das Verhalten des Input zu manipuliern. Danke für deine Antwort . :)

  • GUISetAccelerators mit einem Dummy-Control wäre auch eine Möglchkeit. So wie es jetzt ist, wird eine Änderung auch angenommen, wenn das Inputfeld den Fokus verliert.

    • Offizieller Beitrag

    Coole Sache das .Hab ich euch jetzt so viel Mühe gemacht . Danke Progandy und Bugfix :thumbup:

  • Hallo,

    ist zwar schon etwas älter der Thread. Aber kann mir jemand sagen, warum ich die editierbaren Zellen, wenn sie geöffnet sind (Quelltext aus #1) immer in einem ganz breiten Feld (blauer Rahmen) sehe, sodass der eigentlich editierbare Text nicht gesehen wird? Die Editierung funktioniert. Nur sehen tut man nicht, was man macht. Siehe anliegenden Screenshot.

    Dank und Gruß

    Thomas

    • Offizieller Beitrag

    Oh man, das ist wirklich seeeehr alt. ;)

    Das Editierfenster wird hier erstellt:

    AutoIt
    $EditBox = GUICreate('', 200, 30, -1, -1, BitOR($WS_POPUP,$WS_BORDER), $WS_EX_TOPMOST)
    $dummy = GUICtrlCreateDummy()
    $hEdit = GUICtrlCreateInput('', 5, 5, 190, 20, $SS_CENTER)

    Passe die Breite der GUI und des Input individuell an.