#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 #include #include #include "DrawItem.au3" #include "GuiListViewEx.au3" #include #include #include Global Const $tagMSG = "hwnd hwnd;uint message;wparam wParam;lparam lParam;dword time;int X;int Y" Global Const $sSearchMsg = "Search request in selected column..." Global $hGui, $idListView, $hListView, $fListViewHasFocus = 0, $iItems = 1000, $iCols = 4, $iCol = 0, $aItems[$iItems][$iCols] Global $idSearch, $hSearch, $idSearchAction, $aSearch[$iItems], $iSearch = 0, $sSearch = "" Global $iExListViewStyle = BitOR($LVS_EX_FULLROWSELECT, $LVS_EX_SUBITEMIMAGES, $LVS_EX_GRIDLINES, $LVS_EX_DOUBLEBUFFER) Global $iExWindowStyle = $WS_EX_CLIENTEDGE Example() Func Example() ; Create GUI $hGui = GUICreate( "Show matching rows only - multiple columns", 1060, 330 ) ; Create search group GUICtrlCreateGroup( "Search", 10, 5, 1060-20, 120 ) ; Create Checkbox Local $idRegExp = GUICtrlCreateCheckbox( "Use regular expression as search string", 20, 25, 260, 20 ) GUICtrlSetState( $idRegExp, $GUI_CHECKED ) ; Create Edit control $idSearch = GUICtrlCreateEdit( "", 20, 55, 200, 20, $GUI_SS_DEFAULT_EDIT-$ES_AUTOVSCROLL-$WS_HSCROLL-$WS_VSCROLL ) GUICtrlSetData( $idSearch, $sSearchMsg ) ; "Enter search string - possibly as reg. exp." $hSearch = GUICtrlGetHandle( $idSearch ) $idSearchAction = GUICtrlCreateDummy() ; Create read only Edit control for number of matches Local $idCount = GUICtrlCreateEdit( "0", 230, 55, 50, 20, $GUI_SS_DEFAULT_EDIT+$ES_READONLY+$ES_RIGHT-$WS_HSCROLL-$WS_VSCROLL ) GUICtrlSetBkColor( $idCount, 0xFFFFFF ) ; Create Buttons Local $idSortDes = GUICtrlCreateButton( "Descending Sort", 20, 85, 125, 25 ) Local $idSortAsc = GUICtrlCreateButton( "Ascending Sort", 155, 85, 125, 25 ) ;~ GUICtrlSetState( $idNext, $GUI_DISABLE ) ;~ GUICtrlSetState( $idPrev, $GUI_DISABLE ) ; Search column Local $idComboBox = GUICtrlCreateCombo( "Search column 0", 350, 25, 200, 20, BitOR($CBS_DROPDOWN, $CBS_SIMPLE) ) GUICtrlSetData( $idComboBox, "Search column 1|Search column 2|Search column 3" ) ; Close group GUICtrlCreateGroup( "", -99, -99, 1, 1 ) ; Create ListView $idListView = GUICtrlCreateListView( "", 10, 140, 1060-20, 180, $GUI_SS_DEFAULT_LISTVIEW+$LVS_OWNERDATA+$LVS_OWNERDRAWFIXED, $WS_EX_CLIENTEDGE+$LVS_EX_DOUBLEBUFFER ) ;~ $idListView = GUICtrlCreateListView( "", 10, 140, 1060-20, 180, $GUI_SS_DEFAULT_LISTVIEW+$LVS_OWNERDATA+$LVS_OWNERDRAWFIXED, $WS_EX_CLIENTEDGE+$LVS_EX_DOUBLEBUFFER+$LVS_EX_GRIDLINES ) ; With GRID LINES $hListView = GUICtrlGetHandle( $idListView ) ; Virtual Owner drawn Reduces flicker _GUICtrlListView_AddColumn( $hListView, "Column 0", 250 ) _GUICtrlListView_AddColumn( $hListView, "Column 1", 250 ) _GUICtrlListView_AddColumn( $hListView, "Column 2", 250 ) _GUICtrlListView_AddColumn( $hListView, "Column 3", 250 ) _GUICtrlListView_SetExtendedListViewStyle($idListView, $iExListViewStyle) ; Fill array FillArray( $aItems ) _ArraySort( $aItems, 0, 0, 0, $iCol ) ; $iCol is the search column ; Set search array to display all items For $i = 0 To $iItems - 1 $aSearch[$i] = $i Next $iSearch = $iItems ; Initialize ListView GUICtrlSendMsg( $idListView, $LVM_SETITEMCOUNT, $iSearch, 0 ) ; Adjust height of GUI and ListView to fit 15 rows Local $iLvHeight = _GUICtrlListView_GetHeightToFitRows( $hListView, 15 ) WinMove( $hGui, "", Default, Default, Default, WinGetPos( $hGui )[3] - WinGetClientSize( $hGui )[1] + $iLvHeight + 150 ) WinMove( $hListView, "", Default, Default, Default, $iLvHeight ) ; Register WM_ACTIVATE message handler ; To check when GUI receives/loses focus GUIRegisterMsg( $WM_ACTIVATE, "WM_ACTIVATE" ) ; Register WM_COMMAND message handler ; To read search string from Edit control while it's typed in GUIRegisterMsg( $WM_COMMAND, "WM_COMMAND" ) ; Register WM_DRAWITEM message handler ; To display items in an owner drawn ListView GUIRegisterMsg( $WM_DRAWITEM, "WM_DRAWITEM" ) GUIRegisterMsg($WM_NOTIFY, "WM_NOTIFY") ; Register message handler to test ListView focus Local $hMessageHandler = DllCallbackRegister( "MessageHandler", "long", "int;wparam;lparam" ) Local $hMessageHook = _WinAPI_SetWindowsHookEx( $WH_MSGFILTER, DllCallbackGetPtr( $hMessageHandler ), 0, _WinAPI_GetCurrentThreadId() ) ; Show GUI GUISetState( @SW_SHOW ) ; Message loop While 1 Switch GUIGetMsg() Case $idSearchAction, $idRegExp $sSearch = GUICtrlRead( $idSearch ) ConsoleWrite($sSearch & @CRLF) If $sSearch = $sSearchMsg Then $sSearch = "" If $sSearch = "" Then ; Empty search string, display all items For $i = 0 To $iItems - 1 $aSearch[$i] = $i Next $iSearch = $iItems GUICtrlSetData( $idCount, 0 ) Else ; Find rows matching search string $iSearch = 0 If GUICtrlRead( $idRegExp ) = $GUI_CHECKED Then For $i = 0 To $iItems - 1 If StringRegExp( $aItems[$i][$iCol], "(?i)" & $sSearch ) Then ; Reg. exp. search, (?i) - for case-insensitive search $aSearch[$iSearch] = $i $iSearch += 1 EndIf Next Else For $i = 0 To $iItems - 1 If StringInStr( $aItems[$i][$iCol], $sSearch ) Then ; Normal search, case-insensitive $aSearch[$iSearch] = $i $iSearch += 1 EndIf Next EndIf GUICtrlSetData( $idCount, $iSearch ) EndIf GUICtrlSendMsg( $idListView, $LVM_SETITEMCOUNT, $iSearch, 0 ) Case $idComboBox ; New search column $iCol = Int( StringRight( GUICtrlRead( $idComboBox ), 1 ) ) _ArraySort( $aItems, 0, 0, 0, $iCol ) ;~ GUICtrlSetData( $idSearch, "" ) GUICtrlSendToDummy( $idSearchAction ) Case $idSortDes _ArraySort( $aItems, 0, 0, 0, $iCol ) ConsoleWrite("_ArraySort Error: " & @error & @CRLF) GUICtrlSendMsg( $idListView, $LVM_REDRAWITEMS, 0, $iSearch - 1 ) ;~ ConsoleWrite(">>>ITEMCOUNT: " & GUICtrlSendMsg( $idListView, $LVM_GETITEMCOUNT, 0, 0 ) & @CRLF) ;~ GUICtrlSendToDummy( $idSearchAction ) Case $idSortAsc _ArraySort( $aItems, 1, 0, 0, $iCol ) ConsoleWrite("_ArraySort Error: " & @error & @CRLF) GUICtrlSendMsg( $idListView, $LVM_REDRAWITEMS, 0, $iSearch - 1) ;~ ConsoleWrite(">>>ITEMCOUNT: " & GUICtrlSendMsg( $idListView, $LVM_GETITEMCOUNT, 0, 0 ) & @CRLF) ;~ GUICtrlSendToDummy( $idSearchAction ) Case $GUI_EVENT_CLOSE ExitLoop EndSwitch WEnd ; Cleanup _WinAPI_UnhookWindowsHookEx( $hMessageHook ) GUIDelete() EndFunc ; Check when GUI receives/loses focus Func WM_ACTIVATE( $hWnd, $iMsg, $wParam, $lParam ) #forceref $iMsg, $lParam If $hWnd = $hGui Then _ $fListViewHasFocus += BitAND( $wParam, 0xFFFF ) ? 1 : -1 Return $GUI_RUNDEFMSG EndFunc ; Read search string from Edit control while it's typed in Func WM_COMMAND( $hWnd, $iMsg, $wParam, $lParam ) #forceref $hWnd, $iMsg Local Static $bEditClear = True Local $hWndFrom = $lParam Local $iCode = BitShift( $wParam, 16 ) ; High word Switch $hWndFrom Case $hSearch Switch $iCode Case $EN_CHANGE GUICtrlSendToDummy( $idSearchAction ) Case $EN_SETFOCUS ; Clear search field If $bEditClear Then GUICtrlSetData( $idSearch, "" ) $bEditClear = False EndIf Case $EN_KILLFOCUS ; The control has lost the input focus If GUICtrlRead($idSearch) = "" Then GUICtrlSetData( $idSearch, $sSearchMsg ) $bEditClear = True EndIf ConsoleWrite("Search Focus lost" & @CRLF) EndSwitch EndSwitch Return $GUI_RUNDEFMSG EndFunc ; Display items in an owner drawn ListView Func WM_DRAWITEM( $hWnd, $iMsg, $wParam, $lParam ) 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 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 $iCols - 1 ; Subitem rectangle DllStructSetData( $tRect, 2, $i ) ; Top DllStructSetData( $tRect, 1, $LVIR_BOUNDS ) ; Left GUICtrlSendMsg( $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 $sItemText = $aItems[$aSearch[$itemID]][$i] DllCall( "user32.dll", "int", "DrawTextW", "handle", $hDC, "wstr", $sItemText, "int", StringLen( $sItemText ), "struct*", $tRect, "uint", 0 ) ; _WinAPI_DrawText ; $i is column index ; $iCol is the search column ; Mark matching substring only if column index = search column If $i <> $iCol Then ContinueLoop ; Matching substring? If $sSearch Then Local $sMatch = StringRegExp( $sItemText, "(?i)" & $sSearch, 1 ), $extended = @extended, $iLen = StringLen( $sMatch[0] ) ; (?i) - for case-insensitive search ; 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 (Selected Text color) 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, $iwParam, $ilParam) #forceref $hWnd, $iMsg, $iwParam Local $hWndFrom, $iCode, $tNMHDR, $tInfo, $iIndex, $iColId, $iRawId, $hWndListView, $sItemText;, $iIDFrom $hWndListView = $idListView If Not IsHWnd($idListView) Then $hWndListView = GUICtrlGetHandle($idListView) $tNMHDR = DllStructCreate($tagNMHDR, $ilParam) $hWndFrom = HWnd(DllStructGetData($tNMHDR, "hWndFrom")) ;~ $iIDFrom = DllStructGetData($tNMHDR, "IDFrom") $iCode = DllStructGetData($tNMHDR, "Code") Switch $hWndFrom Case $hWndListView Switch $iCode Case $LVN_COLUMNCLICK ; A column was clicked $tInfo = DllStructCreate($tagNMLISTVIEW, $ilParam) $iColId = DllStructGetData($tInfo, "SubItem") ; Column Header ConsoleWrite("- Column Header ID:" & $iColId & ", Text: " & _GUICtrlListView_GetColumn($idListView, $iColId)[5] & @CRLF) ; Kick off the sort callback _GUICtrlListView_SortItems($hWndFrom, $iColId) _ArraySort( $aItems, 0, 0, 0, $iColId ) $iIndex = _GUICtrlListView_GetSelectionMark($idListView) _GUICtrlListView_EnsureVisible($idListView, $iIndex) Case $NM_CLICK ; Sent by a list-view control when the user clicks an item with the left mouse button $tInfo = DllStructCreate($tagNMITEMACTIVATE, $ilParam) $iRawId = DllStructGetData($tInfo, "Index") $iColId = DllStructGetData($tInfo, "SubItem") ; Column If $iRawId >=0 Then $sItemText = $aItems[$iRawId][$iColId] ConsoleWrite("Row ID " & $iRawId & " - SubItem ID " & $iColId & @CRLF) ConsoleWrite("Item " & $sItemText & @CRLF) EndIf Case $NM_DBLCLK ; Sent by a list-view control when the user double-clicks an item with the left mouse button $tInfo = DllStructCreate($tagNMITEMACTIVATE, $ilParam) $iRawId = DllStructGetData($tInfo, "Index") $iColId = DllStructGetData($tInfo, "SubItem") ; Column If $iRawId >=0 Then $sItemText = $aItems[$iRawId][$iColId] ConsoleWrite("DBLCLK Row ID: " & $iRawId & ", SubItem ID: " & $iColId & ", Text: " & $sItemText & @CRLF) EndIf Case $NM_RDBLCLK ; Sent by a list-view control when the user double-clicks an item with the right mouse button MsgBox(0, "", "Open Script Folder") ;~ Case $LVN_COLUMNDROPDOWN ;~ ConsoleWrite("5555" & @CRLF) ;~ Case $NM_SETFOCUS ; The control has received the input focus ;~ ConsoleWrite("In Focus" & @CRLF) ;~ Case $NM_KILLFOCUS ; The control has lost the input focus ;~ ConsoleWrite("Focus lost" & @CRLF) EndSwitch EndSwitch Return $GUI_RUNDEFMSG EndFunc ;==>WM_NOTIFY ; Message handler to test ListView focus Func MessageHandler( $nCode, $wParam, $lParam ) #forceref $nCode, $wParam Local $tMsg = DllStructCreate( $tagMSG, $lParam ), $iMsg = DllStructGetData( $tMsg, "message" ) If $iMsg = $WM_LBUTTONDOWN Or $iMsg = $WM_RBUTTONDOWN Then $fListViewHasFocus = DllStructGetData( $tMsg, "hwnd" ) = $hListView ? 1 : 0 EndFunc ; Fill array with random strings Func FillArray( ByRef $aItems ) Local $aLetters[26] = [ 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', _ 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z' ], $s For $i = 0 To $iCols - 1 For $j = 0 To $iItems - 1 $s = $aLetters[Random(0,25,1)] For $k = 1 To Random(10,30,1) $s &= $aLetters[Random(0,25,1)] Next $aItems[$j][$i] = StringFormat("[%04s]", $j) & "-" & $s Next Next EndFunc