Resiak1811 Posted April 21 Posted April 21 Here's my code that allows me to "edit text" (simulate edit) text in a ListView. I know GUIListViewEx (from Melba23) does this (and much much more), however, I only need the editing part and I've never been able to get a stable program with GUIListViewEx (probably due to my bad coding style? / too many ListViews? / too many GUIs and Child GUIs?, I don't know). If that can make things easier for others too. In reality, my code opens a TextBox over the field to be edited and SetItemText the field in the ListView. (100% stable) expandcollapse popup#include <EditConstants.au3> #include <GUIConstantsEx.au3> #include <GuiListView.au3> #include <MsgBoxConstants.au3> #include <SendMessage.au3> #include <WindowsStylesConstants.au3> Global $hWindow $hGUI = GUICreate("listview editing", 810, 368) $hWindow = $hGUI $ListView1 = GUICtrlCreateListView("Col 0|Col 1|Col 2||Col 4||Col 6|Col 7|Col 8|Col 9|Col 10", 5, 70, 800, 250) Local $colWidths[11] = [150, 60, 125, 10, 75, 10, 150, 150, 150, 100, 100] For $i = 0 To UBound($colWidths) - 1 _GUICtrlListView_SetColumnWidth($ListView1, $i, $colWidths[$i]) _GUICtrlListView_JustifyColumn($ListView1, $i, 2) Next ; Example: Filling from an array Local $aData[3] = ["11|21|31||51||71|81|91|101|111", "12|22|32||52||72|82|92|102|112", "13|23|33||53||73|83|93|103|113"] For $i = 0 To UBound($aData) - 1 GUICtrlCreateListViewItem($aData[$i], $ListView1) Next $hGUI2_button = GUICtrlCreateButton("$hGUI2", 704, 11, 100, 20) GUIRegisterMsg($WM_NOTIFY, "WM_NOTIFY") GUISetState(@SW_SHOW) While 1 $Main_MSG = GUIGetMsg() Switch $Main_MSG Case $GUI_EVENT_CLOSE Exit Case $hGUI2_button $hGUI2 = GUICreate("Example - $hGUI2", 605, 270, Default, Default, $WS_SYSMENU, $WS_EX_MDICHILD, $hWindow) $hWindow = $hGUI2 $ListView2 = GUICtrlCreateListView("Col 0|Col 1|Col 2||Col 4||Col 5", 5, 5, 590, 230) Local $cols[7] = [150, 100, 150, 10, 75, 10, 67] For $i = 0 To UBound($cols) - 1 _GUICtrlListView_SetColumnWidth($ListView2, $i, $cols[$i]) _GUICtrlListView_JustifyColumn($ListView2, $i, 2) Next ; Example: Filling from an array Local $aData[3] = ["16|26|36||56||76", "17|27|37||57||77", "18|28|38||58||78"] For $i = 0 To UBound($aData) - 1 GUICtrlCreateListViewItem($aData[$i], $ListView2) Next GUISetState(@SW_SHOW, $hWindow) While 1 $hGUI2_MSG = GUIGetMsg() Switch $hGUI2_MSG Case $GUI_EVENT_CLOSE ExitLoop EndSwitch Sleep(10) ; avoid crash due to fast loop WEnd GUIDelete($hWindow) $hWindow = $hGUI EndSwitch Sleep(10) ; avoid crash due to fast loop WEnd Func WM_NOTIFY($hWnd, $iMsg, $iwParam, $ilParam) #forceref $hWnd, $iMsg, $iwParam, $ilParam Local $hWndListView, $hWndListView2 Switch $hWindow Case $hGUI If Not IsHWnd($ListView1) Then $hWndListView = GUICtrlGetHandle($ListView1) Case $hGUI2 If Not IsHWnd($ListView2) Then $hWndListView2 = GUICtrlGetHandle($ListView2) EndSwitch Local $tNMHDR = DllStructCreate($tagNMHDR, $ilParam), _ $hWndFrom = HWnd(DllStructGetData($tNMHDR, "hWndFrom")), _ $iCode = DllStructGetData($tNMHDR, "Code") Switch $hWndFrom Case $hWndListView ;~ $ListView1 Switch $iCode Case $NM_DBLCLK Local $tInfo = DllStructCreate($tagNMITEMACTIVATE, $ilParam), _ $iIndex = DllStructGetData($tInfo, "Index"), _ $iSubItem = DllStructGetData($tInfo, "SubItem") If $iIndex > -1 Then Switch $iSubItem Case 0, 1, 2, 4, 6, 8 Local $before = _GUICtrlListView_GetItemText($ListView1, $iIndex, $iSubItem) Local $after = CustomInputBox($ListView1, $before, $iIndex, $iSubItem) If $after <> "Cancel" Then _edited($ListView1, $iIndex, $iSubItem, $before, $after) Else _canceled($ListView1, $iIndex, $iSubItem, $before, $after) EndIf Case 3, 5, 7, 9, 10 MsgBox("", "", "Column " & $iSubItem & " not editable !", 0, $hWindow) EndSwitch EndIf EndSwitch Case $hWndListView2 ;~ $ListView2 Switch $iCode Case $NM_DBLCLK Local $tInfo = DllStructCreate($tagNMITEMACTIVATE, $ilParam), _ $iIndex = DllStructGetData($tInfo, "Index"), _ $iSubItem = DllStructGetData($tInfo, "SubItem") If $iIndex > -1 Then Switch $iSubItem Case 0, 1, 4, 6 Local $before = _GUICtrlListView_GetItemText($ListView2, $iIndex, $iSubItem) Local $after = CustomInputBox($ListView2, $before, $iIndex, $iSubItem) If $after <> "Cancel" Then _edited($ListView2, $iIndex, $iSubItem, $before, $after) Else _canceled($ListView2, $iIndex, $iSubItem, $before, $after) EndIf Case 2, 3, 5 MsgBox("", "", "Column " & $iSubItem & " not editable !", 0, $hWindow) EndSwitch EndIf EndSwitch EndSwitch Return $GUI_RUNDEFMSG EndFunc ;==>WM_NOTIFY Func _edited($hListView, $row, $column, $before, $after) If Not IsHWnd($hListView) Then $hListView = GUICtrlGetHandle($hListView) Switch $hListView Case GUICtrlGetHandle($ListView1) _GUICtrlListView_BeginUpdate($ListView1) _GUICtrlListView_SetItemText($ListView1, $row, $after, $column) _GUICtrlListView_EndUpdate($ListView1) MsgBox("", "", "Enter pressed in $ListView1 !") Case GUICtrlGetHandle($ListView2) _GUICtrlListView_BeginUpdate($ListView2) _GUICtrlListView_SetItemText($ListView2, $row, $after, $column) _GUICtrlListView_EndUpdate($ListView2) MsgBox("", "", "Enter pressed in $ListView2 !") EndSwitch EndFunc ;==>_edited Func _canceled($hListView, $row, $column, $before, $after) If Not IsHWnd($hListView) Then $hListView = GUICtrlGetHandle($hListView) Switch $hListView Case GUICtrlGetHandle($ListView1) MsgBox("", "", "Esc pressed in $ListView1 !") Case GUICtrlGetHandle($ListView2) MsgBox("", "", "Esc pressed in $ListView2 !") EndSwitch EndFunc ;==>_canceled Func CustomInputBox($listview, $hBefore, $iIndex, $iSubItem) GuiDisableEnable($hWindow, 0, 35) Local $iXstart, $iYend ; <----- offset for the inputbox Switch $listview Case $ListView1 ;~ how to calculate : $ListView1 = GUICtrlCreateListView("Col 0|Col 1|...|Col 10", 5, 70, 800, 250) ;~ $iXstart = The left side of the control. (5) ;~ $iYend = The top of the control. 70 - 22 = 48 ;~ ** 20 is the listview item height but its slighty to high so 22 is a perfect number.. but its a case by case (listview by listview).. $iXstart = 5 $iYend = 48 Case $ListView2 ;~ how to calculate : $ListView2 = GUICtrlCreateListView("Col 0|Col 1|...|Col 5", 5, 5, 590, 230) ;~ $iXstart = The left side of the control. (5) ;~ $iYend = The top of the control. 5 - 22 = -17 $iXstart = 5 $iYend = -17 EndSwitch ; Ensure handle If Not IsHWnd($listview) Then $listview = GUICtrlGetHandle($listview) ; Validate indexes Local $iCols = _GUICtrlListView_GetColumnCount($listview) If $iSubItem >= $iCols Then Return "" Local $iItems = _GUICtrlListView_GetItemCount($listview) If $iIndex >= $iItems Then Return "" ; Compute X offset by summing column widths Local $iXOffset = 0 For $i = 0 To $iSubItem - 1 $iXOffset += _GUICtrlListView_GetColumnWidth($listview, $i) Next ; Compute Y offset by summing column widths Local $iTopIndex = _GUICtrlListView_GetTopIndex($listview) $iYOffset = ($iIndex - $iTopIndex) * 19 ; Column width Local $iWidth = _GUICtrlListView_GetColumnWidth($listview, $iSubItem) ; ========================= ; CONVERT TO SCREEN COORDS ; ========================= ; Get ListView position (client coords) Local $hGUI = _WinAPI_GetParent($listview) Local $aLVPos = ControlGetPos($hGUI, "", $listview) If @error Then Return "" ; Scroll offset Local $aOrigin = _GUICtrlListView_GetOrigin($listview) Local $iScrollX = $aOrigin[0] ; Position relative to GUI client Local $iX = $aLVPos[0] + $iXOffset - $iScrollX - $iXstart Local $iY = $aLVPos[1] + $iYOffset - $iYend ; Convert to SCREEN coordinates (THIS is the key) Local $tPoint = DllStructCreate("int X;int Y") DllStructSetData($tPoint, "X", $iX) DllStructSetData($tPoint, "Y", $iY) _WinAPI_ClientToScreen($listview, $tPoint) $iX = DllStructGetData($tPoint, "X") $iY = DllStructGetData($tPoint, "Y") ; Small padding (visual polish) $iX += 1 $iY += 1 Local $CustomInputBoxhGUI = GUICreate("", $iWidth, 20, $iX, $iY, $WS_POPUP, $WS_EX_TOPMOST) GUISetBkColor(0xFFFFFF) Local $hInput = GUICtrlCreateInput($hBefore, 0, 0, $iWidth, 20) Local $hOkButton = GUICtrlCreateDummy() Local $iCLOSE = GUICtrlCreateDummy() Dim $AccelKeysF3[2][2] = [["{ENTER}", $hOkButton], ["{ESC}", $iCLOSE]] GUISetAccelerators($AccelKeysF3, $CustomInputBoxhGUI) GUISetState(@SW_SHOW) WinSetOnTop($CustomInputBoxhGUI, "", 1) ControlFocus($CustomInputBoxhGUI, "", $hInput) _SendMessage(GUICtrlGetHandle($hInput), $EM_SETSEL, 0, -1) Local $Msg, $input_result = "" While 1 $Msg = GUIGetMsg() Switch $Msg Case $GUI_EVENT_CLOSE, $iCLOSE GUIDelete($CustomInputBoxhGUI) GUISetAccelerators("") GuiDisableEnable($hWindow, 1) Return "Cancel" Case $hOkButton $input_result = GUICtrlRead($hInput) GUIDelete($CustomInputBoxhGUI) ExitLoop EndSwitch Sleep(10) ; avoid crash due to fast loop WEnd GUISetAccelerators("") GuiDisableEnable($hWindow, 1) Return $input_result EndFunc ;==>CustomInputBox Func GuiDisableEnable($hGUI2, $sate, $br = 25, $DisableMenu = 1, $bColor = 0x000000) Local Static $avGUI[1] = [0] Switch $sate Case 0 If $DisableMenu = 1 Then GuiMenuDisable($hGUI2, 0) $vGUI = _GUIDisable($hGUI2, 0, $br, $bColor) GUISetState(@SW_DISABLE, $vGUI) _ArrayAdd($avGUI, $vGUI) $avGUI[0] += 1 If $DisableMenu = 1 Then GUISetState(@SW_DISABLE, $hGUI2) Case 1 If $DisableMenu = 1 Then GuiMenuDisable($hGUI2, 1) $MaxVGui = UBound($avGUI) - 1 If $MaxVGui = 0 Then Return _GUIDisable($avGUI[$MaxVGui], 1) _ArrayDelete($avGUI, $MaxVGui) $avGUI[0] -= 1 If $DisableMenu = 1 Then GUISetState(@SW_ENABLE, $hGUI2) WinActivate(WinGetHandle($hGUI2)) EndSwitch EndFunc ;==>GuiDisableEnable ;~ #Region Internal use Func GuiMenuDisable($hWnd, $sate) Local $dSysMenu = DllCall("User32.dll", "hwnd", "GetSystemMenu", "hwnd", $hWnd, "int", $sate) DllCall("User32.dll", "int", "RemoveMenu", "hwnd", $dSysMenu[0], "int", 0xF060, "int", $sate) DllCall("User32.dll", "int", "DrawMenuBar", "hwnd", $hWnd) EndFunc ;==>GuiMenuDisable Func _GUIDisable($hWnd = -1, $iDelete = 0, $iBrightness = Default, $bColor = 0x000000) Local $vGUI = 0 If $iBrightness = Default Then $iBrightness = 5 If $hWnd = -1 Then Local $iLabel = GUICtrlCreateLabel('', -99, -99, 1, 1) $hWnd = _WinAPI_GetParent(GUICtrlGetHandle($iLabel)) If @error Then Return SetError(1, 0 * GUICtrlDelete($iLabel), 0) GUICtrlDelete($iLabel) EndIf If $iDelete Then $vGUI = GUIDelete($hWnd) Else Local $aWinGetPos = WinGetClientSize($hWnd) $vGUI = GUICreate('', $aWinGetPos[0], $aWinGetPos[1], 0, 0, $WS_POPUP, $WS_EX_MDICHILD, $hWnd) GUISetBkColor($bColor, $vGUI) WinSetTrans($vGUI, '', Round($iBrightness * (255 / 100))) GUISetState(@SW_SHOW, $vGUI) EndIf Return $vGUI EndFunc ;==>_GUIDisable $before and $after represent the value before and after the modification (if you need them). argumentum and WildByDesign 2
WildByDesign Posted April 21 Posted April 21 This is really nice work. Thank you for sharing. Testing it on my end went very well. I especially like how you darken the background of the ListView while the text box is open for editing. This is awesome! Resiak1811 1
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now