musicstashall Posted March 15, 2021 Share Posted March 15, 2021 Is it possible to increase the height of the item in this drawing option? I thought that this way you can draw multi-line items. Link to comment Share on other sites More sharing options...
LarsJ Posted March 16, 2021 Author Share Posted March 16, 2021 An owner drawn listview supports multi-line items through the LVS_OWNERDRAWFIXED style. FIXED means that it's only possible to set a certain height for all listview items. This common height is set during creation of the listview. You probably want to set individual heights for each listview item. But this is simply not possible for a standard listview control available in AutoIt. But other controls supports individual heights on a per-item basis. These are comboboxes and listboxes through the CBS_OWNERDRAWVARIABLE and LBS_OWNERDRAWVARIABLE styles, respectively. VARIABLE means that you can set individual heights on a per-item basis. If you want to use individual item heights then the only option is to rewrite the code to support e.g. a listbox control. But it'll complicate the owner draw code for multi-line items in that you'll need multiple text rectangles in the same listbox item corresponding to each subline. A simpler solution to the problem could be to simulate multi-line listview items using one listview item for each subline. This could be done by simply adding an additional listview column with item numbers as shown in the figure: For multi-line items, the item number is only filled in for the first subline. The advantage of this approach is that all existing owner draw code can be reused. You probably still need additional code to handle the multi-line items depending on what functionality you want. But this can in all likelihood be done through an array index to keep track of these multi-line items. I've made a note about simulating multi-line listview items in this way because it might be interesting to investigate the technique. So I might be able to help with some code. But it probably won’t be until the Easter holidays. musicstashall 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 Link to comment Share on other sites More sharing options...
musicstashall Posted March 17, 2021 Share Posted March 17, 2021 12 hours ago, LarsJ said: simpler solution to the problem could be to simulate multi-line listview items using one listview item for each subline. Thank you for your answer. Rather, this option will not suit me. But I implemented multiline items in a different your example, but I had to abandon the LVS_OWNERDRAWFIXED style. Link to comment Share on other sites More sharing options...
pixelsearch Posted May 9, 2021 Share Posted May 9, 2021 (edited) On 5/8/2021 at 7:52 AM, Lion66 said: ...Inspired by your examples, I thought it was possible to connect one of your versions, including sorting, with marking the resulting yellow color, as in this thread [link to the current thread] If you find it possible to please us with the solution of this task, it would be interesting to see such a modification. Thank you. Hi Lion66 With the help of LarsJ's function WM_DRAWITEM in this post, I could combine my last script ("2h") and his function WM_DRAWITEM to display partially colored items (incremental search) in an owner drawn ListView. Here is what it looks like : Changing the search column can be done through the combo control or via a right-click on a column header. Columns sorting indexes on full array are created when user left-click a column header, then they are preserved until the script ends. Temporary column indexes on sub array (i.e corresponding to one search) are created the same way (when user left-click on a column header) and they are preserved until the next search etc... all this already existed in preceding version "2h" The script seems to work though some parts are missing (no hook and no Func WM_ACTIVATE, $fListViewHasFocus forced to 1) . Even with these missing parts, it worked for me without any crash. Concerning your "script crash" dated July 2019 in this post (of the present thread) I hope you found the solution as you needed the non-sensitive mode. We'll talk about it if it's not solved as it worked for me after adding "(?i)" in both RegEx parts (you will see that in the script below too) Meanwhile, could you please try this script "2i" and let's hope all will be good. 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 + Sort + Incremental search + Color (2i)", 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 ; If StringRegExp($g_aArray[$i][$g_iSearchCol], $g_sSearch) Then ; https://www.autoitscript.com/forum/topic/179112-incremental-search-in-owner-drawn-listview/?tab=comments#comment-1438067 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 ; 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_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 ; $i is column index ; $g_iSearchCol is the search column ; Mark matching substring only if column index = search column If $i <> $g_iSearchCol Then ContinueLoop ; Matching substring? If $g_sSearch Then ; Local $sMatch = StringRegExp( $sItemText, $g_sSearch, 1 ), $extended = @extended, $iLen = StringLen( $sMatch[0] ) ; https://www.autoitscript.com/forum/topic/179112-incremental-search-in-owner-drawn-listview/?tab=comments#comment-1438067 Local $sMatch = StringRegExp( $sItemText, "(?i)" & $g_sSearch, 1 ), $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 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, $HDN_DIVIDERDBLCLICKW ; let's forget $HDN_TRACKW... ; _MoveMarker(GUICtrlRead($g_idComboCol)) Case $HDN_ENDTRACKW _MoveMarker(GUICtrlRead($g_idComboCol)) Case $HDN_DIVIDERDBLCLICKW ; notif. doesn't do its job when LV style is $LVS_OWNERDATA and $LVN_GETDISPINFOW not in code (?) 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) ; $iCol won't do it (msdn) , $g_idListView won't work ; $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 I attach below 2 include files from LarsJ, they're needed in the script. RandomArray.au3DrawItem.au3 Â Edit 1 : I notice some display issues in the script above but LarsJ got the same ones in his example "2) Show matching rows only" in zip file (1st post), or in his separate example "2.2) Show matching rows only - multiple columns [Oct 3, 2019]" in another post of this thread. For example, double clicking on a column divider (when the search field is empty and the column is filled) ... will reduce the column size to nearly 0, then incremental search will overlap on an eventual column on its right : I don't know why it doesn't happen in his example "1) Incremental text search" where a double click on the column divider will correctly adjust the column width. LarsJ will surely have the correct answer Edit 2 (a few hours after) : I just digged a bit into these different codes. This bad behavior seems to happen when the LV got a $LVS_OWNERDATA style but $LVN_GETDISPINFOW isn't used in the script. Then a double click on any header separator reduces immediately the column width to nearly 0 . It's just an hypothesis, we'll see if it's confirmed or refuted. The script above has just been updated to prevent this bad behavior of $HDN_DIVIDERDBLCLICKW (i.e. after a double-click on a header separator, the column will now retrieve its original size, which is better than a 0 width column) Edit 3 : Update May 26th, 2021 Fixed the search issue discussed in this post Edited May 26, 2021 by pixelsearch Update May 26th, 2021 Lion66 1 Link to comment Share on other sites More sharing options...
LarsJ Posted May 11, 2021 Author Share Posted May 11, 2021 On 5/9/2021 at 10:35 AM, pixelsearch said: I notice some display issues in the script above but LarsJ got the same ones in his example "2) Show matching rows only" in zip file (1st post), or in his separate example "2.2) Show matching rows only - multiple columns [Oct 3, 2019]" in another post of this thread. For example, double clicking on a column divider (when the search field is empty and the column is filled) ... will reduce the column size to nearly 0, then incremental search will overlap on an eventual column on its right In these 3 scripts, the listviews are created with the LVS_OWNERDATA style, making them true virtual listviews where no item/subitem texts are stored in the listview structures. There is simply no information to calculate the column width at an HDN_DIVIDERDBLCLICK notification.  On 5/9/2021 at 10:35 AM, pixelsearch said: I don't know why it doesn't happen in his example "1) Incremental text search" where a double click on the column divider will correctly adjust the column width. In this script without the LVS_OWNERDATA style, an owner drawn listview will store information about item/subitem texts in the listview structures so that it's possible to calculate the column width at an HDN_DIVIDERDBLCLICK notification. pixelsearch 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 Link to comment Share on other sites More sharing options...
pixelsearch Posted May 11, 2021 Share Posted May 11, 2021 (edited) 9 minutes ago, LarsJ said: In these 3 scripts, the listviews are created with the LVS_OWNERDATA style, making them true virtual listviews where no item/subitem texts are stored in the listview structures. There is simply no information to calculate the column width at an HDN_DIVIDERDBLCLICK notification. Thanks for the confirmation. I would like to add that even when the LV is created with a LVS_OWNERDATA style (virtual LV), then a HDN_DIVIDERDBLCLICK notification will retrieve correct informations about the column width if LVN_GETDISPINFOW is used to set the text. In this case, a double click on a header separator will behave nicely again (this is the case in my preceding script "2h") On 12/7/2015 at 5:33 PM, LarsJ said: (A custom drawn listview supports coloring of fields. However, the coloring works best for whole fields. This doesn't make it applicable to incremental search.) I would like to ask. When you write that "the custom drawn [NM_CUSTOMDRAW] works best for whole fields", you don't definitely say that it doesn't work at all for partial fields. Do you think it would be possible to try it on an incremental search, or there is absolutely no way that it will work ? Thanks. Edited May 11, 2021 by pixelsearch Link to comment Share on other sites More sharing options...
Lion66 Posted May 11, 2021 Share Posted May 11, 2021 (edited) Hi pixelsearch. You as always on top! Thank you for puzzled and answered. I have not had time yet to see the code. I'm wondering to dig and learn. But I fear it to use it in my scripts, because I do not understand much, and if necessary, i cant to make changes. The solution with the insensitive search mode present is also in your examples and work good. The only thing I noticed in version 2i: when you click on the separator between the first two columns, in the second column, the partial date of the first is displayed on the left.  Edited May 11, 2021 by Lion66 Link to comment Share on other sites More sharing options...
pixelsearch Posted May 12, 2021 Share Posted May 12, 2021 5 hours ago, Lion66 said: You as always on top! ... The only thing I noticed in version 2i: when you click on the separator between the first two columns, in the second column, the partial data of the first is displayed on the left. Hi Lion66 Really the one "on top" is LarsJ. Without his persuasion, detailed explanations and incredible examples, I would never have tried any Virtual listview. Now I like them ! Concerning version "2i" above and its overlapping data from 1 column in the other (when you resize columns), I noticed it too but I got no idea how to fix this (some refresh works but partially) Is there a way to fix this when the items are displayed via WM_DRAWITEM in an owner drawn Virtual ListView ? Let's hope anyone who reads this will have the answer to that question. 5 hours ago, Lion66 said: I'm wondering to dig and learn. But I fear it to use it in my scripts, because I do not understand much, and if necessary, i cant to make changes. There's nothing to be afraid of. Just try a simple script with a single column (at least nothing will overlap) a few rows and no sorting. Maybe the non-coloured script "2h" would be a good choice too (as it doesn't use the complicated WM_DRAWITEM notification) . When you're confident with the result, then you can add some functionalities. And if you find problems in your script, there always will be nice people on this Forum to help, after you show them what you scripted. Good luck Link to comment Share on other sites More sharing options...
dmob Posted May 12, 2021 Share Posted May 12, 2021 6 hours ago, pixelsearch said: Really the one "on top" is LarsJ. Without his persuasion, detailed explanations and incredible examples, I would never have tried any Virtual listview. Now I like them ! I agree 100%, it was his absorbing tutorials that encouraged me to dive in & implement them successfully Link to comment Share on other sites More sharing options...
LarsJ Posted May 13, 2021 Author Share Posted May 13, 2021 On 5/11/2021 at 6:59 PM, pixelsearch said: When you write that "the custom drawn [NM_CUSTOMDRAW] works best for whole fields", you don't definitely say that it doesn't work at all for partial fields. Do you think it would be possible to try it on an incremental search, or there is absolutely no way that it will work ? It can probably easily be done. But because custom draw code is extremely message intensive, you really need to pay attention to the performance of your code. The technique is basically the same as for the owner draw code. Also in the custom draw code you use GDI functions to draw the different visual elements. When using GDI functions in custom draw code, the functions must be performed in the postpaint drawing stage i.e. after all default drawing is done. I think the code in the "Too much code" section here contains all the information you need.  A workaround for all these HDN_DIVIDERDBLCLICK issues is to set correct column widths from the start, and then disable column resize through dragging/double-clicking header dividers by adding the HDS_NOSIZING style to the header control. pixelsearch 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 Link to comment Share on other sites More sharing options...
Lion66 Posted May 14, 2021 Share Posted May 14, 2021 22 hours ago, LarsJ said: by adding the HDS_NOSIZING style to the header control. I watched examples about HDS_NOSIZING in this topic. As I understand it, a daughter window with a new header is superimposed on the header of Listview. But then for the sort function I need to handle this new header in the WM_Notify. Or I can somehow add a HDS_NOSIZING style to the header of the existing ListView? Link to comment Share on other sites More sharing options...
LarsJ Posted May 14, 2021 Author Share Posted May 14, 2021 Add this code and you'll see that everything works normally except column resizing: ; No listview column resizing by dragging header dividers Local $hHeader = _GUICtrlListView_GetHeader( $idListView ) ;_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", $hHeader, "int", $GWL_STYLE, "long_ptr", _ DllCall( "user32.dll", "long_ptr", @AutoItX64 ? "GetWindowLongPtrW" : "GetWindowLongW", "hwnd", $hHeader, "int", $GWL_STYLE )[0] + $HDS_NOSIZING )  Lion66 and Danyfirex 2 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 Link to comment Share on other sites More sharing options...
Lion66 Posted May 15, 2021 Share Posted May 15, 2021 Hi LarsJ. It works great! Many thanks. Â Link to comment Share on other sites More sharing options...
Lion66 Posted May 15, 2021 Share Posted May 15, 2021 (edited) LarsJ, pixelsearch: After that change is no longer needed function WM_NOTIFY (about ver 2i)? Or I'm wrong? OK, need for Right click. Edited May 15, 2021 by Lion66 Link to comment Share on other sites More sharing options...
pixelsearch Posted May 15, 2021 Share Posted May 15, 2021 7 hours ago, Lion66 said: OK, need for Right click. Link to comment Share on other sites More sharing options...
pixelsearch Posted May 18, 2021 Share Posted May 18, 2021 (edited) Hi LarsJ I tried to use the Custom draw for incremental search but it didn't work fine, could you please help ? The only thing that "works" in the script below (named "2k") is this : * Please type . or .$ in the Search field, then hover over rows and you'll see the correct matching 1st (or last) character with cyan background in Col 0. Nothing appears if the rows aren't hovered over. * Then change the search column (right-click on a new header or use the Combo) and the cyan background never appears in any searched column (it should appear on 1st or last character, no matter the searched column, as RegEx search is "." or ".$") I checked the 4 values of the rectangle etc... and added some commented ConsoleWrite's during Case $NM_CUSTOMDRAW. Values seem correct, maybe hdc isn't correct when applied to Cols 1+ ? I didn't use at all "clrTextBk" or "clrText". Their value is constantly 0xFF000000 ($CLR_DEFAULT) and if we're able to see a cyan background on matched characters while hovering over Col 0, then it should be ok. Also, as soon as I tried to use "clrTextBk" during a test, then the whole subitem got its background colored. Finally, as the Owner draw script ("2i") worked fine in a precedent post , then we don't really need the Custom draw way (especially it's "extremely message intensive" as you indicated) , but I was just curious to see if it was doable or not. Thanks if you got any idea on how to make Case $NM_CUSTOMDRAW work correctly in the script : 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" 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, 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($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_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_NOTIFY, "WM_NOTIFY") 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 = "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) Local $iDrawStage = DllStructGetData($tCustDraw, "dwDrawStage") If $iDrawStage = $CDDS_PREPAINT Then Return $CDRF_NOTIFYITEMDRAW If $iDrawStage = $CDDS_ITEMPREPAINT Then Return $CDRF_NOTIFYSUBITEMDRAW Local $iItem = DllStructGetData($tCustDraw, "dwItemSpec") Local $iSubItem = DllStructGetData($tCustDraw, "iSubItem") ;~ ConsoleWrite("0x" & Hex($tCustDraw.clrText, 8) & " 0x" & Hex($tCustDraw.clrTextBk, 8) & @lf) ; both 0xFF000000 ($CLR_DEFAULT) If ($iSubItem = $g_iSearchCol) And $g_sSearch Then 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 $hDC = DllStructGetData( $tCustDraw, "hDC" ) ;~ ConsoleWrite("$hDC = " & $hDC & @lf) If $g_iSortDir = 0x0400 Then ; 0x0400 = $HDF_SORTUP Local $sItemText = $g_aSubArray[$g_tIndex.arr($iItem + 1)][$iSubItem] Else Local $sItemText = $g_aSubArray[$g_tIndex.arr($g_iSearch - $iItem)][$iSubItem] EndIf ;~ ConsoleWrite("$sItemText = " & $sItemText & @lf) Local $sMatch = StringRegExp( $sItemText, "(?i)" & $g_sSearch, 1 ), $extended = @extended, $iLen = StringLen( $sMatch[0] ) ; 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 ;~ DllStructSetData( $tRect, 2, DllStructGetData( $tRect, 2 ) + 2 ) ; Top margin ;~ ConsoleWrite("Top = " & $tRect.Top & " " & "Bottom = " & $tRect.Bottom & " " & _ ;~ "Left = " & $tRect.Left & " " & "Right = " & $tRect.Right & @lf) ; 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" ) ) ;~ ConsoleWrite("Top = " & $tRect.Top & " " & "Bottom = " & $tRect.Bottom & " " & _ ;~ "Left = " & $tRect.Left & " " & "Right = " & $tRect.Right & @lf) ; Fill rectangle with cyan background color DllCall( "user32.dll", "int", "FillRect", "handle", $hDC, "struct*", $tRect, "handle", $hBrushCyan) ; _WinAPI_FillRect ; Draw matching substring in rectangle ; DllCall( "gdi32.dll", "int", "SetTextColor", "handle", $hDC, "int", 0x000000 ) ; _WinAPI_SetTextColor DllCall( "gdi32.dll", "int", "SetBkColor", "handle", $hDC, "int", 0xFFFF00 ) ; _WinAPI_SetBkColor (cyan) DllCall( "user32.dll", "int", "DrawTextW", "handle", $hDC, "wstr", $sMatch[0], "int", $iLen, "struct*", $tRect, "uint", 0 ) ; _WinAPI_DrawText EndIf Return $CDRF_NEWFONT Case $LVN_GETDISPINFOW Local $tNMLVDISPINFO = DllStructCreate($tagNMLVDISPINFO, $lParam) Local Static $tText = DllStructCreate("wchar[50]"), $pText = DllStructGetPtr($tText) If $g_iSortDir = 0x0400 Then ; 0x0400 = $HDF_SORTUP DllStructSetData($tText, 1, $g_aSubArray[$g_tIndex.arr($tNMLVDISPINFO.Item + 1)][$tNMLVDISPINFO.SubItem]) Else DllStructSetData($tText, 1, $g_aSubArray[$g_tIndex.arr($g_iSearch - $tNMLVDISPINFO.Item)][$tNMLVDISPINFO.SubItem]) EndIf 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  Edited May 18, 2021 by pixelsearch LarsJ and Norm73 1 1 Link to comment Share on other sites More sharing options...
Lion66 Posted May 20, 2021 Share Posted May 20, 2021 I noticed that when using the $LVS_OWNERDRAWFIXED style, the standard functions stop working. Such as the: _GUICtrlListView_JustifyColumn _GUICtrlListView_GetItemText Possibly a finished version "2k" will solve that. Or how to solve this in early version "2i" ? Link to comment Share on other sites More sharing options...
pixelsearch Posted May 20, 2021 Share Posted May 20, 2021 (edited) Hi Lion66 * Concerning _GUICtrlListView_GetItemText (LVM_GETITEMTEXT message) it doesn't work in a Virtual Listview (LVS_OWNERDATA style) as stipulated in this MS link (just search LVM_GETITEMTEXT in the web page, it will lead you to 4 chapters concerning Virtual Listview, all interesting to read) Edit #1 : _GUICtrlListView_GetItemText seems to work fine if LVN_GETDISPINFO is used (just tested on "2h") * Concerning _GUICtrlListView_JustifyColumn (LVM_SETCOLUMN message) I think you're right. It works fine when the Virtual ListView is populated via LVN_GETDISPINFO, but when it's populated via WM_DRAWITEM (when LV got the LVS_OWNERDRAWFIXED style) then it doesn't work because coords applied by user's code in WM_DRAWITEM are all related to a left string justification. Here is a silly test to show what could work. In version "2i", you can add 1 line to center headers : For $i = 0 To $g_iCols - 1 _GUICtrlListView_AddColumn($g_idListView, $g_aCols[$i], $g_aWidths[$i]) _GUICtrlListView_JustifyColumn($g_idListView, $i, 2) ; <======= added line Next Then you can center all items (starting from col 1 in the example below, by modifying 1 line : ; DllCall( "user32.dll", "int", "DrawTextW", "handle", $hDC, "wstr", $sItemText, "int", StringLen( $sItemText ), "struct*", $tRect, "uint", 0) ; _WinAPI_DrawText changed to : DllCall( "user32.dll", "int", "DrawTextW", "handle", $hDC, "wstr", $sItemText, "int", StringLen( $sItemText ), "struct*", $tRect, "uint", $i > 0 ? $DT_CENTER : 0) ; _WinAPI_DrawText Unfortunately it's not enough : what looks great in the precedent pic (all cols centered starting from col 1+) will display bad coords when search (a "." in search field) is applied to other columns, for example : Maybe if we knew how to change the matched rectangle coords, then center justification could be done when using WM_DRAWITEM ? Edit #2 : @Lion66 To retrieve the text of any subitem in a virtual listview having LVS_OWNERDRAWFIXED style, you need to retrieve it from the array that populated the listview. As you can't use _GUICtrlListView_GetItemText, then try this code in "2i", it will give you an idea on how to retrieve subitem texts in your script. This code is just an example and has to be added inside the While... Wend Loop . Then right click on an item, it will be selected and retrieve the text of column 0 (because of column [0] in code) no matter the columns are sorted or not. Case $GUI_EVENT_SECONDARYDOWN Local $iSelected = GUICtrlSendMsg($g_idListView, $LVM_GETNEXTITEM, -1, $LVNI_SELECTED) If $iSelected > - 1 Then If $g_iSortDir = 0x0400 Then ; 0x0400 = $HDF_SORTUP Local $sGetText = $g_aSubArray[$g_tIndex.arr($iSelected + 1)][0] Else Local $sGetText = $g_aSubArray[$g_tIndex.arr($g_iSearch - $iSelected)][0] EndIf MsgBox($MB_TOPMOST, "Item = " & $iSelected, "Text col 0 = " & $sGetText) EndIf It's easy to create a function for this, so it's reusable anywhere in the script : Case $GUI_EVENT_SECONDARYDOWN 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 ... ;======================================================================== 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 It's great that global variables all start with $g_ in the script, so it's quicker to prepare a function (we don't spend time on checking $g_ variables to add them as parameters) Edited May 20, 2021 by pixelsearch Added Edit #1 and Edit #2 Lion66 1 Link to comment Share on other sites More sharing options...
Lion66 Posted May 20, 2021 Share Posted May 20, 2021 The second question is solved, the first is not. It's Complicated. Tomorrow will need something else, and again It will be necessary ask for help on the forum. I hope that you will be able to solve the version "2k", and there will be no such problems in it. Link to comment Share on other sites More sharing options...
LarsJ Posted May 20, 2021 Author Share Posted May 20, 2021 (edited) Virtual listview On 5/18/2021 at 5:54 PM, pixelsearch said: I was just curious to see if it was doable or not. It's certainly doable: 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" 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, 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($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_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_NOTIFY, "WM_NOTIFY") 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 = "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 And the custom draw code is much more effective than the owner draw code. In the custom draw code, only the column provided with a search filter is drawn with GDI functions. Otherwise, all columns are drawn with default code in the Windows dll-files at the speed of real compiled code. This also applies when there is no search filter. In the owner draw code, all columns are drawn with GDI functions. It ends up being quite a lot of code that's executed as pure interpreted AutoIt code. In an example like this, it's a really good idea to use custom draw code. The code has been tested on Windows 7. From Windows 7 and newer Windows versions, the subitem rectangles appear to be implemented in a consistent manner. But this isn't the case on older Windows versions. Eg. on Windows XP, the size and location of subitem rectangles may vary by a few pixels. An example is seen in Multi-line ListView items (search for Windows XP). Custom draw documentation Column alignment Edited May 22, 2021 by LarsJ pixelsearch 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 Link to comment Share on other sites More sharing options...
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