pixelsearch Posted May 20, 2021 Posted May 20, 2021 (edited) You did it. Bravo LarsJ and thanks for your comments (in script & post) Edited May 20, 2021 by pixelsearch
Lion66 Posted May 21, 2021 Posted May 21, 2021 (edited) I am pleased with the appearance of a new version. Unfortunately, it has the same features (for me the problem) as the previous one. 1. How to make a button to align the first column on the left-mid-right? 2. I added the context menu on the LV to get text using Func _GetText from pixelsearch. How to prohibit the context menu call on the header of the LV to leave only the "choice of column to search" option? Thank you. Edited May 21, 2021 by Lion66
pixelsearch Posted May 21, 2021 Posted May 21, 2021 (edited) 6 hours ago, Lion66 said: How to prohibit the context menu call on the header of the LV to leave only the "choice of column to search" option? I'd re-use the same coords test as found in this script Applied to the present script, it would end like this : ... $g_hHeader = _GUICtrlListView_GetHeader($g_idListView) Local $iHeaderHeight = _WinAPI_GetWindowHeight($g_hHeader) ; <========== added line ... Case $GUI_EVENT_SECONDARYDOWN Local $aMPos = MouseGetPos() Local $aLVPos = WinGetPos($g_hListView) Local $aLVCli = WinGetClientSize($g_hListView) ; includes LV headers, excludes both scrollbars (if any), great ! If $aMPos[0] > $aLVPos[0] + 1 AND $aMPos[0] <= $aLVPos[0] + $aLVCli[0] + 1 _ AND $aMPos[1] > $aLVPos[1] + $iHeaderHeight + 1 AND $aMPos[1] <= $aLVPos[1] + $aLVCli[1] + 1 Then Local $iSelected = GUICtrlSendMsg($g_idListView, $LVM_GETNEXTITEM, -1, $LVNI_SELECTED) If $iSelected > - 1 Then ; if an item is selected Local $sGetText = _GetText($iSelected, 0) MsgBox($MB_TOPMOST, "Item = " & $iSelected, "Text col 0 = " & $sGetText) EndIf EndIf ... ;======================================================================== Func _GetText($iItem, $iSubItem) Local $sGetText If $g_iSortDir = 0x0400 Then ; 0x0400 = $HDF_SORTUP $sGetText = $g_aSubArray[$g_tIndex.arr($iItem + 1)][$iSubItem] Else $sGetText = $g_aSubArray[$g_tIndex.arr($g_iSearch - $iItem)][$iSubItem] EndIf Return $sGetText EndFunc ;==>_GetText  Edited May 21, 2021 by pixelsearch
Lion66 Posted May 21, 2021 Posted May 21, 2021 An interesting attempt. And although the message is not issued when clicking on the header, but the context menu still appears. It is necessary to somehow solve in the same style as Larsj forbade the change in the column width.
pixelsearch Posted May 21, 2021 Posted May 21, 2021 56 minutes ago, Lion66 said: but the context menu still appears. As you don't share your code, then I had no idea that you created a real Context Menu ! I simply thought that you called "Context Menu" the fact that the right click I indicated (Case $GUI_EVENT_SECONDARYDOWN) was retrieving infos and the last script I presented is enough to prevent a right click in LV header. Now if you want to see how to prevent a real Context Menu to appear, then you need to take care of the message WM_CONTEXTMENU as shown in this thread where we exchanged some good ideas with Nine. Then you could mix it with the coords to exclude of the preceding script. Good luck
Norm73 Posted May 22, 2021 Posted May 22, 2021 The pixelsearch made a very good (complete) example in which the search for columns is done. What do you have to do so that the search in the entire list is carried out in all columns at the same time? For example, if I wrote the number 7 so that this number would appear in all columns.
Lion66 Posted May 22, 2021 Posted May 22, 2021 Hi pixelsearch. I tried to block the context menu by using your tip. The menu is blocked if it is set to all GUI, and is not blocked if the menu is set to LV. And in this case, the WM_CONTEXTMENU sends messages when right-clicking in any part of the GUI, and not only in LV. And in general, I do not like the use of coordinates. In my Windows 7, click in the bottom of the header is worked as in the inside LV (and not as on header). I assume that need change the offsets that, with different window themes and different OS, there will be different. expandcollapse popup#include <ComboConstants.au3> #include <EditConstants.au3> #include <GuiListView.au3> #include <GUIConstantsEx.au3> #include <StaticConstants.au3> #include <WindowsConstants.au3> #include "RandomArray.au3" ; LarsJ Opt("MustDeclareVars", 1) Global $g_iRows = 1000, $g_iCols = 6, $g_iLeftLV = 10, $g_iTopLV = 40, $g_hGui, $g_hListView, $g_hHeader, $g_hEdit Global $g_aCols = ["Strings", "Integers", "Floats", "Dates", "Times", "R/C"], $g_aWidths = [230, 61, 124, 70, 60, 60] Global $g_idListView, $g_idMarker, $g_idComboCol, $g_idComboColDummy, $g_idEditDummy Global $g_sSearch, $g_iSearchCol, $g_iSortDir, $g_iSearch = $g_iRows Global $g_aArray, $g_aSubArray, $g_tDefaultIndex, $g_tIndex = DllStructCreate("uint arr[" & $g_iRows & "]") Global $g_aIndex[$g_iCols], $g_aIndexTemp[$g_iCols] ; VarGetType's : $g_aIndex => "Array", $g_aIndex[0] => "String" Global $idDummy_CancelCrop Example() Func Example() ; Generate array & one index _Generate_All($g_aArray) $g_aSubArray = $g_aArray $g_tDefaultIndex = $g_tIndex ; Create GUI $g_hGui = GUICreate("Virtual ListView + Sort + Incremental search + CustomDraw (2k)", 630 + 20, 400 + 30 + 20) ; Create ComboBox control (how to search : RegEx or Normal ?) Local $idSearchHow = GUICtrlCreateCombo("RegEx search", 11, 9, 100, 20, BitOR($GUI_SS_DEFAULT_COMBO, $CBS_DROPDOWNLIST)) Local $sSearchHow = "RegEx search", $sSearchHowPrev = $sSearchHow ; default way of searching (changeable) GUICtrlSetData($idSearchHow, "Normal search", $sSearchHow) Local $Left = GUICtrlCreateButton("Left", 120, 10, 60, 20) Local $Right = GUICtrlCreateButton("Right", 190, 10, 60, 20) ; Create Edit control (search) + dummy control Local $idEdit = GUICtrlCreateEdit("", 260, 10, 160, 20, BitXOR($GUI_SS_DEFAULT_EDIT, $WS_HSCROLL, $WS_VSCROLL)) $g_hEdit = GUICtrlGetHandle($idEdit) $g_idEditDummy = GUICtrlCreateDummy() ; Create ComboBox control (column where to search) + dummy control GUICtrlCreateLabel("Col", 429, 10, 20, 20, BitOR($SS_CENTERIMAGE, $SS_CENTER)) $g_idComboCol = GUICtrlCreateCombo("0", 452, 9, 41, 20, BitOR($GUI_SS_DEFAULT_COMBO, $CBS_DROPDOWNLIST)) $g_iSearchCol = 0 ; default column where to search (changeable) Local $iSearchColPrev = $g_iSearchCol For $i = 1 To $g_iCols - 1 GUICtrlSetData($g_idComboCol, $i & "|", $g_iSearchCol) Next $g_idComboColDummy = GUICtrlCreateDummy() ; Create Label control (number of matching results) Local $idResult = GUICtrlCreateLabel(" " & $g_iRows & " rows (no pattern)", 501, 10, 135, 20, BitOR($SS_CENTERIMAGE, $SS_SUNKEN)) ; Create ListView $g_idListView = GUICtrlCreateListView("", $g_iLeftLV, $g_iTopLV, 630, 400, BitOR($GUI_SS_DEFAULT_LISTVIEW, $LVS_OWNERDATA), $WS_EX_CLIENTEDGE) _GUICtrlListView_SetExtendedListViewStyle($g_idListView, BitOR($LVS_EX_DOUBLEBUFFER, $LVS_EX_FULLROWSELECT)) $g_hListView = GUICtrlGetHandle($g_idListView) $g_hHeader = _GUICtrlListView_GetHeader($g_idListView) Global $iHeaderHeight = _WinAPI_GetWindowHeight($g_hHeader) For $i = 0 To $g_iCols - 1 _GUICtrlListView_AddColumn($g_idListView, $g_aCols[$i], $g_aWidths[$i]) Next $idDummy_CancelCrop = GUICtrlCreateDummy() ;Local $idButtoncontext = GUICtrlCreateContextMenu() ; for all GUI Local $idButtoncontext = GUICtrlCreateContextMenu($g_idListView) ; for LV only Local $idGetText = GUICtrlCreateMenuItem("Get text", $idButtoncontext) ; Create Marker (an orange line placed above the header of the column being searched) $g_idMarker = GUICtrlCreateLabel("", 0, 0) GUICtrlSetBkColor(-1, 0xFFA060) ; orange _MoveMarker($g_iSearchCol) _GUICtrlListView_SetSelectedColumn($g_idListView, $g_iSearchCol) ; Sorting information $g_iSortDir = 0x0400 ; $HDF_SORTUP Local $iSortCol = -1, $iSortColPrev = -1 GUIRegisterMsg($WM_NOTIFY, "WM_NOTIFY") GUIRegisterMsg($WM_COMMAND, "WM_COMMAND") GUIRegisterMsg($WM_CONTEXTMENU, "WM_CONTEXTMENU") GUICtrlSendMsg($g_idListView, $LVM_SETITEMCOUNT, $g_iRows, 0) GUISetState(@SW_SHOW) While 1 Switch GUIGetMsg() Case $GUI_EVENT_CLOSE ExitLoop Case $idDummy_CancelCrop ConsoleWrite("Code for Cancel Crop" & @CRLF) Case $idGetText Local $iSelected = GUICtrlSendMsg($g_idListView, $LVM_GETNEXTITEM, -1, $LVNI_SELECTED) If $iSelected > -1 Then ; an item is selected Local $sGetText = _GetText($iSelected, 0) MsgBox($MB_TOPMost, "Item = " & $iSelected, "Text col 0 = " & $sGetText) EndIf Case $Left _GUICtrlListView_JustifyColumn($g_idListView, 0, 0) Case $Right _GUICtrlListView_JustifyColumn($g_idListView, 0, 1) Case $g_idComboCol, $g_idComboColDummy, $idSearchHow $g_iSearchCol = GUICtrlRead($g_idComboCol) $sSearchHow = GUICtrlRead($idSearchHow) Select Case $g_iSearchCol <> $iSearchColPrev _MoveMarker($g_iSearchCol) ; Search column will be selected below, after ContinueCase $iSearchColPrev = $g_iSearchCol Case $sSearchHow <> $sSearchHowPrev $sSearchHowPrev = $sSearchHow Case Else ; no change in both Combo controls (same search column, same search way) ContinueLoop EndSelect ContinueCase Case $g_idEditDummy _GUICtrlHeader_SetItemFormat($g_hHeader, $iSortCol, $HDF_STRING) $g_sSearch = GUICtrlRead($idEdit) $g_tIndex = $g_tDefaultIndex If $g_sSearch = "" Then ; Empty search string, display all rows $g_aSubArray = $g_aArray $g_iSearch = $g_iRows Else ; Find rows matching the search string $g_iSearch = 0 If $sSearchHow = "RegEx search" Then For $i = 0 To $g_iRows - 1 ; duplicated For... Next for speed If StringRegExp($g_aArray[$i][$g_iSearchCol], "(?i)" & $g_sSearch) Then For $j = 0 To $g_iCols - 1 $g_aSubArray[$g_iSearch][$j] = $g_aArray[$i][$j] Next $g_iSearch += 1 EndIf Next Else ; "Normal search" For $i = 0 To $g_iRows - 1 ; duplicated For... Next for speed If StringInStr($g_aArray[$i][$g_iSearchCol], $g_sSearch) Then For $j = 0 To $g_iCols - 1 $g_aSubArray[$g_iSearch][$j] = $g_aArray[$i][$j] Next $g_iSearch += 1 EndIf Next EndIf ; Delete eventual temporary subindexes For $i = 0 To $g_iCols - 1 If VarGetType($g_aIndexTemp[$i]) = "DLLStruct" Then $g_aIndexTemp[$i] = "" ; "String" Next EndIf GUICtrlSetData($idResult, " " & $g_iSearch & ($g_sSearch = "" ? " rows (no pattern)" : " matching rows")) ;------ ; _GUICtrlListView_SetSelectedColumn($g_hListView, $g_iSearchCol) ; depending on search, crashes script when placed here ; _GUICtrlListView_SetSelectedColumn($g_idListView, $g_iSearchCol) ; strange behavior here ; GUICtrlSendMsg($g_idListView, $LVM_SETSELECTEDCOLUMN, $g_iSearchCol, 0) ; strange behavior here ;------ GUICtrlSendMsg($g_idListView, $LVM_SETITEMCOUNT, $g_iSearch, 0) _GUICtrlListView_SetSelectedColumn($g_hListView, $g_iSearchCol) ; seems ok here (after $LVM_SETITEMCOUNT) Case $g_idListView ; Sort $iSortCol = GUICtrlGetState($g_idListView) If $iSortCol <> $iSortColPrev Then _GUICtrlHeader_SetItemFormat($g_hHeader, $iSortColPrev, $HDF_STRING) EndIf ; Set $g_tIndex + eventual update of $g_aIndexTemp[$iSortCol] OR $g_aIndex[$iSortCol] If GUICtrlRead($idEdit) Then _UpdateIndex($g_aIndexTemp, $iSortCol) Else _UpdateIndex($g_aIndex, $iSortCol) EndIf $g_iSortDir = (($iSortCol = $iSortColPrev) ? ($g_iSortDir = $HDF_SORTUP ? $HDF_SORTDOWN : $HDF_SORTUP) : ($HDF_SORTUP)) _GUICtrlHeader_SetItemFormat($g_hHeader, $iSortCol, $HDF_STRING + $g_iSortDir) GUICtrlSendMsg($g_idListView, $LVM_SETSELECTEDCOLUMN, $iSortCol, 0) GUICtrlSendMsg($g_idListView, $LVM_SETITEMCOUNT, $g_iSearch, 0) $iSortColPrev = $iSortCol Case $GUI_EVENT_RESTORE ; needed, or Marker goes back in 0, 0 after Restore (why ?) _MoveMarker($g_iSearchCol) EndSwitch WEnd ; Cleanup GUIDelete($g_hGui) EndFunc ;==>Example ;======================================================================== Func WM_NOTIFY($hWnd, $iMsg, $wParam, $lParam) Local $tNMHDR = DllStructCreate($tagNMHDR, $lParam) Switch HWnd(DllStructGetData($tNMHDR, "hWndFrom")) Case $g_hListView Switch DllStructGetData($tNMHDR, "Code") Case $NM_CUSTOMDRAW Local $tCustDraw = DllStructCreate($tagNMLVCUSTOMDRAW, $lParam) Switch DllStructGetData($tCustDraw, "dwDrawStage") ; Holds a value that specifies the drawing stage Case $CDDS_PREPAINT ; Before the paint cycle begins Return $CDRF_NOTIFYITEMDRAW ; Notify the parent window of any item-related drawing operations Case $CDDS_ITEMPREPAINT ; Before painting an item Return $CDRF_NOTIFYSUBITEMDRAW ; Notify the parent window of any subitem-related drawing operations Case $CDDS_ITEMPREPAINT + $CDDS_SUBITEM ; Before painting a subitem If (DllStructGetData($tCustDraw, "iSubItem") = $g_iSearchCol) And $g_sSearch Then Return $CDRF_NOTIFYPOSTPAINT ; If $g_sSearch then paint $g_iSearchCol in postpaint stage Return $CDRF_NEWFONT ; $CDRF_NEWFONT must be returned after changing font or colors ; Paint all other columns in prepaint stage with default code Case $CDDS_ITEMPOSTPAINT + $CDDS_SUBITEM ; After painting a subitem ; Paints $g_iSearchCol ($g_iSearchCol only) if $g_sSearch Local Static $tRect = DllStructCreate($tagRECT), $pRect = DllStructGetPtr($tRect), $tSize = DllStructCreate($tagSIZE) Local Static $hBrushYellow = _WinAPI_CreateSolidBrush(0x00FFFF), $hBrushCyan = _WinAPI_CreateSolidBrush(0xFFFF00) ; Yellow and cyan, BGR Local $iItem = DllStructGetData($tCustDraw, "dwItemSpec"), $hDC = DllStructGetData($tCustDraw, "hDC") ; Subitem text and matching text Local $sSubItemText = $g_iSortDir = 0x0400 ? $g_aSubArray[$g_tIndex.arr($iItem + 1)][$g_iSearchCol] _ ; 0x0400 = $HDF_SORTUP : $g_aSubArray[$g_tIndex.arr($g_iSearch - $iItem)][$g_iSearchCol] Local $sMatch = StringRegExp($sSubItemText, "(?i)" & $g_sSearch, 1), $extended = @extended, $iLen = StringLen($sMatch[0]) ; Entire subitem rectangle DllStructSetData($tRect, 2, $g_iSearchCol) ; Top DllStructSetData($tRect, 1, $LVIR_BOUNDS) ; Left GUICtrlSendMsg($g_idListView, $LVM_GETSUBITEMRECT, $iItem, $pRect) DllStructSetData($tRect, 1, DllStructGetData($tRect, 1) + ($g_iSearchCol ? 6 : 3)) ; Left margin ; Set transparent background for the subitem DllCall("gdi32.dll", "int", "SetBkMode", "handle", $hDC, "int", $TRANSPARENT) ; _WinAPI_SetBkMode ; Draw entire subitem text DllStructSetData($tRect, 2, DllStructGetData($tRect, 2) + 2) ; Top margin DllCall("user32.dll", "int", "DrawTextW", "handle", $hDC, "wstr", $sSubItemText, "int", StringLen($sSubItemText), "struct*", $tRect, "uint", 0) ; _WinAPI_DrawText DllStructSetData($tRect, 2, DllStructGetData($tRect, 2) - 2) ; Top margin ; Rectangle for matching substring DllCall("gdi32.dll", "bool", "GetTextExtentPoint32W", "handle", $hDC, "wstr", $sSubItemText, "int", $extended - $iLen - 1, "struct*", $tSize) ; _WinAPI_GetTextExtentPoint32 DllStructSetData($tRect, "Left", DllStructGetData($tRect, "Left") + DllStructGetData($tSize, "X")) DllCall("gdi32.dll", "bool", "GetTextExtentPoint32W", "handle", $hDC, "wstr", $sMatch[0], "int", $iLen, "struct*", $tSize) ; _WinAPI_GetTextExtentPoint32 DllStructSetData($tRect, "Right", DllStructGetData($tRect, "Left") + DllStructGetData($tSize, "X")) ; Fill matching rectangle with yellow or cyan background color DllCall("user32.dll", "int", "FillRect", "handle", $hDC, "struct*", $tRect, "handle", GUICtrlSendMsg($g_idListView, $LVM_GETITEMSTATE, $iItem, $LVIS_SELECTED) ? $hBrushYellow : $hBrushCyan) ; _WinAPI_FillRect ; Redraw matching text on the yellow or cyan background DllStructSetData($tRect, 2, DllStructGetData($tRect, 2) + 2) ; Top margin DllCall("gdi32.dll", "int", "SetTextColor", "handle", $hDC, "int", 0x000000) ; _WinAPI_SetTextColor DllCall("user32.dll", "int", "DrawTextW", "handle", $hDC, "wstr", $sMatch[0], "int", $iLen, "struct*", $tRect, "uint", 0) ; _WinAPI_DrawText Return $CDRF_NEWFONT ; $CDRF_NEWFONT must be returned after changing font or colors EndSwitch Case $LVN_GETDISPINFOW Local $tNMLVDISPINFO = DllStructCreate($tagNMLVDISPINFO, $lParam) If ($tNMLVDISPINFO.SubItem = $g_iSearchCol) And $g_sSearch Then Return ; Don't paint $g_iSearchCol if $g_sSearch Local Static $tText = DllStructCreate("wchar[50]"), $pText = DllStructGetPtr($tText) Local $s = $g_iSortDir = 0x0400 ? DllStructSetData($tText, 1, $g_aSubArray[$g_tIndex.arr($tNMLVDISPINFO.Item + 1)][$tNMLVDISPINFO.SubItem]) _ ; 0x0400 = $HDF_SORTUP : DllStructSetData($tText, 1, $g_aSubArray[$g_tIndex.arr($g_iSearch - $tNMLVDISPINFO.Item)][$tNMLVDISPINFO.SubItem]) DllStructSetData($tNMLVDISPINFO, "Text", $pText) EndSwitch Case $g_hHeader Switch DllStructGetData($tNMHDR, "Code") Case $HDN_ENDTRACKW, $HDN_DIVIDERDBLCLICKW ; let's forget $HDN_TRACKW... _MoveMarker(GUICtrlRead($g_idComboCol)) Case $NM_RCLICK Local $aHit = _GUICtrlListView_SubItemHitTest($g_hListView) ; $aHit[1] : 0-based index of the LV subitem... i.e. the column in our case (may be -1 if right click on empty part of header) If $aHit[1] > -1 Then ; valid column GUICtrlSetData($g_idComboCol, $aHit[1]) GUICtrlSendToDummy($g_idComboColDummy) EndIf EndSwitch EndSwitch Return $GUI_RUNDEFMSG EndFunc ;==>WM_NOTIFY ;======================================================================== Func WM_COMMAND($hWnd, $iMsg, $wParam, $lParam) Local $hWndFrom = $lParam Local $iCode = BitShift($wParam, 16) ; High word Switch $hWndFrom Case $g_hEdit Switch $iCode Case $EN_CHANGE GUICtrlSendToDummy($g_idEditDummy) EndSwitch EndSwitch Return $GUI_RUNDEFMSG EndFunc ;==>WM_COMMAND ;======================================================================== Func _Generate_All(ByRef $g_aArray) ConsoleWrite("$g_iRows = " & $g_iRows & " $g_iCols = " & $g_iCols & @CRLF) Local $hTimer = TimerInit() $g_aArray = FAS_Random2DArrayAu3($g_iRows, "sifdtr", "abcdefghijklmnopqrstuvwxyz") For $i = 0 To $g_iRows - 1 $g_tIndex.arr($i + 1) = $i Next ConsoleWrite("Generating array & one index = " & TimerDiff($hTimer) & @CRLF & @CRLF) EndFunc ;==>_Generate_All ;======================================================================== Func _SortArrayStruct(Const ByRef $aArray, $iCol, $iRows) Local $tIndex = DllStructCreate("uint arr[" & $iRows & "]") Local $pIndex = DllStructGetPtr($tIndex) Local Static $hDll = DllOpen("kernel32.dll") Local Static $hDllComp = DllOpen("shlwapi.dll") Local $lo, $hi, $mi, $r ; Sorting by one column For $i = 1 To $iRows - 1 $lo = 0 $hi = $i - 1 Do $mi = Int(($lo + $hi) / 2) $r = DllCall($hDllComp, 'int', 'StrCmpLogicalW', 'wstr', $aArray[$i][$iCol], 'wstr', $aArray[DllStructGetData($tIndex, 1, $mi + 1)][$iCol])[0] Switch $r Case -1 $hi = $mi - 1 Case 1 $lo = $mi + 1 Case 0 ExitLoop EndSwitch Until $lo > $hi DllCall($hDll, "none", "RtlMoveMemory", "struct*", $pIndex + ($mi + 1) * 4, "struct*", $pIndex + $mi * 4, "ulong_ptr", ($i - $mi) * 4) DllStructSetData($tIndex, 1, $i, $mi + 1 + ($lo = $mi + 1)) Next Return $tIndex EndFunc ;==>_SortArrayStruct ;======================================================================== Func _UpdateIndex(ByRef $aIndex, $iCol) If VarGetType($aIndex[$iCol]) = "DLLStruct" Then $g_tIndex = $aIndex[$iCol] Else $g_tIndex = _SortArrayStruct($g_aSubArray, $iCol, $g_iSearch) $aIndex[$iCol] = $g_tIndex ; "DLLStruct" (or "Int32" when no match found +++) EndIf EndFunc ;==>_UpdateIndex ;======================================================================== Func _MoveMarker($iCol) Local $aRect = _GUICtrlHeader_GetItemRect($g_hHeader, $iCol) ControlMove($g_hGui, "", $g_idMarker, $g_iLeftLV + $aRect[0], $g_iTopLV - 3, $aRect[2] - $aRect[0] + 1, 3) EndFunc ;==>_MoveMarker Func _GetText($iItem, $iSubItem) Local $sGetText If $g_iSortDir = 0x0400 Then ; 0x0400 = $HDF_SORTUP $sGetText = $g_aSubArray[$g_tIndex.arr($iItem + 1)][$iSubItem] Else $sGetText = $g_aSubArray[$g_tIndex.arr($g_iSearch - $iItem)][$iSubItem] EndIf Return $sGetText EndFunc ;==>_GetText Func WM_CONTEXTMENU($hWnd, $iMsg, $wParam, $lParam) #forceref $hWnd, $iMsg, $wParam, $lParam #cs Local $aMPos = MouseGetPos() Local $aLVPos = WinGetPos($g_hListView) Local $aLVCli = WinGetClientSize($g_hListView) ; includes LV headers, excludes both scrollbars (if any), great ! If $aMPos[0] > $aLVPos[0] + 1 And $aMPos[0] <= $aLVPos[0] + $aLVCli[0] + 1 _ And $aMPos[1] > $aLVPos[1] + $iHeaderHeight + 1 And $aMPos[1] <= $aLVPos[1] + $aLVCli[1] + 1 Then Local $iSelected = GUICtrlSendMsg($g_idListView, $LVM_GETNEXTITEM, -1, $LVNI_SELECTED) If $iSelected > -1 Then ; if an item is selected Local $sGetText = _GetText($iSelected, 0) MsgBox($MB_TOPMOST, "Item = " & $iSelected, "Text col 0 = " & $sGetText) EndIf Return $GUI_RUNDEFMSG Else #ce GUICtrlSendToDummy($idDummy_CancelCrop) Return 0 ; prevents the context menu to appear ;EndIf EndFunc ;==>WM_CONTEXTMENU Â
LarsJ Posted May 22, 2021 Author Posted May 22, 2021 (edited) Column alignment expandcollapse popup#AutoIt3Wrapper_Au3Check_Parameters=-d -w- 1 -w 2 -w 3 -w 4 -w 5 -w 6 -w 7 #AutoIt3Wrapper_UseX64=Y Opt( "MustDeclareVars", 1 ) #include <ComboConstants.au3> #include <EditConstants.au3> #include <GuiListView.au3> #include <GUIConstantsEx.au3> #include <StaticConstants.au3> #include <WindowsConstants.au3> #include "RandomArray.au3" Global $g_iRows = 1000, $g_iCols = 6, $g_aArray, $g_aSubArray, $g_tIndex = DllStructCreate( "uint arr[" & $g_iRows & "]" ), $g_tDefaultIndex, $g_aIndex[$g_iCols], $g_aIndexTemp[$g_iCols], $g_iSortDir Global $g_aColNames[$g_iCols] = [ "Strings", "Integers", "Floats", "Dates", "Times", "R/C" ], $g_aColWidths[$g_iCols] = [ 230, 61, 124, 70, 60, 60 ], $g_aColAligns[$g_iCols] = [ $HDF_CENTER, $HDF_RIGHT, $HDF_RIGHT, $HDF_RIGHT, $HDF_RIGHT, $HDF_RIGHT ] ; $HDF_LEFT, $HDF_RIGHT, $HDF_CENTER Global $g_hGui, $g_idListView, $g_hListView, $g_hHeader, $g_idMarker, $g_hEdit, $g_idEditDummy, $g_idComboCol, $g_idComboColDummy Global $g_sSearch, $g_iSearchCol, $g_iSearch = $g_iRows Example() Func Example() ; Generate array & one index Generate_All( $g_aArray ) $g_aSubArray = $g_aArray $g_tDefaultIndex = $g_tIndex ; Create GUI $g_hGui = GUICreate( "Virtual and Custom Drawn List View With Sorting and Incremental Search", 630 + 20, 788 + 30 + 20 ) ; Create Edit control ( search ) + dummy control Local $idEdit = GUICtrlCreateEdit( "", 120, 10, 305, 20, BitXOR( $GUI_SS_DEFAULT_EDIT, $WS_HSCROLL, $WS_VSCROLL ) ) $g_hEdit = GUICtrlGetHandle( $idEdit ) $g_idEditDummy = GUICtrlCreateDummy() ; Create ComboBox control ( how to search : RegEx or Normal ? ) Local $idSearchHow = GUICtrlCreateCombo( "RegEx search", 11, 9, 100, 20, BitOR( $GUI_SS_DEFAULT_COMBO, $CBS_DROPDOWNLIST ) ) Local $sSearchHow = "RegEx search", $sSearchHowPrev = $sSearchHow ; Default way of searching ( changeable ) GUICtrlSetData( $idSearchHow, "Normal search", $sSearchHow ) ; Create ComboBox control ( column where to search ) + dummy control GUICtrlCreateLabel( "Col", 429, 10, 20, 20, BitOR( $SS_CENTERIMAGE, $SS_CENTER ) ) $g_idComboCol = GUICtrlCreateCombo( "0", 452, 9, 41, 20, BitOR( $GUI_SS_DEFAULT_COMBO, $CBS_DROPDOWNLIST ) ) $g_iSearchCol = 0 ; Default column where to search ( changeable ) Local $iSearchColPrev = $g_iSearchCol For $i = 1 To $g_iCols - 1 GUICtrlSetData( $g_idComboCol, $i & "|", $g_iSearchCol ) Next $g_idComboColDummy = GUICtrlCreateDummy() ; Create Label control ( number of matching results ) Local $idResult = GUICtrlCreateLabel( " " & $g_iRows & " rows ( no pattern )", 501, 10, 135, 20, BitOR( $SS_CENTERIMAGE, $SS_SUNKEN ) ) ; Create ListView $g_idListView = GUICtrlCreateListView( "", 10, 40, 630, 788, BitOr( $GUI_SS_DEFAULT_LISTVIEW, $LVS_OWNERDATA ), $WS_EX_CLIENTEDGE ) _GUICtrlListView_SetExtendedListViewStyle( $g_idListView, BitOr( $LVS_EX_DOUBLEBUFFER, $LVS_EX_FULLROWSELECT ) ) $g_hListView = GUICtrlGetHandle( $g_idListView ) $g_hHeader = _GUICtrlListView_GetHeader( $g_idListView ) For $i = 0 To $g_iCols - 1 _GUICtrlListView_AddColumn( $g_idListView, $g_aColNames[$i], $g_aColWidths[$i] ) _GUICtrlHeader_SetItemFormat( $g_hHeader, $i, $HDF_STRING + $g_aColAligns[$i] ) Next ; No ListView column resizing by dragging header dividers ;_WinAPI_SetWindowLong( $hHeader, $GWL_STYLE, _WinAPI_GetWindowLong( $hHeader, $GWL_STYLE ) + $HDS_NOSIZING ) ; AutoIt 3.3.14.5 issue DllCall( "user32.dll", "long_ptr", @AutoItX64 ? "SetWindowLongPtrW" : "SetWindowLongW", "hwnd", $g_hHeader, "int", $GWL_STYLE, "long_ptr", _ DllCall( "user32.dll", "long_ptr", @AutoItX64 ? "GetWindowLongPtrW" : "GetWindowLongW", "hwnd", $g_hHeader, "int", $GWL_STYLE )[0] + $HDS_NOSIZING ) ; Create Marker ( an orange line placed above the header of the column being searched ) $g_idMarker = GUICtrlCreateLabel( "", 0, 0 ) GUICtrlSetBkColor( -1, 0xFFA060 ) ; Orange MoveMarker( $g_iSearchCol ) GUICtrlSendMsg( $g_idListView, $LVM_SETSELECTEDCOLUMN, $g_iSearchCol, 0 ) ; Sorting information $g_iSortDir = $HDF_SORTUP Local $iSortCol = 0, $iSortColPrev = 0 ; Register message handlers GUIRegisterMsg( $WM_NOTIFY, "WM_NOTIFY" ) GUIRegisterMsg( $WM_COMMAND, "WM_COMMAND" ) ; Allocate memory for ListView rows GUICtrlSendMsg( $g_idListView, $LVM_SETITEMCOUNT, $g_iRows, 0 ) ; Show GUI GUISetState( @SW_SHOW ) ; Main loop While 1 Switch GUIGetMsg() Case $g_idComboCol, $g_idComboColDummy, $idSearchHow $g_iSearchCol = GUICtrlRead( $g_idComboCol ) + 0 ; Return int $sSearchHow = GUICtrlRead( $idSearchHow ) Select Case $g_iSearchCol <> $iSearchColPrev MoveMarker( $g_iSearchCol ) ; Search column will be selected below, after ContinueCase $iSearchColPrev = $g_iSearchCol Case $sSearchHow <> $sSearchHowPrev $sSearchHowPrev = $sSearchHow Case Else ; No change in both Combo controls ( same search column, same search way ) ContinueLoop EndSelect ContinueCase Case $g_idEditDummy _GUICtrlHeader_SetItemFormat( $g_hHeader, $iSortCol, $HDF_STRING + $g_aColAligns[$iSortCol] ) $g_sSearch = GUICtrlRead( $idEdit ) $g_tIndex = $g_tDefaultIndex If $g_sSearch = "" Then ; Empty search string, display all rows $g_aSubArray = $g_aArray $g_iSearch = $g_iRows Else ; Find rows matching the search string $g_iSearch = 0 If $sSearchHow = "RegEx search" Then For $i = 0 To $g_iRows - 1 ; Duplicated For... Next for speed If StringRegExp( $g_aArray[$i][$g_iSearchCol], "(?i)" & $g_sSearch ) Then For $j = 0 To $g_iCols - 1 $g_aSubArray[$g_iSearch][$j] = $g_aArray[$i][$j] Next $g_iSearch += 1 EndIf Next Else ; "Normal search" For $i = 0 To $g_iRows - 1 ; Duplicated For... Next for speed If StringInStr( $g_aArray[$i][$g_iSearchCol], $g_sSearch ) Then For $j = 0 To $g_iCols - 1 $g_aSubArray[$g_iSearch][$j] = $g_aArray[$i][$j] Next $g_iSearch += 1 EndIf Next EndIf ; Delete eventual temporary subindexes For $i = 0 To $g_iCols - 1 If VarGetType( $g_aIndexTemp[$i] ) = "DLLStruct" Then $g_aIndexTemp[$i] = "" Next EndIf GUICtrlSendMsg( $g_idListView, $LVM_SETITEMCOUNT, $g_iSearch, 0 ) GUICtrlSendMsg( $g_idListView, $LVM_SETSELECTEDCOLUMN, $g_iSearchCol, 0 ) GUICtrlSetData( $idResult, " " & $g_iSearch & ( $g_sSearch = "" ? " rows ( no pattern )" : " matching rows" ) ) Case $g_idListView ; Sort $iSortCol = GUICtrlGetState( $g_idListView ) + 0 If $iSortCol <> $iSortColPrev Then _GUICtrlHeader_SetItemFormat( $g_hHeader, $iSortColPrev, $HDF_STRING + $g_aColAligns[$iSortColPrev] ) ; Set $g_tIndex + eventual update of $g_aIndexTemp[$iSortCol] OR $g_aIndex[$iSortCol] $i = GUICtrlRead( $idEdit ) ? UpdateIndex( $g_aIndexTemp, $iSortCol ) : UpdateIndex( $g_aIndex, $iSortCol ) $g_iSortDir = ( ( $iSortCol = $iSortColPrev ) ? ( $g_iSortDir = $HDF_SORTUP ? $HDF_SORTDOWN : $HDF_SORTUP ) : ( $HDF_SORTUP ) ) _GUICtrlHeader_SetItemFormat( $g_hHeader, $iSortCol, $HDF_STRING + $g_aColAligns[$iSortCol] + $g_iSortDir ) GUICtrlSendMsg( $g_idListView, $LVM_SETSELECTEDCOLUMN, $iSortCol, 0 ) GUICtrlSendMsg( $g_idListView, $LVM_SETITEMCOUNT, $g_iSearch, 0 ) $iSortColPrev = $iSortCol Case $GUI_EVENT_RESTORE ; Needed, or Marker goes back in 0, 0 after Restore ( why ? ) MoveMarker( $g_iSearchCol ) Case $GUI_EVENT_CLOSE ExitLoop EndSwitch WEnd ; Cleanup GUIDelete( $g_hGui ) EndFunc ;======================================================================== Func WM_NOTIFY( $hWnd, $iMsg, $wParam, $lParam ) Local $tNMHDR = DllStructCreate( $tagNMHDR, $lParam ) Switch HWnd( DllStructGetData( $tNMHDR, "hWndFrom" ) ) Case $g_hListView Switch DllStructGetData( $tNMHDR, "Code" ) Case $NM_CUSTOMDRAW Local $tCustDraw = DllStructCreate( $tagNMLVCUSTOMDRAW, $lParam ) Switch DllStructGetData( $tCustDraw, "dwDrawStage" ) ; Holds a value that specifies the drawing stage Case $CDDS_PREPAINT ; Before the paint cycle begins Return $CDRF_NOTIFYITEMDRAW ; Notify the parent window of any item-related drawing operations Case $CDDS_ITEMPREPAINT ; Before painting an item Return $CDRF_NOTIFYSUBITEMDRAW ; Notify the parent window of any subitem-related drawing operations Case $CDDS_ITEMPREPAINT + $CDDS_SUBITEM ; Before painting a subitem If ( DllStructGetData( $tCustDraw, "iSubItem" ) = $g_iSearchCol ) And $g_sSearch Then Return $CDRF_NOTIFYPOSTPAINT ; If $g_sSearch then paint $g_iSearchCol in postpaint stage Return $CDRF_NEWFONT ; $CDRF_NEWFONT must be returned after changing font or colors ; Paint all other columns in prepaint stage with default code Case $CDDS_ITEMPOSTPAINT + $CDDS_SUBITEM ; After painting a subitem ; Paints $g_iSearchCol ( $g_iSearchCol only ) if $g_sSearch Local Static $tRect = DllStructCreate( $tagRECT ), $pRect = DllStructGetPtr( $tRect ), $tSize = DllStructCreate( $tagSIZE ) Local Static $hBrushYellow = _WinAPI_CreateSolidBrush( 0x00FFFF ), $hBrushCyan = _WinAPI_CreateSolidBrush( 0xFFFF00 ) ; Yellow and cyan, BGR Local $iItem = DllStructGetData( $tCustDraw, "dwItemSpec" ), $hDC = DllStructGetData( $tCustDraw, "hDC" ) ; Subitem text and matching text Local $sSubItemText = $g_iSortDir = $HDF_SORTUP ? $g_aSubArray[$g_tIndex.arr($iItem+1)][$g_iSearchCol] _ : $g_aSubArray[$g_tIndex.arr($g_iSearch-$iItem)][$g_iSearchCol] Local $sMatch = StringRegExp( $sSubItemText, "(?i)" & $g_sSearch, 1 ), $extended = @extended, $iLen = StringLen( $sMatch[0] ) ; Entire subitem rectangle DllStructSetData( $tRect, 2, $g_iSearchCol ) ; Top DllStructSetData( $tRect, 1, $LVIR_BOUNDS ) ; Left GUICtrlSendMsg( $g_idListView, $LVM_GETSUBITEMRECT, $iItem, $pRect ) DllStructSetData( $tRect, 1, DllStructGetData( $tRect, 1 ) + 6 ) ; Left margin If Not $g_iSearchCol Then DllStructSetData( $tRect, 3, DllStructGetData( $tRect, 1 ) + GUICtrlSendMsg( $g_idListView, $LVM_GETCOLUMNWIDTH, 0, 0 ) ) ; If $g_iSearchCol = 0 (first column), the rectangle is calculated for the entire listview item. ; Compensate for this by setting the width of the rectangle to the width of the first column. ; Subitem rectangle for right and center aligned columns If $g_aColAligns[$g_iSearchCol] = $HDF_RIGHT Or $g_aColAligns[$g_iSearchCol] = $HDF_CENTER Then DllCall( "gdi32.dll", "bool", "GetTextExtentPoint32W", "handle", $hDC, "wstr", $sSubItemText, "int", StringLen( $sSubItemText ), "struct*", $tSize ) ; _WinAPI_GetTextExtentPoint32 Switch $g_aColAligns[$g_iSearchCol] Case $HDF_RIGHT DllStructSetData( $tRect, "Left", DllStructGetData( $tRect, "Right" ) - DllStructGetData( $tSize, "X" ) - 6 ) Case $HDF_CENTER DllStructSetData( $tRect, "Left", DllStructGetData( $tRect, "Left" ) + ( DllStructGetData( $tRect, "Right" ) - DllStructGetData( $tRect, "Left" ) - DllStructGetData( $tSize, "X" ) ) / 2 - 3 ) EndSwitch EndIf ; Set transparent background for the subitem DllCall( "gdi32.dll", "int", "SetBkMode", "handle", $hDC, "int", $TRANSPARENT ) ; _WinAPI_SetBkMode ; Draw entire subitem text DllStructSetData( $tRect, 2, DllStructGetData( $tRect, 2 ) + 2 ) ; Top margin DllCall( "user32.dll", "int", "DrawTextW", "handle", $hDC, "wstr", $sSubItemText, "int", StringLen( $sSubItemText ), "struct*", $tRect, "uint", 0 ) ; _WinAPI_DrawText DllStructSetData( $tRect, 2, DllStructGetData( $tRect, 2 ) - 2 ) ; Top margin ; Rectangle for matching substring DllCall( "gdi32.dll", "bool", "GetTextExtentPoint32W", "handle", $hDC, "wstr", $sSubItemText, "int", $extended - $iLen - 1, "struct*", $tSize ) ; _WinAPI_GetTextExtentPoint32 DllStructSetData( $tRect, "Left", DllStructGetData( $tRect, "Left" ) + DllStructGetData( $tSize, "X" ) ) DllCall( "gdi32.dll", "bool", "GetTextExtentPoint32W", "handle", $hDC, "wstr", $sMatch[0], "int", $iLen, "struct*", $tSize ) ; _WinAPI_GetTextExtentPoint32 DllStructSetData( $tRect, "Right", DllStructGetData( $tRect, "Left" ) + DllStructGetData( $tSize, "X" ) ) ; Fill matching rectangle with yellow or cyan background color DllCall( "user32.dll", "int", "FillRect", "handle", $hDC, "struct*", $tRect, "handle", GUICtrlSendMsg( $g_idListView, $LVM_GETITEMSTATE, $iItem, $LVIS_SELECTED ) ? $hBrushYellow : $hBrushCyan ) ; _WinAPI_FillRect ; Redraw matching text on the yellow or cyan background DllStructSetData( $tRect, 2, DllStructGetData( $tRect, 2 ) + 2 ) ; Top margin DllCall( "gdi32.dll", "int", "SetTextColor", "handle", $hDC, "int", 0x000000 ) ; _WinAPI_SetTextColor DllCall( "user32.dll", "int", "DrawTextW", "handle", $hDC, "wstr", $sMatch[0], "int", $iLen, "struct*", $tRect, "uint", 0 ) ; _WinAPI_DrawText Return $CDRF_NEWFONT ; $CDRF_NEWFONT must be returned after changing font or colors EndSwitch Case $LVN_GETDISPINFOW Local $tNMLVDISPINFO = DllStructCreate( $tagNMLVDISPINFO, $lParam ) If ( $tNMLVDISPINFO.SubItem = $g_iSearchCol ) And $g_sSearch Then Return ; Don't paint $g_iSearchCol if $g_sSearch Local Static $tText = DllStructCreate( "wchar[50]" ), $pText = DllStructGetPtr( $tText ) Local $s = $g_iSortDir = 0x0400 ? DllStructSetData( $tText, 1, $g_aSubArray[$g_tIndex.arr($tNMLVDISPINFO.Item+1)][$tNMLVDISPINFO.SubItem] ) _ ; 0x0400 = $HDF_SORTUP : DllStructSetData( $tText, 1, $g_aSubArray[$g_tIndex.arr($g_iSearch-$tNMLVDISPINFO.Item)][$tNMLVDISPINFO.SubItem] ) DllStructSetData( $tNMLVDISPINFO, "Text", $pText ) EndSwitch Case $g_hHeader Switch DllStructGetData( $tNMHDR, "Code" ) Case $NM_RCLICK Local $aHit = _GUICtrlListView_SubItemHitTest( $g_hListView ) If $aHit[1] > - 1 Then ; Valid column GUICtrlSetData( $g_idComboCol, $aHit[1] ) GUICtrlSendToDummy( $g_idComboColDummy ) EndIf EndSwitch EndSwitch Return $GUI_RUNDEFMSG #forceref $hWnd, $iMsg, $wParam, $s EndFunc Func WM_COMMAND( $hWnd, $iMsg, $wParam, $lParam ) Switch $lParam ; $hWndFrom Case $g_hEdit Switch BitShift( $wParam, 16 ) ; $iCode = High word Case $EN_CHANGE GUICtrlSendToDummy( $g_idEditDummy ) EndSwitch EndSwitch Return $GUI_RUNDEFMSG #forceref $hWnd, $iMsg EndFunc Func Generate_All( ByRef $g_aArray ) $g_aArray = FAS_Random2DArrayAu3( $g_iRows, "sifdtr", "abcdefghijklmnopqrstuvwxyz" ) For $i = 0 To $g_iRows - 1 $g_tIndex.arr( $i + 1 ) = $i Next EndFunc Func SortArrayStruct( $aArray, $iCol, $iRows ) Local Static $hDll = DllOpen( "kernel32.dll" ), $hDllComp = DllOpen( "shlwapi.dll" ) Local $tIndex = DllStructCreate( "uint arr[" & $iRows & "]" ), $pIndex = DllStructGetPtr( $tIndex ) ; Sorting by one column Local $lo, $hi, $mi For $i = 1 To $iRows - 1 $lo = 0 $hi = $i - 1 Do $mi = Int( ( $lo + $hi ) / 2 ) Switch DllCall( $hDllComp, 'int', 'StrCmpLogicalW', 'wstr', $aArray[$i][$iCol], 'wstr', $aArray[DllStructGetData($tIndex,1,$mi+1)][$iCol] )[0] Case -1 $hi = $mi - 1 Case 1 $lo = $mi + 1 Case 0 ExitLoop EndSwitch Until $lo > $hi DllCall( $hDll, "none", "RtlMoveMemory", "struct*", $pIndex + ( $mi + 1 ) * 4, "struct*", $pIndex + $mi * 4, "ulong_ptr", ( $i - $mi ) * 4 ) DllStructSetData( $tIndex, 1, $i, $mi + 1 + ( $lo = $mi + 1 ) ) Next Return $tIndex EndFunc Func UpdateIndex( ByRef $aIndex, $iCol ) If VarGetType( $aIndex[$iCol] ) = "DLLStruct" Then $g_tIndex = $aIndex[$iCol] Else $g_tIndex = SortArrayStruct( $g_aSubArray, $iCol, $g_iSearch ) $aIndex[$iCol] = $g_tIndex EndIf EndFunc Func MoveMarker( $iCol ) Local $aRect = _GUICtrlHeader_GetItemRect( $g_hHeader, $iCol ) ControlMove( $g_hGui, "", $g_idMarker, 10 + $aRect[0], 40 - 3, $aRect[2] - $aRect[0] + 1, 3 ) EndFunc The first column is centered. Other columns are right aligned. Note that alignment is set with the function _GUICtrlHeader_SetItemFormat(). ColAlign.7z Virtual listview Edited May 22, 2021 by LarsJ pixelsearch and Lion66 1 1 Controls,  File Explorer,  ROT objects,  UI Automation,  Windows Message MonitorCompiled code: Accessing AutoIt variables,  DotNet.au3 UDF,  Using C# and VB codeShell menus: The Context menu,  The Favorites menu. Shell related: Control Panel,  System Image ListsGraphics related: Rubik's Cube,  OpenGL without external libraries,  Navigating in an image,  Non-rectangular selectionsListView controls: Colors and fonts,  Multi-line header,  Multi-line items,  Checkboxes and icons,  Incremental searchListView controls: Virtual ListViews,  Editing cells,  Data display functions
pixelsearch Posted May 22, 2021 Posted May 22, 2021 (edited) Gonna look at LarsJ's last post very soon, it's sure very interesting. @Lion66 I'll post a "light" script in a new thread (in 10 min) to show how to use the Context Menu in a Listview without interfering at all with its headers. It's just courtesy towards LarsJ as it's not related to Virtual LV any more. See you there. @Norm73 It should be doable, but there are 2 ways to think of it : 1) A row should be visible as soon as at least 1 column got a match in it (which means some rows will be hidden) 2) All rows should appear constantly, even the rows having no match in them. Of course the matches will be colored (personnaly I'd prefer option 1) Thank you LarsJ for your patience & explanations Edit: nice code in your Column alignment script, so easy when you think of it... first the entire subitem rectangle, then the smaller text rectangle (never heard of GetTextExtentPoint32W before) then the smaller matching rectangle, just like a set of matryoshkas... and Left became Right Case $HDF_RIGHT DllStructSetData( $tRect, "Left", DllStructGetData( $tRect, "Right" ) - DllStructGetData( $tSize, "X" ) - 6 ) Â Edited May 23, 2021 by pixelsearch
Norm73 Posted May 23, 2021 Posted May 23, 2021 6 hours ago, pixelsearch said: 1) A row should be visible as soon as at least 1 column got a match in it (which means some rows will be hidden) I realized the search like this: Spoiler Else ; "Normal search" Local $nM For $i = 0 To $g_iRows - 1 ; duplicated For... Next for speed $nM = 0 For $j = 0 To $g_iCols - 1 If StringInStr($g_aArray[$i][$j], $g_sSearch) Then $nM = 1 ExitLoop EndIf Next If $nM = 1 Then For $j = 0 To $g_iCols - 1 $g_aSubArray[$g_iSearch][$j] = $g_aArray[$i][$j] Next $g_iSearch += 1 EndIf Next EndIf  I can't figure out how to mark the found rows in all columns at the same time. At this point my autoit knowledge is unfortunately at an end. pixelsearch 1
Lion66 Posted May 23, 2021 Posted May 23, 2021 Thank you LarsJ. Great job! Special thanks for the explanations. Â
pixelsearch Posted May 23, 2021 Posted May 23, 2021 (edited) On 5/22/2021 at 12:07 PM, Norm73 said: For example, if I wrote the number 7 so that this number would appear in all columns. Here we go, version "2m" expandcollapse popup#include <ComboConstants.au3> #include <EditConstants.au3> #include <GuiListView.au3> #include <GUIConstantsEx.au3> #include <StaticConstants.au3> #include <WindowsConstants.au3> #include "RandomArray.au3" ; LarsJ #include "DrawItem.au3" ; " Opt("MustDeclareVars", 1) Global $g_iRows = 1000, $g_iCols = 6, $g_iLeftLV = 10, $g_iTopLV = 40, $g_hGui, $g_hListView, $g_hHeader, $g_hEdit Global $g_aCols = ["Strings", "Integers", "Floats", "Dates", "Times", "R/C"], $g_aWidths = [230, 61, 124, 70, 60, 60] Global $g_idListView, $g_idMarker, $g_idComboCol, $g_idComboColDummy, $g_idEditDummy Global $g_sSearch, $g_iSearchCol, $g_iSortDir, $g_iSearch = $g_iRows Global $g_aArray, $g_aSubArray, $g_tDefaultIndex, $g_tIndex = DllStructCreate("uint arr[" & $g_iRows & "]") Global $g_aIndex[$g_iCols], $g_aIndexTemp[$g_iCols] ; VarGetType's : $g_aIndex => "Array", $g_aIndex[0] => "String" Global $fListViewHasFocus = 1 ; trying this for now, we'll see... Example() Func Example() ; Generate array & one index _Generate_All($g_aArray) $g_aSubArray = $g_aArray $g_tDefaultIndex = $g_tIndex ; Create GUI $g_hGui = GUICreate("Virtual ListView + match all columns (2m)", 630 + 20, 788 + 30 + 20) ; Create Edit control (search) + dummy control Local $idEdit = GUICtrlCreateEdit("", 120, 10, 305, 20, BitXOR($GUI_SS_DEFAULT_EDIT, $WS_HSCROLL, $WS_VSCROLL)) $g_hEdit = GUICtrlGetHandle($idEdit) $g_idEditDummy = GUICtrlCreateDummy() ; Create ComboBox control (how to search : RegEx or Normal ?) Local $idSearchHow = GUICtrlCreateCombo("RegEx search", 11, 9, 100, 20, BitOR($GUI_SS_DEFAULT_COMBO, $CBS_DROPDOWNLIST)) Local $sSearchHow = "RegEx search", $sSearchHowPrev = $sSearchHow ; default way of searching (changeable) GUICtrlSetData($idSearchHow, "Normal search", $sSearchHow) ; Create ComboBox control (column where to search) + dummy control GUICtrlCreateLabel("Col", 429, 10, 20, 20, BitOR($SS_CENTERIMAGE, $SS_CENTER)) $g_idComboCol = GUICtrlCreateCombo("0", 452, 9, 41, 20, BitOR($GUI_SS_DEFAULT_COMBO, $CBS_DROPDOWNLIST)) $g_iSearchCol = 0 ; default column where to search (changeable) Local $iSearchColPrev = $g_iSearchCol For $i = 1 To $g_iCols - 1 GUICtrlSetData($g_idComboCol, $i & "|", $g_iSearchCol) Next $g_idComboColDummy = GUICtrlCreateDummy() ; Create Label control (number of matching results) Local $idResult = GUICtrlCreateLabel(" " & $g_iRows & " rows (no pattern)", 501, 10, 135, 20, BitOR($SS_CENTERIMAGE, $SS_SUNKEN)) ; Create ListView $g_idListView = GUICtrlCreateListView("", $g_iLeftLV, $g_iTopLV, 630, 788, BitOr($LVS_OWNERDATA, $LVS_OWNERDRAWFIXED), $WS_EX_CLIENTEDGE) _GUICtrlListView_SetExtendedListViewStyle($g_idListView, BitOr($LVS_EX_DOUBLEBUFFER, $LVS_EX_FULLROWSELECT)) $g_hListView = GUICtrlGetHandle($g_idListView) $g_hHeader = _GUICtrlListView_GetHeader($g_idListView) For $i = 0 To $g_iCols - 1 _GUICtrlListView_AddColumn($g_idListView, $g_aCols[$i], $g_aWidths[$i]) Next ; Create Marker (an orange line placed above the header of the column being searched) $g_idMarker = GUICtrlCreateLabel("", 0, 0) GUICtrlSetBkColor(-1, 0xFFA060) ; orange _MoveMarker($g_iSearchCol) _GUICtrlListView_SetSelectedColumn($g_idListView, $g_iSearchCol) ; Sorting information $g_iSortDir = 0x0400 ; $HDF_SORTUP Local $iSortCol = -1, $iSortColPrev = -1 GUIRegisterMsg($WM_DRAWITEM, "WM_DRAWITEM") GUIRegisterMsg($WM_NOTIFY, "WM_NOTIFY") ; for LV header only GUIRegisterMsg($WM_COMMAND, "WM_COMMAND") GUICtrlSendMsg($g_idListView, $LVM_SETITEMCOUNT, $g_iRows, 0) GUISetState(@SW_SHOW) While 1 Switch GUIGetMsg() Case $GUI_EVENT_CLOSE ExitLoop Case $g_idComboCol, $g_idComboColDummy, $idSearchHow $g_iSearchCol = GUICtrlRead($g_idComboCol) $sSearchHow = GUICtrlRead($idSearchHow) Select Case $g_iSearchCol <> $iSearchColPrev _MoveMarker($g_iSearchCol) ; Search column will be selected below, after ContinueCase $iSearchColPrev = $g_iSearchCol Case $sSearchHow <> $sSearchHowPrev $sSearchHowPrev = $sSearchHow Case Else ; no change in both Combo controls (same search column, same search way) ContinueLoop EndSelect ContinueCase Case $g_idEditDummy _GUICtrlHeader_SetItemFormat($g_hHeader, $iSortCol, $HDF_STRING) $g_sSearch = GUICtrlRead($idEdit) $g_tIndex = $g_tDefaultIndex If $g_sSearch = "" Then ; Empty search string, display all rows $g_aSubArray = $g_aArray $g_iSearch = $g_iRows Else ; Find rows matching the search string $g_iSearch = 0 If $sSearchHow = "Normal search" Then ; all searches use RegEx => escape 12 + 1 metacharacters $g_sSearch = StringRegExpReplace($g_sSearch, "(\\|\.|\^|\$|\||\[|\(|\{|\*|\+|\?|\#|\))" , "\\$1") EndIf ; ConsoleWrite("$sSearchHow = " & $sSearchHow & @TAB & "$g_sSearch = " & $g_sSearch & @lf) For $i = 0 To $g_iRows - 1 For $j = 0 To $g_iCols - 1 If StringRegExp($g_aArray[$i][$j], "(?i)" & $g_sSearch) Then For $k = 0 To $g_iCols - 1 $g_aSubArray[$g_iSearch][$k] = $g_aArray[$i][$k] Next $g_iSearch += 1 ContinueLoop 2 EndIf Next Next ; Delete eventual temporary subindexes For $i = 0 To $g_iCols - 1 If VarGetType($g_aIndexTemp[$i]) = "DLLStruct" Then $g_aIndexTemp[$i] = "" ; "String" Next EndIf GUICtrlSetData($idResult, " " & $g_iSearch & ($g_sSearch = "" ? " rows (no pattern)" : " matching rows")) GUICtrlSendMsg($g_idListView, $LVM_SETITEMCOUNT, $g_iSearch, 0) _GUICtrlListView_SetSelectedColumn($g_hListView, $g_iSearchCol) ; seems ok here (after $LVM_SETITEMCOUNT) Case $g_idListView ; Sort $iSortCol = GUICtrlGetState($g_idListView) If $iSortCol <> $iSortColPrev Then _GUICtrlHeader_SetItemFormat($g_hHeader, $iSortColPrev, $HDF_STRING) EndIf ; Set $g_tIndex + eventual update of $g_aIndexTemp[$iSortCol] OR $g_aIndex[$iSortCol] If GUICtrlRead($idEdit) Then _UpdateIndex($g_aIndexTemp, $iSortCol) Else _UpdateIndex($g_aIndex, $iSortCol) EndIf $g_iSortDir = (($iSortCol = $iSortColPrev) ? ($g_iSortDir = $HDF_SORTUP ? $HDF_SORTDOWN : $HDF_SORTUP) : ($HDF_SORTUP)) _GUICtrlHeader_SetItemFormat($g_hHeader, $iSortCol, $HDF_STRING + $g_iSortDir) GUICtrlSendMsg($g_idListView, $LVM_SETSELECTEDCOLUMN, $iSortCol, 0) GUICtrlSendMsg($g_idListView, $LVM_SETITEMCOUNT, $g_iSearch, 0) $iSortColPrev = $iSortCol Case $GUI_EVENT_RESTORE ; needed, or Marker goes back in 0, 0 after Restore (why ?) _MoveMarker($g_iSearchCol) EndSwitch WEnd ; Cleanup GUIDelete($g_hGui) EndFunc ;==>Example ;======================================================================== Func WM_DRAWITEM( $hWnd, $iMsg, $wParam, $lParam ) ; Display items in an owner drawn ListView Local Static $tRect = DllStructCreate( $tagRECT ), $pRect = DllStructGetPtr( $tRect ), $tSize = DllStructCreate( $tagSIZE ) Local Static $hBrushYellow = _WinAPI_CreateSolidBrush( 0xFFFF00 ), $hBrushCyan = _WinAPI_CreateSolidBrush( 0x00FFFF ) ; Yellow and cyan, BGR Local Static $hBrushHighLight = _WinAPI_GetSysColorBrush( $COLOR_HIGHLIGHT ), $hBrushButtonFace = _WinAPI_GetSysColorBrush( $COLOR_BTNFACE ) ; We can optimize code by removing Switch statements because the ListView is the only ownerdrawn control and only $ODA_DRAWENTIRE actions are present Local $tDrawItem = DllStructCreate( $tagDRAWITEM, $lParam ), $itemID = DllStructGetData( $tDrawItem, "itemID" ), $iState = DllStructGetData( $tDrawItem, "itemState" ), $hDC = DllStructGetData( $tDrawItem, "hDC" ), $sItemText ; Loop through columns ($i is the column index) For $i = 0 To $g_iCols - 1 ; Subitem rectangle DllStructSetData( $tRect, 2, $i ) ; Top DllStructSetData( $tRect, 1, $LVIR_BOUNDS ) ; Left GUICtrlSendMsg( $g_idListView, $LVM_GETSUBITEMRECT, $itemID, $pRect ) DllStructSetData( $tRect, 1, DllStructGetData( $tRect, 1 ) + 6 ) ; Left margin DllStructSetData( $tRect, 2, DllStructGetData( $tRect, 2 ) + 2 ) ; Top margin ; Subitem background and text color If BitAND( $iState, $ODS_SELECTED ) Then DllCall( "user32.dll", "int", "FillRect", "handle", $hDC, "struct*", $tRect, "handle", $fListViewHasFocus = 1 ? $hBrushHighLight : $hBrushButtonFace ) ; _WinAPI_FillRect DllCall( "gdi32.dll", "int", "SetTextColor", "handle", $hDC, "int", BitAND( $iState, $ODS_SELECTED ) ? $fListViewHasFocus = 1 ? 0xFFFFFF : 0x000000 : 0x000000 ) ; _WinAPI_SetTextColor ; Draw subitem text If $g_iSortDir = 0x0400 Then ; 0x0400 = $HDF_SORTUP $sItemText = $g_aSubArray[$g_tIndex.arr($itemID + 1)][$i] Else $sItemText = $g_aSubArray[$g_tIndex.arr($g_iSearch - $itemID)][$i] EndIf DllCall( "user32.dll", "int", "DrawTextW", "handle", $hDC, "wstr", $sItemText, "int", StringLen( $sItemText ), "struct*", $tRect, "uint", 0 ) ; _WinAPI_DrawText ; Mark matching substring if found in ANY column If $g_sSearch Then Local $sMatch = StringRegExp( $sItemText, "(?i)" & $g_sSearch, 1 ) If Not @error Then ; match found Local $extended = @extended, $iLen = StringLen( $sMatch[0] ) ; Rectangle for matching substring DllCall( "gdi32.dll", "bool", "GetTextExtentPoint32W", "handle", $hDC, "wstr", $sItemText, "int", $extended - $iLen - 1, "struct*", $tSize ) ; _WinAPI_GetTextExtentPoint32 DllStructSetData( $tRect, "Left", DllStructGetData( $tRect, "Left" ) + DllStructGetData( $tSize, "X" ) ) DllCall( "gdi32.dll", "bool", "GetTextExtentPoint32W", "handle", $hDC, "wstr", $sMatch[0], "int", $iLen, "struct*", $tSize ) ; _WinAPI_GetTextExtentPoint32 DllStructSetData( $tRect, "Right", DllStructGetData( $tRect, "Left" ) + DllStructGetData( $tSize, "X" ) ) ; Fill rectangle with yellow or cyan (selected) background color DllCall( "user32.dll", "int", "FillRect", "handle", $hDC, "struct*", $tRect, "handle", BitAND( $iState, $ODS_SELECTED ) ? $hBrushCyan : $hBrushYellow ) ; _WinAPI_FillRect ; Draw matching substring in rectangle DllCall( "gdi32.dll", "int", "SetTextColor", "handle", $hDC, "int", 0x000000 ) ; _WinAPI_SetTextColor DllCall( "user32.dll", "int", "DrawTextW", "handle", $hDC, "wstr", $sMatch[0], "int", $iLen, "struct*", $tRect, "uint", 0 ) ; _WinAPI_DrawText EndIf EndIf Next Return $GUI_RUNDEFMSG #forceref $hWnd, $iMsg, $wParam EndFunc ;======================================================================== Func WM_NOTIFY($hWnd, $iMsg, $wParam, $lParam) Local $tNMHEADER = DllStructCreate($tagNMHEADER, $lParam) Switch HWnd(DllStructGetData($tNMHEADER, "hWndFrom")) Case $g_hHeader Local $iCode = DllStructGetData($tNMHEADER, "Code") Switch $iCode Case $HDN_ENDTRACKW _MoveMarker(GUICtrlRead($g_idComboCol)) Case $HDN_DIVIDERDBLCLICKW Local $iCol = DllStructGetData($tNMHEADER, "Item") _GUICtrlListView_SetColumnWidth($g_idListView, $iCol, $g_aWidths[$iCol]) ; initial size _MoveMarker(GUICtrlRead($g_idComboCol)) Case $NM_RCLICK Local $aHit = _GUICtrlListView_SubItemHitTest($g_hListView) ; $aHit[1] : 0-based index of the LV subitem... i.e. the column in our case (may be -1 if right click on empty part of header) If $aHit[1] > - 1 Then ; valid column GUICtrlSetData($g_idComboCol, $aHit[1]) GUICtrlSendToDummy($g_idComboColDummy) EndIf EndSwitch EndSwitch Return $GUI_RUNDEFMSG EndFunc ;==>WM_NOTIFY ;======================================================================== Func WM_COMMAND($hWnd, $iMsg, $wParam, $lParam) Local $hWndFrom = $lParam Local $iCode = BitShift($wParam, 16) ; High word Switch $hWndFrom Case $g_hEdit Switch $iCode Case $EN_CHANGE GUICtrlSendToDummy($g_idEditDummy) EndSwitch EndSwitch Return $GUI_RUNDEFMSG EndFunc ;==>WM_COMMAND ;======================================================================== Func _Generate_All(ByRef $g_aArray) ConsoleWrite("$g_iRows = " & $g_iRows & " $g_iCols = " & $g_iCols & @CRLF) Local $hTimer = TimerInit() $g_aArray = FAS_Random2DArrayAu3($g_iRows, "sifdtr", "abcdefghijklmnopqrstuvwxyz") ; $g_aArray = FAS_Random2DArrayAu3($g_iRows, "sifdtr", "abcdefghijklmnopqrstuvwxyz" & "\.^$|[({*+?#)") ; 12 + 1 RegEx metacharacters For $i = 0 To $g_iRows - 1 $g_tIndex.arr($i + 1) = $i Next ConsoleWrite("Generating array & one index = " & TimerDiff($hTimer) & @CRLF & @CRLF) EndFunc ;==>_Generate_All ;======================================================================== Func _SortArrayStruct(Const ByRef $aArray, $iCol, $iRows) Local $tIndex = DllStructCreate("uint arr[" & $iRows & "]") Local $pIndex = DllStructGetPtr($tIndex) Local Static $hDll = DllOpen("kernel32.dll") Local Static $hDllComp = DllOpen("shlwapi.dll") Local $lo, $hi, $mi, $r ; Sorting by one column For $i = 1 To $iRows - 1 $lo = 0 $hi = $i - 1 Do $mi = Int(($lo + $hi) / 2) $r = DllCall($hDllComp, 'int', 'StrCmpLogicalW', 'wstr', $aArray[$i][$iCol], 'wstr', $aArray[DllStructGetData($tIndex, 1, $mi + 1)][$iCol])[0] Switch $r Case -1 $hi = $mi - 1 Case 1 $lo = $mi + 1 Case 0 ExitLoop EndSwitch Until $lo > $hi DllCall($hDll, "none", "RtlMoveMemory", "struct*", $pIndex + ($mi + 1) * 4, "struct*", $pIndex + $mi * 4, "ulong_ptr", ($i - $mi) * 4) DllStructSetData($tIndex, 1, $i, $mi + 1 + ($lo = $mi + 1)) Next Return $tIndex EndFunc ;==>_SortArrayStruct ;======================================================================== Func _UpdateIndex(ByRef $aIndex, $iCol) If VarGetType($aIndex[$iCol]) = "DLLStruct" Then $g_tIndex = $aIndex[$iCol] Else $g_tIndex = _SortArrayStruct($g_aSubArray, $iCol, $g_iSearch) $aIndex[$iCol] = $g_tIndex ; "DLLStruct" (or "Int32" when no match found +++) EndIf EndFunc ;==>_UpdateIndex ;======================================================================== Func _MoveMarker($iCol) Local $aRect = _GUICtrlHeader_GetItemRect($g_hHeader, $iCol) ControlMove($g_hGui, "", $g_idMarker, $g_iLeftLV + $aRect[0], $g_iTopLV - 3, $aRect[2] - $aRect[0] + 1, 3) EndFunc ;==>_MoveMarker Many controls become irrelevant (combo to switch columns, orange marker, right click on headers etc...) because the number of matched rows is now the same, no matter the searched column. Anyway I'm keeping all controls untouched, better have more than less More important : something has to be improved in all these scripts (even LarsJ got the same problem, just tested). I'll prepare a new post to indicate the issue. Â Edit: update May 24th 2021 : fixed 'Normal Search' which includes RegEx metacharacters, for example a "." search in Normal search now returns correct matches (pic below) Edited May 24, 2021 by pixelsearch Script updated on May 24th, 2021 Norm73 1
pixelsearch Posted May 23, 2021 Posted May 23, 2021 @LarsJ I notice an issue in all these scripts, here is a way to reproduce it in one of yours (post titled "Virtual listview" on page before) : * Please right click on "Floats" header (or use Combo) . "Floats" will become the "search column" * Search Field, type . * All 1st characters of the Float column will have a cyan background (because of . in RegEx search) and this is correct. * Now change the Search method to "Normal Search" and a wrong result appears : Dots in "Floats" column should have a cyan background instead of the 1st character. This is because StringRegExp is used in all cases (in the handler function) even when user wants a Normal search. Then all RegEx metacharacters behave badly during a Normal search (if not escaped in StringRegExp) \ . ^ $ | [ ( { * + ? # Escaping them seems challenging to script, in case the user wants a Normal search and these characters are found in the Search Field. Another simpler way could be, during the message treatment ($NM_CUSTOMDRAW or $WM_DRAWITEM) to use the same test that was used for the search (i.e. StringRegExp Or StringInStr), though StringInStr could be slower in this case (?) This RegEx line will be easy to adapt to StringInStr Local $extended = @extended, $iLen = StringLen( $sMatch[0] ) I faced this issue while testing the script adapted to all columns :
LarsJ Posted May 23, 2021 Author Posted May 23, 2021 Turn $sSearchHow into a global variable. And replace these lines: ; Subitem text and matching text Local $sSubItemText = $g_iSortDir = 0x0400 ? $g_aSubArray[$g_tIndex.arr($iItem + 1)][$g_iSearchCol] _ ; 0x0400 = $HDF_SORTUP : $g_aSubArray[$g_tIndex.arr($g_iSearch - $iItem)][$g_iSearchCol] Local $sMatch = StringRegExp( $sSubItemText, "(?i)" & $g_sSearch, 1 ), $extended = @extended, $iLen = StringLen( $sMatch[0] ) with these lines: ; Subitem text and matching text Local $sSubItemText = $g_iSortDir = 0x0400 ? $g_aSubArray[$g_tIndex.arr($iItem + 1)][$g_iSearchCol] _ ; 0x0400 = $HDF_SORTUP : $g_aSubArray[$g_tIndex.arr($g_iSearch - $iItem)][$g_iSearchCol], $sMatch, $extended, $iLen If $g_sSearchHow = "RegEx search" Then Local $aMatch = StringRegExp( $sSubItemText, "(?i)" & $g_sSearch, 1 ) $extended = @extended $sMatch = $aMatch[0] Else $iLen = StringLen( $g_sSearch ) Local $iPos = StringInStr( $sSubItemText, $g_sSearch ) $sMatch = StringMid( $sSubItemText, $iPos, $iLen ) $extended = $iPos + $iLen EndIf $iLen = StringLen( $sMatch )  Norm73 1 Controls,  File Explorer,  ROT objects,  UI Automation,  Windows Message MonitorCompiled code: Accessing AutoIt variables,  DotNet.au3 UDF,  Using C# and VB codeShell menus: The Context menu,  The Favorites menu. Shell related: Control Panel,  System Image ListsGraphics related: Rubik's Cube,  OpenGL without external libraries,  Navigating in an image,  Non-rectangular selectionsListView controls: Colors and fonts,  Multi-line header,  Multi-line items,  Checkboxes and icons,  Incremental searchListView controls: Virtual ListViews,  Editing cells,  Data display functions
Norm73 Posted May 24, 2021 Posted May 24, 2021 (edited) Thank you LarsJ and Pixelsearch@Pixelsearch I used the correction from LarsJ and now everything works great. 18 hours ago, pixelsearch said: Anyway I'm keeping all controls untouched, better have more than less You are right, you don't have to do without it. Make the search even more flexible.   All | 0 | 1 | 2 | 3 | 4 .... I have one more request. Your virtual ListView with the search can be used in many cases. But there are many lists where the content may not be changed. For example, a log protocol. How can you do this in such a way that the lines are not deleted, but the first one found is scrolled up? Similar to _GUICtrlListView_EnsureVisible. For example, if I sort your list in column 0 and then search in RegExp mode like this ^ u. In this case, the list should not get smaller, but should be scrolled up. It won't be hard to realize in order for the lines to stay in place. I have no idea how to implement the analog of the _GUICtrlListView_EnsureVisible() function.  Edited May 24, 2021 by Norm73
Norm73 Posted May 24, 2021 Posted May 24, 2021 (edited) Sorry, accidentally created the message Edited May 24, 2021 by Norm73
Lion66 Posted May 24, 2021 Posted May 24, 2021 (edited) 10 hours ago, Norm73 said: Make the search even more flexible.   All | 0 | 1 | 2 | 3 | 4 .... I support the request 😃 Edited May 24, 2021 by Lion66
pixelsearch Posted May 24, 2021 Posted May 24, 2021 (edited) @Norm73 I'm glad the changes indicated by LarsJ fixed the issue. As I like challenges, then I just scripted the fix in another way (no more StringInStr, all searches are done using RegEx, even when user chooses "Normal Search") and without touching $NM_CUSTOMDRAW or $WM_DRAWITEM code. Below is the code found in amended script "2m" which has just been updated accordingly. Other older scripts should be amended soon. Old code : ; Find rows matching the search string $g_iSearch = 0 If $sSearchHow = "RegEx search" Then For $i = 0 To $g_iRows - 1 ; duplicated For... Next for speed For $j = 0 To $g_iCols - 1 If StringRegExp($g_aArray[$i][$j], "(?i)" & $g_sSearch) Then For $k = 0 To $g_iCols - 1 $g_aSubArray[$g_iSearch][$k] = $g_aArray[$i][$k] Next $g_iSearch += 1 ContinueLoop 2 EndIf Next Next Else ; "Normal search" For $i = 0 To $g_iRows - 1 ; duplicated For... Next for speed For $j = 0 To $g_iCols - 1 If StringInStr($g_aArray[$i][$j], $g_sSearch) Then For $k = 0 To $g_iCols - 1 $g_aSubArray[$g_iSearch][$k] = $g_aArray[$i][$k] Next $g_iSearch += 1 ContinueLoop 2 EndIf Next Next EndIf New code : ; Find rows matching the search string $g_iSearch = 0 If $sSearchHow = "Normal search" Then ; all searches use RegEx => escape 12 + 1 metacharacters $g_sSearch = StringRegExpReplace($g_sSearch, "(\\|\.|\^|\$|\||\[|\(|\{|\*|\+|\?|\#|\))" , "\\$1") EndIf ; ConsoleWrite("$sSearchHow = " & $sSearchHow & @TAB & "$g_sSearch = " & $g_sSearch & @lf) For $i = 0 To $g_iRows - 1 For $j = 0 To $g_iCols - 1 If StringRegExp($g_aArray[$i][$j], "(?i)" & $g_sSearch) Then For $k = 0 To $g_iCols - 1 $g_aSubArray[$g_iSearch][$k] = $g_aArray[$i][$k] Next $g_iSearch += 1 ContinueLoop 2 EndIf Next Next The fix is based, when user chooses Normal search, in escaping all (eventual) 12 metacharacters indicated in AutoIt help file (topic StringRegExp) which are : \.^$|[({*+?# But I notice a 13th metacharacter indicated on PCRE web site (Perl Compatible Regular Expressions) and AutoIt uses the PCRE engine. This 13th meta is ")" and it's really a metacharacter that you can check after uncommenting a ConsoleWrite line in "2m" and create the array using the alternate line (also found in "2m") : ; ConsoleWrite("$sSearchHow = " & $sSearchHow & @TAB & "$g_sSearch = " & $g_sSearch & @lf) ... $g_aArray = FAS_Random2DArrayAu3($g_iRows, "sifdtr", "abcdefghijklmnopqrstuvwxyz") ; $g_aArray = FAS_Random2DArrayAu3($g_iRows, "sifdtr", "abcdefghijklmnopqrstuvwxyz" & "\.^$|[({*+?#)") ; 12 + 1 RegEx metacharacters ... Now if you search for ")" , without quotes of course, then no matches are found with "RegEx Search", which indicates (at least for me) that we just faced a metacharacter, because if you switch to "Normal Search", then ")" will appear in the results. Here is what ConsoleWrite will show : $sSearchHow = RegEx search $g_sSearch = ) $sSearchHow = Normal search $g_sSearch = \) The "." search (that revealed the issue) now works normally in amended "2m" ConsoleWrite : $sSearchHow = RegEx search $g_sSearch = . $sSearchHow = Normal search $g_sSearch = \. Concerning your other questions, I'll see what's doable when I have some time. Dinner time Edited May 25, 2021 by pixelsearch typo Norm73 1
pixelsearch Posted May 25, 2021 Posted May 25, 2021 9 hours ago, Lion66 said: 20 hours ago, Norm73 said: Make the search even more flexible.   All | 0 | 1 | 2 | 3 | 4 .... I support the request 😃 Done in script "2p" below (while everything is still fresh !) * Note how the orange marker is placed above all headers when user wants to search all columns. * Right-click a header acts same as in preceding scripts (search in this column only + appropriate orange marker) Though we read "All" in the ComboBox, the corresponding global variable $g_iSearchCol = -1 in this case (by design) . It's important to remember this point in case someone reworks the script : - 1 means search in all columns, while 0, 1, 2... means search in one column only (col 0, 1, 2) I wonder if all these scripts should be zipped together and placed I don't know where... but as they all concern "Incremental search in owner and custom drawn ListViews" (LarsJ new title for this thread) well... maybe they are at their right place expandcollapse popup#include <ComboConstants.au3> #include <EditConstants.au3> #include <GuiListView.au3> #include <GUIConstantsEx.au3> #include <StaticConstants.au3> #include <WindowsConstants.au3> #include "RandomArray.au3" ; LarsJ #include "DrawItem.au3" ; " Opt("MustDeclareVars", 1) Global $g_iRows = 1000, $g_iCols = 6, $g_hGui, $g_hListView, $g_hHeader, $g_hEdit Global $g_aCols = ["Strings", "Integers", "Floats", "Dates", "Times", "R/C"], $g_aWidths = [230, 61, 124, 70, 60, 60] Global $g_idListView, $g_idMarker, $g_idComboCol, $g_idComboColDummy, $g_idEditDummy Global $g_sSearch, $g_iSearchCol, $g_iSortDir, $g_iSearch = $g_iRows Global $g_aArray, $g_aSubArray, $g_tDefaultIndex, $g_tIndex = DllStructCreate("uint arr[" & $g_iRows & "]") Global $g_aIndex[$g_iCols], $g_aIndexTemp[$g_iCols] ; VarGetType's : $g_aIndex => "Array", $g_aIndex[0] => "String" Global $fListViewHasFocus = 1 ; trying this for now, we'll see... Example() Func Example() ; Generate array & one index _Generate_All($g_aArray) $g_aSubArray = $g_aArray $g_tDefaultIndex = $g_tIndex ; Create GUI $g_hGui = GUICreate("Virtual ListView + match 1 or All columns (2p)", 630 + 20, 788 + 30 + 20) ; Create Edit control (search) + dummy control Local $idEdit = GUICtrlCreateEdit("", 120, 10, 305, 20, BitXOR($GUI_SS_DEFAULT_EDIT, $WS_HSCROLL, $WS_VSCROLL)) $g_hEdit = GUICtrlGetHandle($idEdit) $g_idEditDummy = GUICtrlCreateDummy() ; Create ComboBox control (how to search : RegEx or Normal ?) Local $idSearchHow = GUICtrlCreateCombo("RegEx search", 11, 9, 100, 20, BitOR($GUI_SS_DEFAULT_COMBO, $CBS_DROPDOWNLIST)) Local $sSearchHow = "RegEx search", $sSearchHowPrev = $sSearchHow ; default way of searching (changeable) GUICtrlSetData($idSearchHow, "Normal search", $sSearchHow) ; Create ComboBox control (column where to search, possible All) + dummy control GUICtrlCreateLabel("Col", 429, 10, 20, 20, BitOR($SS_CENTERIMAGE, $SS_CENTER)) $g_idComboCol = GUICtrlCreateCombo("All", 452, 9, 41, 20, BitOR($GUI_SS_DEFAULT_COMBO, $CBS_DROPDOWNLIST)) Local $sSearchCol = "All" ; default column where to search (changeable) => becomes $g_iSearchCol $g_iSearchCol = ($sSearchCol == "All" ? - 1 : Number($sSearchCol)) ; - 1 means search All columns Local $iSearchColPrev = $g_iSearchCol For $i = 0 To $g_iCols - 1 GUICtrlSetData($g_idComboCol, $i & "|", $g_iSearchCol) Next $g_idComboColDummy = GUICtrlCreateDummy() ; Create Label control (number of matching results) Local $idResult = GUICtrlCreateLabel(" " & $g_iRows & " rows (no pattern)", 501, 10, 135, 20, BitOR($SS_CENTERIMAGE, $SS_SUNKEN)) ; Create ListView $g_idListView = GUICtrlCreateListView("", 10, 40, 630, 788, BitOr($LVS_OWNERDATA, $LVS_OWNERDRAWFIXED), $WS_EX_CLIENTEDGE) _GUICtrlListView_SetExtendedListViewStyle($g_idListView, BitOr($LVS_EX_DOUBLEBUFFER, $LVS_EX_FULLROWSELECT)) $g_hListView = GUICtrlGetHandle($g_idListView) $g_hHeader = _GUICtrlListView_GetHeader($g_idListView) For $i = 0 To $g_iCols - 1 _GUICtrlListView_AddColumn($g_idListView, $g_aCols[$i], $g_aWidths[$i]) Next ; No ListView column resizing by dragging header dividers (LarsJ) ;_WinAPI_SetWindowLong( $hHeader, $GWL_STYLE, _WinAPI_GetWindowLong( $hHeader, $GWL_STYLE ) + $HDS_NOSIZING ) ; AutoIt 3.3.14.5 issue DllCall( "user32.dll", "long_ptr", @AutoItX64 ? "SetWindowLongPtrW" : "SetWindowLongW", "hwnd", $g_hHeader, "int", $GWL_STYLE, "long_ptr", _ DllCall( "user32.dll", "long_ptr", @AutoItX64 ? "GetWindowLongPtrW" : "GetWindowLongW", "hwnd", $g_hHeader, "int", $GWL_STYLE )[0] + $HDS_NOSIZING ) ; Create Marker (an orange line placed above the header of the column being searched) $g_idMarker = GUICtrlCreateLabel("", 0, 0) GUICtrlSetBkColor(-1, 0xFFA060) ; orange _MoveMarker($g_iSearchCol) _GUICtrlListView_SetSelectedColumn($g_idListView, $g_iSearchCol) ; Sorting information $g_iSortDir = 0x0400 ; $HDF_SORTUP Local $iSortCol = -1, $iSortColPrev = -1 GUIRegisterMsg($WM_DRAWITEM, "WM_DRAWITEM") GUIRegisterMsg($WM_NOTIFY, "WM_NOTIFY") ; for LV header only GUIRegisterMsg($WM_COMMAND, "WM_COMMAND") GUICtrlSendMsg($g_idListView, $LVM_SETITEMCOUNT, $g_iRows, 0) GUISetState(@SW_SHOW) While 1 Switch GUIGetMsg() Case $GUI_EVENT_CLOSE ExitLoop Case $g_idComboCol, $g_idComboColDummy, $idSearchHow $sSearchCol = GUICtrlRead($g_idComboCol) $g_iSearchCol = ($sSearchCol == "All" ? - 1 : Number($sSearchCol)) ; - 1 means search All columns $sSearchHow = GUICtrlRead($idSearchHow) Select Case $g_iSearchCol <> $iSearchColPrev _MoveMarker($g_iSearchCol) ; Search column will be selected below, after ContinueCase $iSearchColPrev = $g_iSearchCol Case $sSearchHow <> $sSearchHowPrev $sSearchHowPrev = $sSearchHow Case Else ; no change in both Combo controls (same search column, same search way) ContinueLoop EndSelect ContinueCase Case $g_idEditDummy _GUICtrlHeader_SetItemFormat($g_hHeader, $iSortCol, $HDF_STRING) $g_sSearch = GUICtrlRead($idEdit) $g_tIndex = $g_tDefaultIndex If $g_sSearch = "" Then ; Empty search string, display all rows $g_aSubArray = $g_aArray $g_iSearch = $g_iRows Else ; Find rows matching the search string $g_iSearch = 0 If $sSearchHow = "Normal search" Then ; all searches use RegEx => escape 12 + 1 metacharacters $g_sSearch = StringRegExpReplace($g_sSearch, "(\\|\.|\^|\$|\||\[|\(|\{|\*|\+|\?|\#|\))" , "\\$1") EndIf ; ConsoleWrite("$sSearchHow = " & $sSearchHow & @TAB & "$g_sSearch = " & $g_sSearch & @lf) If $g_iSearchCol = - 1 Then ; - 1 means search All columns For $i = 0 To $g_iRows - 1 For $j = 0 To $g_iCols - 1 If StringRegExp($g_aArray[$i][$j], "(?i)" & $g_sSearch) Then For $k = 0 To $g_iCols - 1 $g_aSubArray[$g_iSearch][$k] = $g_aArray[$i][$k] Next $g_iSearch += 1 ContinueLoop 2 EndIf Next Next Else ; Search only in 1 column For $i = 0 To $g_iRows - 1 If StringRegExp($g_aArray[$i][$g_iSearchCol], "(?i)" & $g_sSearch) Then For $j = 0 To $g_iCols - 1 $g_aSubArray[$g_iSearch][$j] = $g_aArray[$i][$j] Next $g_iSearch += 1 EndIf Next EndIf ; Delete eventual temporary subindexes For $i = 0 To $g_iCols - 1 If VarGetType($g_aIndexTemp[$i]) = "DLLStruct" Then $g_aIndexTemp[$i] = "" ; "String" Next EndIf GUICtrlSetData($idResult, " " & $g_iSearch & ($g_sSearch = "" ? " rows (no pattern)" : " matching rows")) GUICtrlSendMsg($g_idListView, $LVM_SETITEMCOUNT, $g_iSearch, 0) _GUICtrlListView_SetSelectedColumn($g_hListView, $g_iSearchCol) ; seems ok here (after $LVM_SETITEMCOUNT) Case $g_idListView ; Sort $iSortCol = GUICtrlGetState($g_idListView) If $iSortCol <> $iSortColPrev Then _GUICtrlHeader_SetItemFormat($g_hHeader, $iSortColPrev, $HDF_STRING) EndIf ; Set $g_tIndex + eventual update of $g_aIndexTemp[$iSortCol] OR $g_aIndex[$iSortCol] If GUICtrlRead($idEdit) Then _UpdateIndex($g_aIndexTemp, $iSortCol) Else _UpdateIndex($g_aIndex, $iSortCol) EndIf $g_iSortDir = (($iSortCol = $iSortColPrev) ? ($g_iSortDir = $HDF_SORTUP ? $HDF_SORTDOWN : $HDF_SORTUP) : ($HDF_SORTUP)) _GUICtrlHeader_SetItemFormat($g_hHeader, $iSortCol, $HDF_STRING + $g_iSortDir) GUICtrlSendMsg($g_idListView, $LVM_SETSELECTEDCOLUMN, $iSortCol, 0) GUICtrlSendMsg($g_idListView, $LVM_SETITEMCOUNT, $g_iSearch, 0) $iSortColPrev = $iSortCol Case $GUI_EVENT_RESTORE ; needed, or Marker goes back in 0, 0 after Restore (why ?) _MoveMarker($g_iSearchCol) EndSwitch WEnd ; Cleanup GUIDelete($g_hGui) EndFunc ;==>Example ;======================================================================== Func WM_DRAWITEM( $hWnd, $iMsg, $wParam, $lParam ) ; Display items in an owner drawn ListView Local Static $tRect = DllStructCreate( $tagRECT ), $pRect = DllStructGetPtr( $tRect ), $tSize = DllStructCreate( $tagSIZE ) Local Static $hBrushYellow = _WinAPI_CreateSolidBrush( 0xFFFF00 ), $hBrushCyan = _WinAPI_CreateSolidBrush( 0x00FFFF ) ; Yellow and cyan, BGR Local Static $hBrushHighLight = _WinAPI_GetSysColorBrush( $COLOR_HIGHLIGHT ), $hBrushButtonFace = _WinAPI_GetSysColorBrush( $COLOR_BTNFACE ) ; We can optimize code by removing Switch statements because the ListView is the only ownerdrawn control and only $ODA_DRAWENTIRE actions are present Local $tDrawItem = DllStructCreate( $tagDRAWITEM, $lParam ), $itemID = DllStructGetData( $tDrawItem, "itemID" ), $iState = DllStructGetData( $tDrawItem, "itemState" ), $hDC = DllStructGetData( $tDrawItem, "hDC" ), $sItemText ; Loop through columns ($i is the column index) For $i = 0 To $g_iCols - 1 ; Subitem rectangle DllStructSetData( $tRect, 2, $i ) ; Top DllStructSetData( $tRect, 1, $LVIR_BOUNDS ) ; Left GUICtrlSendMsg( $g_idListView, $LVM_GETSUBITEMRECT, $itemID, $pRect ) DllStructSetData( $tRect, 1, DllStructGetData( $tRect, 1 ) + 6 ) ; Left margin DllStructSetData( $tRect, 2, DllStructGetData( $tRect, 2 ) + 2 ) ; Top margin ; Subitem background and text color If BitAND( $iState, $ODS_SELECTED ) Then DllCall( "user32.dll", "int", "FillRect", "handle", $hDC, "struct*", $tRect, "handle", $fListViewHasFocus = 1 ? $hBrushHighLight : $hBrushButtonFace ) ; _WinAPI_FillRect DllCall( "gdi32.dll", "int", "SetTextColor", "handle", $hDC, "int", BitAND( $iState, $ODS_SELECTED ) ? $fListViewHasFocus = 1 ? 0xFFFFFF : 0x000000 : 0x000000 ) ; _WinAPI_SetTextColor ; Draw subitem text If $g_iSortDir = 0x0400 Then ; 0x0400 = $HDF_SORTUP $sItemText = $g_aSubArray[$g_tIndex.arr($itemID + 1)][$i] Else $sItemText = $g_aSubArray[$g_tIndex.arr($g_iSearch - $itemID)][$i] EndIf DllCall( "user32.dll", "int", "DrawTextW", "handle", $hDC, "wstr", $sItemText, "int", StringLen( $sItemText ), "struct*", $tRect, "uint", 0 ) ; _WinAPI_DrawText ; Skip column if search for 1 column only and $i is not the searched column If $g_iSearchCol > - 1 And $i <> $g_iSearchCol Then ContinueLoop ; > - 1 means search for 1 column (0, 1, 2...) ; Mark matching substring if found in this column If $g_sSearch Then Local $sMatch = StringRegExp( $sItemText, "(?i)" & $g_sSearch, 1 ) If Not @error Then ; match found Local $extended = @extended, $iLen = StringLen( $sMatch[0] ) ; Rectangle for matching substring DllCall( "gdi32.dll", "bool", "GetTextExtentPoint32W", "handle", $hDC, "wstr", $sItemText, "int", $extended - $iLen - 1, "struct*", $tSize ) ; _WinAPI_GetTextExtentPoint32 DllStructSetData( $tRect, "Left", DllStructGetData( $tRect, "Left" ) + DllStructGetData( $tSize, "X" ) ) DllCall( "gdi32.dll", "bool", "GetTextExtentPoint32W", "handle", $hDC, "wstr", $sMatch[0], "int", $iLen, "struct*", $tSize ) ; _WinAPI_GetTextExtentPoint32 DllStructSetData( $tRect, "Right", DllStructGetData( $tRect, "Left" ) + DllStructGetData( $tSize, "X" ) ) ; Fill rectangle with yellow or cyan (selected) background color DllCall( "user32.dll", "int", "FillRect", "handle", $hDC, "struct*", $tRect, "handle", BitAND( $iState, $ODS_SELECTED ) ? $hBrushCyan : $hBrushYellow ) ; _WinAPI_FillRect ; Draw matching substring in rectangle DllCall( "gdi32.dll", "int", "SetTextColor", "handle", $hDC, "int", 0x000000 ) ; _WinAPI_SetTextColor DllCall( "user32.dll", "int", "DrawTextW", "handle", $hDC, "wstr", $sMatch[0], "int", $iLen, "struct*", $tRect, "uint", 0 ) ; _WinAPI_DrawText EndIf EndIf Next Return $GUI_RUNDEFMSG #forceref $hWnd, $iMsg, $wParam EndFunc ;======================================================================== Func WM_NOTIFY($hWnd, $iMsg, $wParam, $lParam) Local $tNMHEADER = DllStructCreate($tagNMHEADER, $lParam) Switch HWnd(DllStructGetData($tNMHEADER, "hWndFrom")) Case $g_hHeader Local $iCode = DllStructGetData($tNMHEADER, "Code") Switch $iCode Case $NM_RCLICK Local $aHit = _GUICtrlListView_SubItemHitTest($g_hListView) ; $aHit[1] : 0-based index of the LV subitem... i.e. the column in our case (may be -1 if right click on empty part of header) If $aHit[1] > - 1 Then ; valid column GUICtrlSetData($g_idComboCol, $aHit[1]) GUICtrlSendToDummy($g_idComboColDummy) EndIf EndSwitch EndSwitch Return $GUI_RUNDEFMSG EndFunc ;==>WM_NOTIFY ;======================================================================== Func WM_COMMAND($hWnd, $iMsg, $wParam, $lParam) Local $hWndFrom = $lParam Local $iCode = BitShift($wParam, 16) ; High word Switch $hWndFrom Case $g_hEdit Switch $iCode Case $EN_CHANGE GUICtrlSendToDummy($g_idEditDummy) EndSwitch EndSwitch Return $GUI_RUNDEFMSG EndFunc ;==>WM_COMMAND ;======================================================================== Func _Generate_All(ByRef $g_aArray) ConsoleWrite("$g_iRows = " & $g_iRows & " $g_iCols = " & $g_iCols & @CRLF) Local $hTimer = TimerInit() $g_aArray = FAS_Random2DArrayAu3($g_iRows, "sifdtr", "abcdefghijklmnopqrstuvwxyz") ; $g_aArray = FAS_Random2DArrayAu3($g_iRows, "sifdtr", "abcdefghijklmnopqrstuvwxyz" & "\.^$|[({*+?#)") ; 12 + 1 RegEx metacharacters For $i = 0 To $g_iRows - 1 $g_tIndex.arr($i + 1) = $i Next ConsoleWrite("Generating array & one index = " & TimerDiff($hTimer) & @CRLF & @CRLF) EndFunc ;==>_Generate_All ;======================================================================== Func _SortArrayStruct(Const ByRef $aArray, $iCol, $iRows) Local $tIndex = DllStructCreate("uint arr[" & $iRows & "]") Local $pIndex = DllStructGetPtr($tIndex) Local Static $hDll = DllOpen("kernel32.dll") Local Static $hDllComp = DllOpen("shlwapi.dll") Local $lo, $hi, $mi, $r ; Sorting by one column For $i = 1 To $iRows - 1 $lo = 0 $hi = $i - 1 Do $mi = Int(($lo + $hi) / 2) $r = DllCall($hDllComp, 'int', 'StrCmpLogicalW', 'wstr', $aArray[$i][$iCol], 'wstr', $aArray[DllStructGetData($tIndex, 1, $mi + 1)][$iCol])[0] Switch $r Case -1 $hi = $mi - 1 Case 1 $lo = $mi + 1 Case 0 ExitLoop EndSwitch Until $lo > $hi DllCall($hDll, "none", "RtlMoveMemory", "struct*", $pIndex + ($mi + 1) * 4, "struct*", $pIndex + $mi * 4, "ulong_ptr", ($i - $mi) * 4) DllStructSetData($tIndex, 1, $i, $mi + 1 + ($lo = $mi + 1)) Next Return $tIndex EndFunc ;==>_SortArrayStruct ;======================================================================== Func _UpdateIndex(ByRef $aIndex, $iCol) If VarGetType($aIndex[$iCol]) = "DLLStruct" Then $g_tIndex = $aIndex[$iCol] Else $g_tIndex = _SortArrayStruct($g_aSubArray, $iCol, $g_iSearch) $aIndex[$iCol] = $g_tIndex ; "DLLStruct" (or "Int32" when no match found +++) EndIf EndFunc ;==>_UpdateIndex ;======================================================================== Func _MoveMarker($iCol) If $iCol = - 1 Then ; All columns ControlMove($g_hGui, "", $g_idMarker, 10, 40 - 3, 630, 3) ; 10 / 40 / 630 are LV coords Else ; 1 column (0, 1, 2...) Local $aRect = _GUICtrlHeader_GetItemRect($g_hHeader, $iCol) ControlMove($g_hGui, "", $g_idMarker, 10 + $aRect[0], 40 - 3, $aRect[2] - $aRect[0] + 1, 3) EndIf EndFunc ;==>_MoveMarker  Norm73 and Lion66 1 1
Norm73 Posted May 26, 2021 Posted May 26, 2021 Hollo together I couldn't change the column size of the virtual ListView. When I deleted this block, it worked again. Maybe it was also because of the operating system? I have Windows 8.1 Pro 64 bit. ; No ListView column resizing by dragging header dividers (LarsJ) ;_WinAPI_SetWindowLong( $hHeader, $GWL_STYLE, _WinAPI_GetWindowLong( $hHeader, $GWL_STYLE ) + $HDS_NOSIZING ) ; AutoIt 3.3.14.5 issue DllCall( "user32.dll", "long_ptr", @AutoItX64 ? "SetWindowLongPtrW" : "SetWindowLongW", "hwnd", $g_hHeader, "int", $GWL_STYLE, "long_ptr", _ DllCall( "user32.dll", "long_ptr", @AutoItX64 ? "GetWindowLongPtrW" : "GetWindowLongW", "hwnd", $g_hHeader, "int", $GWL_STYLE )[0] + $HDS_NOSIZING ) I also tried to integrate the LatsJ's ColAlign.au3 script into the last version, but unfortunately it didn't work. I couldn't cope with it. ; Subitem rectangle for right and center aligned columns If $g_aColAligns[$g_iSearchCol] = $HDF_RIGHT Or $g_aColAligns[$g_iSearchCol] = $HDF_CENTER Then DllCall( "gdi32.dll", "bool", "GetTextExtentPoint32W", "handle", $hDC, "wstr", $sSubItemText, "int", StringLen( $sSubItemText ), "struct*", $tSize ) ; _WinAPI_GetTextExtentPoint32 Switch $g_aColAligns[$g_iSearchCol] Case $HDF_RIGHT DllStructSetData( $tRect, "Left", DllStructGetData( $tRect, "Right" ) - DllStructGetData( $tSize, "X" ) - 6 ) Case $HDF_CENTER DllStructSetData( $tRect, "Left", DllStructGetData( $tRect, "Left" ) + ( DllStructGetData( $tRect, "Right" ) - DllStructGetData( $tRect, "Left" ) - DllStructGetData( $tSize, "X" ) ) / 2 - 3 ) EndSwitch EndIf Â
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