September Posted May 5, 2022 Share Posted May 5, 2022 Hi guys, I need to search some key words in treeview, this treeview contains 10000 or up to 100000 lines, but I found that it's too slow to retrieve the result, I need the item and its full path result. Can we: Speed up the searching? Stop the searching progress if I want? Highlight the result item(s) in the treeview? Expand the result item(s) in the treeview? Have a progress control to see the search progress? For example, if you search "zcyrjgwafv" in my script, it takes some seconds, it's too slow, if you search "zc", it's killing me expandcollapse popup#include <GUIConstants.au3> #include <WindowsConstants.au3> #include <GuiTreeView.au3> #include <StaticConstants.au3> #include <ButtonConstants.au3> #include <ListviewConstants.au3> #include <EditConstants.au3> #include <Misc.au3> #include <ProgressConstants.au3> Opt( "MustDeclareVars", 0) Opt( "GUIOnEventMode", 0) Global $tNMHDR, $hWndFrom, $iIDFrom, $iCode, $hGui Global $idTreeView, $hTreeView, $aItems, $item, $txt, $root_parent Global $msg, $show_all_file_new Global $item_handle, $txt_1, $parent_1, $root_parent_1, $fullpath_1, $compare_result Global Const $TREEVIEW_START = 1000 Showall() Func Showall() ; Create GUI $hGui = GUICreate( "Show", 400, 800, -1, -1, ($GUI_SS_DEFAULT_GUI) ) ; Create TreeView $filemenu = GUICtrlCreateMenu("File") Global $fileitem_import = GUICtrlCreateMenuItem("Import", $filemenu) $idTreeView = GUICtrlCreateTreeView( 0, 22, 400, 340, BitOR($GUI_SS_DEFAULT_TREEVIEW, $TVS_TRACKSELECT) ) $hTreeView = GUICtrlGetHandle( $idTreeView ) Global $searchitemBtn = GUICtrlCreateButton("Find item",5, 385, 70, 20, $BS_FLAT) Global $searchfullBtn = GUICtrlCreateButton("Find path",5, 415, 70, 20, $BS_FLAT) Global $sEARCHinput = GUICtrlCreateInput("", 80, 385, 150, 20) Global $edit_searchresult = GUICtrlCreateEdit("",5, 485,392, 290) ; Register WM_NOTIFY message handler To create the treeview item txt GUIRegisterMsg( $WM_NOTIFY, "WM_NOTIFY" ) ; Show GUI GUISetState(@SW_SHOW, $hGui) ; Loop While 1 $Msg = GUIGetMsg() Switch $Msg Case $GUI_EVENT_CLOSE ExitLoop Case $fileitem_import _read_show_all_file() Case $searchitemBtn _searchitem() Case $searchfullBtn _searchpath() EndSwitch WEnd ; Cleanup GUIDelete( $hGui ) EndFunc ;read showall Mo file and transfer to #format Func _read_show_all_file() _GuiCtrlTreeView_DeleteAll($idTreeView) $show_all_file_new = FileOpen(@scriptDir &"\" &"Treefile.txt") $aItems = FileReadToArray( $show_all_file_new ) Global $iLineCount = @extended ;~ GUICtrlCreateLabel($iLineCount&"Lines", 550, 3) FileClose(@scriptDir &"\" &"Treefile.txt") ; Create TreeView structure CreateTreeView( $aItems ) ; Expand all child items ;~ _GUICtrlTreeView_Expand( $hTreeView ) EndFunc ; Create TreeView structure Func CreateTreeView( $aItems ) ; TreeView level information Local $aLevels[100][2], $iLevel = 0, $iLevelPrev = 0 ; $aLevels[$iLevel][0]/[1] contains the last item/parent of that level ; TreeView insert structure Local $tInsert = DllStructCreate( $tagTVINSERTSTRUCT ), $pInsert = DllStructGetPtr( $tInsert ) DllStructSetData( $tInsert, "InsertAfter", $TVI_LAST ) DllStructSetData( $tInsert, "Mask", $TVIF_HANDLE+$TVIF_PARAM+$TVIF_TEXT ) DllStructSetData( $tInsert, "Text", -1 ) ; $LPSTR_TEXTCALLBACK ; Add TreeView root $aLevels[$iLevel][1] = NULL DllStructSetData( $tInsert, "Param", $TREEVIEW_START ) DllStructSetData( $tInsert, "Parent", $aLevels[$iLevel][1] ) $aLevels[$iLevel][0] = GUICtrlSendMsg( $idTreeView, $TVM_INSERTITEMW, 0, $pInsert ) ; Add TreeView items For $i = 1 To UBound( $aItems ) - 1 $iLevel = StringSplit( $aItems[$i], "#", 2 )[0] If $iLevel <> $iLevelPrev Then $aLevels[$iLevel][1] = $iLevel > $iLevelPrev ? $aLevels[$iLevelPrev][0] _ ; A child of the previous level : GUICtrlSendMsg( $idTreeView, $TVM_GETNEXTITEM, $TVGN_PARENT, $aLevels[$iLevel][0] ) ; A sibling of the level $iLevelPrev = $iLevel EndIf DllStructSetData( $tInsert, "Param", $i+$TREEVIEW_START ) DllStructSetData( $tInsert, "Parent", $aLevels[$iLevel][1] ) $aLevels[$iLevel][0] = GUICtrlSendMsg( $idTreeView, $TVM_INSERTITEMW, 0, $pInsert ) Next ; $aLevels[$iLevel][0]/[1] contains the last item/parent of that level EndFunc Func _searchitem() For $i = 0 To UBound( $aItems ) - 1 Global $iLevel_item = StringSplit( $aItems[$i], "#", 2 )[1] ;~ If GUICtrlRead($sEARCHinput) <> 0 Then $compare_result = StringInStr( $iLevel_item, GUICtrlRead($sEARCHinput), 2) ;~ EndIf If $compare_result <> 0 Then ;Determine full path of selected item in TreeView $item_handle = _GUICtrlTreeView_FindItem($idTreeView, $iLevel_item) $txt_1 = _GUICtrlTreeView_GetText($idTreeView, $item_handle) Do $parent_1 = _GUICtrlTreeView_GetParentHandle($idTreeView, $item_handle) $txt_1 = _GUICtrlTreeView_GetText($idTreeView, $parent_1) & "," & $txt_1 $item_handle = $parent_1 Until $parent_1 = 0 $root_parent_1 = _GUICtrlTreeView_GetText($idTreeView, $parent_1) StringLen($root_parent_1) $fullpath_1=StringTrimLeft($txt_1,StringLen($root_parent_1)+1) GUICtrlSetData($edit_searchresult,"", 1) GUICtrlSetData($edit_searchresult,$iLevel_item&@CRLF, 1) EndIf Next EndFunc Func _searchpath() For $i = 0 To UBound( $aItems ) - 1 Global $iLevel_item = StringSplit( $aItems[$i], "#", 2 )[1] ;~ If GUICtrlRead($sEARCHinput) <> 0 Then $compare_result = StringInStr( $iLevel_item, GUICtrlRead($sEARCHinput), 2) ;~ EndIf If $compare_result <> 0 Then ;Determine full path of selected item in TreeView $item_handle = _GUICtrlTreeView_FindItem($idTreeView, $iLevel_item) $txt_1 = _GUICtrlTreeView_GetText($idTreeView, $item_handle) Do $parent_1 = _GUICtrlTreeView_GetParentHandle($idTreeView, $item_handle) $txt_1 = _GUICtrlTreeView_GetText($idTreeView, $parent_1) & "," & $txt_1 $item_handle = $parent_1 Until $parent_1 = 0 $root_parent_1 = _GUICtrlTreeView_GetText($idTreeView, $parent_1) StringLen($root_parent_1) $fullpath_1=StringTrimLeft($txt_1,StringLen($root_parent_1)+1) GUICtrlSetData($edit_searchresult,"", 1) GUICtrlSetData($edit_searchresult,$fullpath_1&@CRLF, 1) EndIf Next EndFunc Func WM_NOTIFY( $hWnd, $iMsg, $wParam, $lParam ) ;For adding item's text Local $tNMHDR = DllStructCreate( $tagNMHDR, $lParam ) Switch HWnd( DllStructGetData( $tNMHDR, "hWndFrom" ) ) Case $hTreeView Switch DllStructGetData( $tNMHDR, "Code" ) Case $TVN_GETDISPINFOW ; Display TreeView item text Local Static $tBuffer = DllStructCreate( "wchar Text[1000]" ), $pBuffer = DllStructGetPtr( $tBuffer ) Local $tDispInfo = DllStructCreate( $tagNMTVDISPINFO, $lParam ), $sText = StringSplit( $aItems[DllStructGetData($tDispInfo,"Param")-$TREEVIEW_START], "#", 2 )[1] DllStructSetData( $tBuffer, "Text", $sText ) DllStructSetData( $tDispInfo, "Text", $pBuffer ) DllStructSetData( $tDispInfo, "TextMax", 2 * StringLen( $sText ) + 2 ) EndSwitch EndSwitch #forceref $hWnd, $iMsg, $wParam EndFunc Treefile.txt Link to comment Share on other sites More sharing options...
KaFu Posted May 5, 2022 Share Posted May 5, 2022 Why do you search in the tree when you first import the data from a text-file? Maybe additionally add the data to a scripting dictionary object (key = text, value = tree item id) while importing, and the results should be nearly instantly. OS: Win10-22H2 - 64bit - German, AutoIt Version: 3.3.16.1, AutoIt Editor: SciTE, Website: https://funk.eu AMT - Auto-Movie-Thumbnailer (2024-Oct-13) BIC - Batch-Image-Cropper (2023-Apr-01) COP - Color Picker (2009-May-21) DCS - Dynamic Cursor Selector (2024-Oct-13) HMW - Hide my Windows (2024-Oct-19) HRC - HotKey Resolution Changer (2012-May-16) ICU - Icon Configuration Utility (2018-Sep-16) SMF - Search my Files (2024-Oct-20) - THE file info and duplicates search tool SSD - Set Sound Device (2017-Sep-16) Link to comment Share on other sites More sharing options...
September Posted May 5, 2022 Author Share Posted May 5, 2022 But how to show the full path (root,parent,child) result? 37 minutes ago, KaFu said: Why do you search in the tree when you first import the data from a text-file? Maybe additionally add the data to a scripting dictionary object (key = text, value = tree item id) while importing, and the results should be nearly instantly. Link to comment Share on other sites More sharing options...
Nine Posted May 5, 2022 Share Posted May 5, 2022 I agree with @KaFu. You would need to build the scripting dictionary within the CreateTreeView function as you're already looking for children and siblings. Just add parents in a string separated with "|" BTW, use ByRef when passing large arrays like $aItems in CreateTreeView. It will prevent making a useless copy of the array. “They did not know it was impossible, so they did it” ― Mark Twain Spoiler Block all input without UAC Save/Retrieve Images to/from Text Monitor Management (VCP commands) Tool to search in text (au3) files Date Range Picker Virtual Desktop Manager Sudoku Game 2020 Overlapped Named Pipe IPC HotString 2.0 - Hot keys with string x64 Bitwise Operations Multi-keyboards HotKeySet Recursive Array Display Fast and simple WCD IPC Multiple Folders Selector Printer Manager GIF Animation (cached) Screen Scraping Multi-Threading Made Easy Link to comment Share on other sites More sharing options...
September Posted May 5, 2022 Author Share Posted May 5, 2022 Sorry I'm a beginner and don't know how to use the scripting dictionary, could you help on the script? @Nine @KaFu Another question is, is it possible to highlight the result on treeview? Thanks. Link to comment Share on other sites More sharing options...
September Posted May 7, 2022 Author Share Posted May 7, 2022 I see this func can be used for comparing/searching, but the keyword must be 100% matching with the item, otherwise it returns failure. Is it possible to change? ; Returns true if a specified key exists in the Dictionary object, false if it does not. Func _ItemExists($v_key) Return $oDictionary.Exists ($v_key) EndFunc ;==>_ItemExists Link to comment Share on other sites More sharing options...
jchd Posted May 7, 2022 Share Posted May 7, 2022 If you have a really large number of entries and need to perform efficient more or less sophisticated queries on it, then I'd switch to a database; immediate candidate is SQLite, with its AutoIt support. This implies there is a significant first step to learn and implement something suited to your needs, but it will pay on the long run. This wonderful site allows debugging and testing regular expressions (many flavors available). An absolute must have in your bookmarks.Another excellent RegExp tutorial. Don't forget downloading your copy of up-to-date pcretest.exe and pcregrep.exe hereRegExp tutorial: enough to get startedPCRE v8.33 regexp documentation latest available release and currently implemented in AutoIt beta. SQLitespeed is another feature-rich premier SQLite manager (includes import/export). Well worth a try.SQLite Expert (freeware Personal Edition or payware Pro version) is a very useful SQLite database manager.An excellent eBook covering almost every aspect of SQLite3: a must-read for anyone doing serious work.SQL tutorial (covers "generic" SQL, but most of it applies to SQLite as well)A work-in-progress SQLite3 tutorial. Don't miss other LxyzTHW pages!SQLite official website with full documentation (may be newer than the SQLite library that comes standard with AutoIt) Link to comment Share on other sites More sharing options...
September Posted May 7, 2022 Author Share Posted May 7, 2022 SQLite is a bit complex, I think "_ArraySearch" is what I wanted, still need to solve the loop through and look up each item, if it has more items are matching. But the big problem is to return the whole path which is including the searched item from the treeview, it takes too much time. Do you have any idea to make it faster? Link to comment Share on other sites More sharing options...
jchd Posted May 7, 2022 Share Posted May 7, 2022 I agree that SQLite seems a bit heavylifting, but here's an example of a hierarchical tree queried in SQL: expandcollapse popup-- make a "who works for whom?" table CREATE TABLE org( name TEXT PRIMARY KEY, boss TEXT REFERENCES org ) WITHOUT ROWID; INSERT INTO org VALUES('Alice',NULL),('Bob','Alice'),('Cindy','Alice'),('Dave','Bob'),('Emma','Bob'),('Fred','Cindy'),('Gail','Cindy'), ('John','Dave'),('Pete','Gail'),('Vlad','Pete'),('Paul','Gail'); -- query that table "depth-first" WITH RECURSIVE under_alice(level,name) AS ( VALUES(0,'Alice') UNION ALL SELECT under_alice.level+1, org.name FROM org JOIN under_alice ON org.boss=under_alice.name ORDER BY 2 DESC ) SELECT level || '#' || name Input FROM under_alice; -- result is a tree similar to what you work with: Input 0#Alice 1#Cindy 2#Gail 3#Pete 4#Vlad 3#Paul 2#Fred 1#Bob 2#Emma 2#Dave 3#John -- now query the tree of bosses from someone whose name contains 'la' WITH RECURSIVE who(name,boss) as (select name,boss from org where name like '%la%'), over_name(name,boss) AS ( select name,boss from who UNION ALL SELECT org.name, org.boss FROM org JOIN over_name ON org.name = over_name.boss ) select name || '.' || bosses Hierarchy from ((select name from who) N, (SELECT group_concat(boss,'.') bosses FROM over_name)); -- result is: Hierarchy Vlad.Pete.Gail.Cindy.Alice So yes this isn't completely obvious to someone who isn't used to SQL but it's perfectly workable, and very fast even on large tables. Of course you'll have to create an index on boss to speed up real-world searches. Needless to say this is just a toy example! This wonderful site allows debugging and testing regular expressions (many flavors available). An absolute must have in your bookmarks.Another excellent RegExp tutorial. Don't forget downloading your copy of up-to-date pcretest.exe and pcregrep.exe hereRegExp tutorial: enough to get startedPCRE v8.33 regexp documentation latest available release and currently implemented in AutoIt beta. SQLitespeed is another feature-rich premier SQLite manager (includes import/export). Well worth a try.SQLite Expert (freeware Personal Edition or payware Pro version) is a very useful SQLite database manager.An excellent eBook covering almost every aspect of SQLite3: a must-read for anyone doing serious work.SQL tutorial (covers "generic" SQL, but most of it applies to SQLite as well)A work-in-progress SQLite3 tutorial. Don't miss other LxyzTHW pages!SQLite official website with full documentation (may be newer than the SQLite library that comes standard with AutoIt) Link to comment Share on other sites More sharing options...
pixelsearch Posted May 7, 2022 Share Posted May 7, 2022 (edited) This should do it, with simplified search functions, results display immediately : expandcollapse popup#include <Array.au3> #include <GUIConstants.au3> #include <GuiTreeView.au3> Opt( "MustDeclareVars", 1) Global $hGui, $idTreeView, $hTreeView, $aItems, $item, $txt, $root_parent Global $msg, $show_all_file_new Global $item_handle, $txt_1, $parent_1, $root_parent_1, $fullpath_1, $compare_result Global Const $TREEVIEW_START = 1000 Showall() ;============================================== Func Showall() ; Create GUI $hGui = GUICreate( "Show", 400, 800) ; Create TreeView Local $filemenu = GUICtrlCreateMenu("File") Global $fileitem_import = GUICtrlCreateMenuItem("Import", $filemenu) $idTreeView = GUICtrlCreateTreeView( 0, 22, 400, 340, BitOR($GUI_SS_DEFAULT_TREEVIEW, $TVS_TRACKSELECT) ) $hTreeView = GUICtrlGetHandle( $idTreeView ) Global $searchitemBtn = GUICtrlCreateButton("Find item",5, 385, 70, 20, $BS_FLAT) Global $searchfullBtn = GUICtrlCreateButton("Find path",5, 415, 70, 20, $BS_FLAT) Global $sEARCHinput = GUICtrlCreateInput("", 80, 385, 150, 20) Global $edit_searchresult = GUICtrlCreateEdit("",5, 485,392, 290) ; Register WM_NOTIFY message handler to create the treeview item txt GUIRegisterMsg( $WM_NOTIFY, "WM_NOTIFY" ) ; Show GUI GUISetState(@SW_SHOW, $hGui) ; Loop While 1 $Msg = GUIGetMsg() Switch $Msg Case $GUI_EVENT_CLOSE ExitLoop Case $fileitem_import _read_show_all_file() Case $searchitemBtn _searchitem() Case $searchfullBtn _searchpath() EndSwitch WEnd ; Cleanup GUIDelete( $hGui ) EndFunc ;======================================================================== Func _read_show_all_file() ; read showall Mo file and transfer to #format _GuiCtrlTreeView_DeleteAll($idTreeView) $show_all_file_new = FileOpen(@scriptDir &"\" &"Treefile.txt") $aItems = FileReadToArray( $show_all_file_new ) Global $iLineCount = @extended ;~ GUICtrlCreateLabel($iLineCount&"Lines", 550, 3) FileClose(@scriptDir &"\" &"Treefile.txt") ; _ArrayDisplay($aItems, "$aItems") ; Create TreeView structure CreateTreeView( $aItems ) ; Expand all child items ;~ _GUICtrlTreeView_Expand( $hTreeView ) EndFunc ;========================================================= Func CreateTreeView( $aItems ) ; Create TreeView structure ; TreeView level information Local $aLevels[100][2], $iLevel = 0, $iLevelPrev = 0 ; $aLevels[$iLevel][0]/[1] contains the last item/parent of that level ; TreeView insert structure Local $tInsert = DllStructCreate( $tagTVINSERTSTRUCT ), $pInsert = DllStructGetPtr( $tInsert ) DllStructSetData( $tInsert, "InsertAfter", $TVI_LAST ) DllStructSetData( $tInsert, "Mask", $TVIF_HANDLE+$TVIF_PARAM+$TVIF_TEXT ) DllStructSetData( $tInsert, "Text", -1 ) ; $LPSTR_TEXTCALLBACK ; Add TreeView root $aLevels[$iLevel][1] = NULL DllStructSetData( $tInsert, "Param", $TREEVIEW_START ) DllStructSetData( $tInsert, "Parent", $aLevels[$iLevel][1] ) $aLevels[$iLevel][0] = GUICtrlSendMsg( $idTreeView, $TVM_INSERTITEMW, 0, $pInsert ) ; Add TreeView items Global $aPath[UBound($aItems)] ; very bad to declare Global in function (my bad !) Local $sPath = "" $aPath[0] = "Root" For $i = 1 To UBound( $aItems ) - 1 $iLevel = StringSplit( $aItems[$i], "#", 2 )[0] Select Case $iLevel = $iLevelPrev ; test most frequent first ; $sPath = $sPath Case $iLevel > $iLevelPrev $aLevels[$iLevel][1] = $aLevels[$iLevelPrev][0] ; A child of the previous level $iLevelPrev = $iLevel $sPath = $aPath[$i - 1] Case Else ; $iLevel < $iLevelPrev $aLevels[$iLevel][1] = GUICtrlSendMsg( $idTreeView, $TVM_GETNEXTITEM, $TVGN_PARENT, $aLevels[$iLevel][0] ) ; A sibling of the level $iLevelPrev = $iLevel $sPath = StringLeft($sPath, StringInStr($sPath, "\", Default, $iLevel) - 1) EndSelect $aPath[$i] = $sPath & "\" & StringSplit( $aItems[$i], "#", 2 )[1] DllStructSetData( $tInsert, "Param", $i+$TREEVIEW_START ) DllStructSetData( $tInsert, "Parent", $aLevels[$iLevel][1] ) $aLevels[$iLevel][0] = GUICtrlSendMsg( $idTreeView, $TVM_INSERTITEMW, 0, $pInsert ) Next ; $aLevels[$iLevel][0]/[1] contains the last item/parent of that level ; _ArrayDisplay($aLevels, "$aLevels") ; _ArrayDisplay($aPath, "$aPath") EndFunc ;============================================== Func _searchitem() Local $sSearch = GUICtrlRead($sEARCHinput) For $i = 0 To UBound( $aItems ) - 1 If StringInStr( $aItems[$i], $sSearch) Then GUICtrlSetData($edit_searchresult, "", 1) GUICtrlSetData($edit_searchresult, StringSplit( $aItems[$i], "#", 2 )[1] & @CRLF, 1) EndIf Next EndFunc ;============================================== Func _searchpath() Local $sSearch = GUICtrlRead($sEARCHinput) For $i = 0 To UBound( $aItems ) - 1 If StringInStr( $aItems[$i], $sSearch) Then GUICtrlSetData($edit_searchresult,"", 1) GUICtrlSetData($edit_searchresult, $aPath[$i] & @CRLF, 1) EndIf Next EndFunc ;============================================== Func WM_NOTIFY( $hWnd, $iMsg, $wParam, $lParam ) ; For adding item's text #forceref $hWnd, $iMsg, $wParam Local $tNMHDR = DllStructCreate( $tagNMHDR, $lParam ) Switch HWnd( DllStructGetData( $tNMHDR, "hWndFrom" ) ) Case $hTreeView Switch DllStructGetData( $tNMHDR, "Code" ) Case $TVN_GETDISPINFOW ; Display TreeView item text Local Static $tBuffer = DllStructCreate( "wchar Text[1000]" ), $pBuffer = DllStructGetPtr( $tBuffer ) Local $tDispInfo = DllStructCreate( $tagNMTVDISPINFO, $lParam ), $sText = StringSplit( $aItems[DllStructGetData($tDispInfo,"Param")-$TREEVIEW_START], "#", 2 )[1] DllStructSetData( $tBuffer, "Text", $sText ) DllStructSetData( $tDispInfo, "Text", $pBuffer ) DllStructSetData( $tDispInfo, "TextMax", 2 * StringLen( $sText ) + 2 ) EndSwitch EndSwitch Return $GUI_RUNDEFMSG EndFunc A pic to show what's inside the array $aPath : Good luck Edited May 7, 2022 by pixelsearch typo Link to comment Share on other sites More sharing options...
mikell Posted May 8, 2022 Share Posted May 8, 2022 Funny, I did nearly the same using a string instead of an array - much dirtier of course This one expands & allows partial searches like "zcy" which may return several results (searching "zc" works too but shows a funny animation in the treeview) expandcollapse popup#include <GUIConstants.au3> #include <WindowsConstants.au3> #include <GuiTreeView.au3> #include <StaticConstants.au3> #include <ButtonConstants.au3> #include <ListviewConstants.au3> #include <EditConstants.au3> #include <Misc.au3> #include <ProgressConstants.au3> Opt( "MustDeclareVars", 0) Opt( "GUIOnEventMode", 0) Global $tNMHDR, $hWndFrom, $iIDFrom, $iCode, $hGui Global $idTreeView, $hTreeView, $aItems, $item, $txt, $root_parent Global $msg, $show_all_file_new Global $item_handle, $txt_1, $parent_1, $root_parent_1, $fullpath_1, $compare_result Global Const $TREEVIEW_START = 1000 Global $ref_txt Showall() Func Showall() ; Create GUI $hGui = GUICreate( "Show", 400, 800, -1, -1, ($GUI_SS_DEFAULT_GUI) ) ; Create TreeView $filemenu = GUICtrlCreateMenu("File") Global $fileitem_import = GUICtrlCreateMenuItem("Import", $filemenu) $idTreeView = GUICtrlCreateTreeView( 0, 22, 400, 340, BitOR($GUI_SS_DEFAULT_TREEVIEW, $TVS_TRACKSELECT) ) $hTreeView = GUICtrlGetHandle( $idTreeView ) Global $searchfullBtn = GUICtrlCreateButton("Find path",5, 415, 70, 20, $BS_FLAT) Global $sEARCHinput = GUICtrlCreateInput("", 80, 385, 150, 20) Global $edit_searchresult = GUICtrlCreateEdit("",5, 485,392, 290) GuiCtrlSetData($sEARCHinput,"zcyrjgwafv") ; Register WM_NOTIFY message handler To create the treeview item txt GUIRegisterMsg( $WM_NOTIFY, "WM_NOTIFY" ) ; Show GUI GUISetState(@SW_SHOW, $hGui) ; Loop While 1 $Msg = GUIGetMsg() Switch $Msg Case $GUI_EVENT_CLOSE ExitLoop Case $fileitem_import _read_show_all_file() Case $searchfullBtn _searchpath_2() EndSwitch WEnd ; Cleanup GUIDelete( $hGui ) EndFunc ;read showall Mo file and transfer to #format Func _read_show_all_file() _GuiCtrlTreeView_DeleteAll($idTreeView) $show_all_file_new = FileOpen(@scriptDir &"\" &"Treefile.txt") $aItems = FileReadToArray( $show_all_file_new ) Global $iLineCount = @extended ;~ GUICtrlCreateLabel($iLineCount&"Lines", 550, 3) FileClose(@scriptDir &"\" &"Treefile.txt") ; Create TreeView structure CreateTreeView( $aItems ) ; Expand all child items ;~ _GUICtrlTreeView_Expand( $hTreeView ) EndFunc ; Create TreeView structure Func CreateTreeView( $aItems ) ; TreeView level information Local $aLevels[100][2], $iLevel = 0, $iLevelPrev = 0 ; $aLevels[$iLevel][0]/[1] contains the last item/parent of that level $line = "Root" $ref_txt = "" ; TreeView insert structure Local $tInsert = DllStructCreate( $tagTVINSERTSTRUCT ), $pInsert = DllStructGetPtr( $tInsert ) DllStructSetData( $tInsert, "InsertAfter", $TVI_LAST ) DllStructSetData( $tInsert, "Mask", $TVIF_HANDLE+$TVIF_PARAM+$TVIF_TEXT ) DllStructSetData( $tInsert, "Text", -1 ) ; $LPSTR_TEXTCALLBACK ; Add TreeView root $aLevels[$iLevel][1] = NULL DllStructSetData( $tInsert, "Param", $TREEVIEW_START ) DllStructSetData( $tInsert, "Parent", $aLevels[$iLevel][1] ) $aLevels[$iLevel][0] = GUICtrlSendMsg( $idTreeView, $TVM_INSERTITEMW, 0, $pInsert ) ; Add TreeView items For $i = 1 To UBound( $aItems ) - 1 $split = StringSplit( $aItems[$i], "#", 2 ) $iLevel = $split[0] $item = $split[1] $line = StringRegExp($line, '((?:\|?\w+){' & $iLevel & '})', 1)[0] & "|" & $item $ref_txt &= $line & @crlf If $iLevel <> $iLevelPrev Then $aLevels[$iLevel][1] = $iLevel > $iLevelPrev ? $aLevels[$iLevelPrev][0] _ ; A child of the previous level : GUICtrlSendMsg( $idTreeView, $TVM_GETNEXTITEM, $TVGN_PARENT, $aLevels[$iLevel][0] ) ; A sibling of the level $iLevelPrev = $iLevel EndIf DllStructSetData( $tInsert, "Param", $i+$TREEVIEW_START ) DllStructSetData( $tInsert, "Parent", $aLevels[$iLevel][1] ) $aLevels[$iLevel][0] = GUICtrlSendMsg( $idTreeView, $TVM_INSERTITEMW, 0, $pInsert ) Next ; $aLevels[$iLevel][0]/[1] contains the last item/parent of that level EndFunc Func _searchpath_2() $find = GUICtrlRead($sEARCHinput) $compare_result = StringInStr( $ref_txt, $find, 2) If $compare_result = 0 Then Return 0 $res = StringRegExp($ref_txt, '(?m)^(.*' & $find & '.*)$', 3) GUICtrlSetData($edit_searchresult, "", 1) For $i = 0 to UBound($res)-1 $item = StringRegExp($res[$i], '(?:^|\|)([^\|]*' & $find & '[^\|]*)(?:\||$)', 1)[0] GUICtrlSetData($edit_searchresult, $find & @CRLF, 1) GUICtrlSetData($edit_searchresult, $item & @CRLF, 1) GUICtrlSetData($edit_searchresult, $res[$i] & @CRLF, 1) ControlTreeView($hGui, "", $idTreeView, "Select", $res[$i]) Next EndFunc Func WM_NOTIFY( $hWnd, $iMsg, $wParam, $lParam ) ;For adding item's text Local $tNMHDR = DllStructCreate( $tagNMHDR, $lParam ) Switch HWnd( DllStructGetData( $tNMHDR, "hWndFrom" ) ) Case $hTreeView Switch DllStructGetData( $tNMHDR, "Code" ) Case $TVN_GETDISPINFOW ; Display TreeView item text Local Static $tBuffer = DllStructCreate( "wchar Text[1000]" ), $pBuffer = DllStructGetPtr( $tBuffer ) Local $tDispInfo = DllStructCreate( $tagNMTVDISPINFO, $lParam ), $sText = StringSplit( $aItems[DllStructGetData($tDispInfo,"Param")-$TREEVIEW_START], "#", 2 )[1] DllStructSetData( $tBuffer, "Text", $sText ) DllStructSetData( $tDispInfo, "Text", $pBuffer ) DllStructSetData( $tDispInfo, "TextMax", 2 * StringLen( $sText ) + 2 ) EndSwitch EndSwitch #forceref $hWnd, $iMsg, $wParam EndFunc Link to comment Share on other sites More sharing options...
September Posted May 8, 2022 Author Share Posted May 8, 2022 Thank you all. @pixelsearch, yes, it's very fast now, but for this declaration $aPath[0] = "Root" however, if the Treefile.txt first few rows are : (This is a common situation in my daily work, and I can't change every original file to start with "root") 0#hello 0#Root 1#abgajvqduj 1#abhrheeufg 1#abiyjmwrxk ..... something interesting happens, see the Row0, it's "Root", not "hello", yes, this is due to $aPath[0]="Root", it will lose some items in the full path, see the Row 68, actually it should be \Root\abutrygviv\agvyidwsak Link to comment Share on other sites More sharing options...
mikell Posted May 8, 2022 Share Posted May 8, 2022 So why not use a regex to fire all the lines up to "0#Root" ? Link to comment Share on other sites More sharing options...
pixelsearch Posted May 9, 2022 Share Posted May 9, 2022 @September As you have several lines #0 in your new text file, then the script needs to be amended : 1 line to delete : ; $aPath[0] = "Root" 1 line to modify : ; $sPath = StringLeft($sPath, StringInStr($sPath, "\", Default, $iLevel) - 1) $sPath = StringLeft($sPath, StringInStr($sPath, "\", Default, $iLevel + 1) - 1) By the way, here is the correct way to close the text file : ; FileClose(@scriptDir &"\" &"Treefile.txt") FileClose($show_all_file_new) The preceding changes should solve the search (Row 68 for example) when your text file starts with : 0#Hello 0#Root 1#abgajvqduj 1#abhrheeufg ... The following could help in case you have several "filled" roots, for example : 0#Hello 1#aaaaaaaaa1 2#aaaaaaaaa2 3#aaaaaaaaa3 3#aaaaaaaaa4 1#aaaaaaaaa5 0#Root 1#abgajvqduj 1#abhrheeufg ... I think the following loop in Func CreateTreeView() should always start from 0 and not 1, to be compatible with the different treefile texts discussed above : ; For $i = 1 To UBound( $aItems ) - 1 For $i = 0 To UBound( $aItems ) - 1 Good luck Link to comment Share on other sites More sharing options...
mikell Posted May 9, 2022 Share Posted May 9, 2022 (edited) About this 0#Root thing, if the solution from pixelsearch is not enough, then you might in the script replace this $show_all_file_new = FileOpen(@scriptDir &"\" &"Treefile.txt") $aItems = FileReadToArray( $show_all_file_new ) FileClose(@scriptDir &"\" &"Treefile.txt") by this $read = FileRead(@scriptDir &"\" &"Treefile.txt") ; read the file $read = StringRegExpReplace($read, '(?s)^(.*?)(?=0#Root)', "") ; remove all from begining up to 0#Root $aItems = StringRegExp($read, '\N+', 3) ; then build the aItems array which works nice in his first script (and btw in mine too) Edited May 9, 2022 by mikell typo Link to comment Share on other sites More sharing options...
September Posted May 10, 2022 Author Share Posted May 10, 2022 Great, both are working. Now I'm thinking how to remove the duplicate first row at treeview, and how to highlight and expand the search items at treeview? Link to comment Share on other sites More sharing options...
pixelsearch Posted May 10, 2022 Share Posted May 10, 2022 2 hours ago, September said: how to remove the duplicate first row at treeview By deleting the following line. Now that the loop always starts at 0 and not at 1, it will be created within the loop : ; $aLevels[$iLevel][0] = GUICtrlSendMsg( $idTreeView, $TVM_INSERTITEMW, 0, $pInsert ) 2 hours ago, September said: how to highlight and expand the search items at treeview? By keeping the unique handles of each treeview item during their creation => array $aPath becomes 2D : For $i = 0 To UBound( $aItems ) - 1 ... $aPath[$i][1] = $aLevels[$iLevel][0] ; handle of the item ... Next Then use _GUICtrlTreeView_Expand and _GUICtrlTreeView_SetSelected during the search. expandcollapse popup#include <Array.au3> #include <GUIConstants.au3> #include <GuiTreeView.au3> Opt( "MustDeclareVars", 1) Global $hGui, $idTreeView, $hTreeView, $aItems, $item, $txt, $root_parent, $aPath Global $msg, $show_all_file_new Global $item_handle, $txt_1, $parent_1, $root_parent_1, $fullpath_1, $compare_result Global Const $TREEVIEW_START = 1000 Showall() ;============================================== Func Showall() ; Create GUI $hGui = GUICreate( "Show", 400, 800) ; Create TreeView Local $filemenu = GUICtrlCreateMenu("File") Global $fileitem_import = GUICtrlCreateMenuItem("Import", $filemenu) $idTreeView = GUICtrlCreateTreeView( 0, 22, 400, 340, BitOR($GUI_SS_DEFAULT_TREEVIEW, $TVS_TRACKSELECT) ) $hTreeView = GUICtrlGetHandle( $idTreeView ) Global $searchitemBtn = GUICtrlCreateButton("Find item",5, 385, 70, 20, $BS_FLAT) Global $searchfullBtn = GUICtrlCreateButton("Find path",5, 415, 70, 20, $BS_FLAT) Global $sEARCHinput = GUICtrlCreateInput("", 80, 385, 150, 20) Global $edit_searchresult = GUICtrlCreateEdit("",5, 485,392, 290) ; Register WM_NOTIFY message handler to create the treeview item txt GUIRegisterMsg( $WM_NOTIFY, "WM_NOTIFY" ) ; Show GUI GUISetState(@SW_SHOW, $hGui) ; Loop While 1 $Msg = GUIGetMsg() Switch $Msg Case $GUI_EVENT_CLOSE ExitLoop Case $fileitem_import _read_show_all_file() Case $searchitemBtn _searchitem() Case $searchfullBtn _searchpath() EndSwitch WEnd ; Cleanup GUIDelete( $hGui ) EndFunc ;======================================================================== Func _read_show_all_file() ; read showall Mo file and transfer to #format _GuiCtrlTreeView_DeleteAll($idTreeView) $show_all_file_new = FileOpen(@scriptDir &"\" &"Treefile.txt") $aItems = FileReadToArray( $show_all_file_new ) Global $iLineCount = @extended ;~ GUICtrlCreateLabel($iLineCount&"Lines", 550, 3) FileClose($show_all_file_new) ; _ArrayDisplay($aItems, "$aItems") ; Create TreeView structure CreateTreeView( $aItems ) ; Expand all child items ;~ _GUICtrlTreeView_Expand( $hTreeView ) EndFunc ;========================================================= Func CreateTreeView( $aItems ) ; Create TreeView structure ; TreeView level information Local $aLevels[100][2], $iLevel = 0, $iLevelPrev = 0 ; $aLevels[$iLevel][0]/[1] contains the last item/parent of that level ; TreeView insert structure Local $tInsert = DllStructCreate( $tagTVINSERTSTRUCT ), $pInsert = DllStructGetPtr( $tInsert ) DllStructSetData( $tInsert, "InsertAfter", $TVI_LAST ) DllStructSetData( $tInsert, "Mask", $TVIF_HANDLE+$TVIF_PARAM+$TVIF_TEXT ) DllStructSetData( $tInsert, "Text", -1 ) ; $LPSTR_TEXTCALLBACK ; Add TreeView root $aLevels[$iLevel][1] = NULL DllStructSetData( $tInsert, "Param", $TREEVIEW_START ) DllStructSetData( $tInsert, "Parent", $aLevels[$iLevel][1] ) ; $aLevels[$iLevel][0] = GUICtrlSendMsg( $idTreeView, $TVM_INSERTITEMW, 0, $pInsert ) ; Add TreeView items Dim $aPath[UBound($aItems)][2] ; $aPath already declared Global in main Local $sPath = "" For $i = 0 To UBound( $aItems ) - 1 $iLevel = StringSplit( $aItems[$i], "#", 2 )[0] ; "0" to "7" in example "Treefile several roots.txt" Select Case $iLevel = $iLevelPrev ; test most frequent first ; $sPath = $sPath Case $iLevel > $iLevelPrev $aLevels[$iLevel][1] = $aLevels[$iLevelPrev][0] ; A child of the previous level $iLevelPrev = $iLevel $sPath = $aPath[$i - 1][0] Case Else ; $iLevel < $iLevelPrev $aLevels[$iLevel][1] = GUICtrlSendMsg( $idTreeView, $TVM_GETNEXTITEM, $TVGN_PARENT, $aLevels[$iLevel][0] ) ; A sibling of the level $iLevelPrev = $iLevel $sPath = StringLeft($sPath, StringInStr($sPath, "\", Default, $iLevel + 1) - 1) EndSelect $aPath[$i][0] = $sPath & "\" & StringSplit( $aItems[$i], "#", 2 )[1] ; ex. `\Root" or "\Root\abgajvqduj" ... DllStructSetData( $tInsert, "Param", $i+$TREEVIEW_START ) DllStructSetData( $tInsert, "Parent", $aLevels[$iLevel][1] ) $aLevels[$iLevel][0] = GUICtrlSendMsg( $idTreeView, $TVM_INSERTITEMW, 0, $pInsert ) $aPath[$i][1] = $aLevels[$iLevel][0] ; handle of the item Next ; $aLevels[$iLevel][0]/[1] contains the last item/parent of that level ; _ArrayDisplay($aLevels, "$aLevels") ; _ArrayDisplay($aPath, "$aPath", Default, Default, Default, _ ; "Path|Handle*") ; * at end of any header means numeric sort for the concerned column. EndFunc ;============================================== Func _searchitem() Local $sSearch = GUICtrlRead($sEARCHinput) For $i = 0 To UBound( $aItems ) - 1 If StringInStr($aItems[$i], $sSearch) Then GUICtrlSetData($edit_searchresult, "", 1) GUICtrlSetData($edit_searchresult, StringSplit( $aItems[$i], "#", 2 )[1] & @CRLF, 1) _GUICtrlTreeView_Expand($idTreeView, $aPath[$i][1], True) _GUICtrlTreeView_SetSelected($idTreeView, $aPath[$i][1], True) EndIf Next EndFunc ;============================================== Func _searchpath() Local $sSearch = GUICtrlRead($sEARCHinput) For $i = 0 To UBound( $aItems ) - 1 If StringInStr($aItems[$i], $sSearch) Then GUICtrlSetData($edit_searchresult,"", 1) GUICtrlSetData($edit_searchresult, $aPath[$i][0] & @CRLF, 1) _GUICtrlTreeView_Expand($idTreeView, $aPath[$i][1], True) _GUICtrlTreeView_SetSelected($idTreeView, $aPath[$i][1], True) EndIf Next EndFunc ;============================================== Func WM_NOTIFY( $hWnd, $iMsg, $wParam, $lParam ) ; For adding item's text #forceref $hWnd, $iMsg, $wParam Local $tNMHDR = DllStructCreate( $tagNMHDR, $lParam ) Switch HWnd( DllStructGetData( $tNMHDR, "hWndFrom" ) ) Case $hTreeView Switch DllStructGetData( $tNMHDR, "Code" ) Case $TVN_GETDISPINFOW ; Display TreeView item text Local Static $tBuffer = DllStructCreate( "wchar Text[1000]" ), $pBuffer = DllStructGetPtr( $tBuffer ) Local $tDispInfo = DllStructCreate( $tagNMTVDISPINFO, $lParam ), $sText = StringSplit( $aItems[DllStructGetData($tDispInfo,"Param")-$TREEVIEW_START], "#", 2 )[1] DllStructSetData( $tBuffer, "Text", $sText ) DllStructSetData( $tDispInfo, "Text", $pBuffer ) DllStructSetData( $tDispInfo, "TextMax", 2 * StringLen( $sText ) + 2 ) EndSwitch EndSwitch Return $GUI_RUNDEFMSG EndFunc A search on "abvd" expands automatically like this : If several matches exist, then they're all automatically selected and expanded. Link to comment Share on other sites More sharing options...
September Posted May 10, 2022 Author Share Posted May 10, 2022 I tested it with a large txt file, when there are many items matching the search, it is impacting the search speed.😀 Link to comment Share on other sites More sharing options...
pixelsearch Posted May 10, 2022 Share Posted May 10, 2022 I just tested it on a 100.000 rows text file, search speed was ok, even with many items found. Link to comment Share on other sites More sharing options...
mikell Posted May 10, 2022 Share Posted May 10, 2022 3 hours ago, September said: it is impacting the search speed The search itself is extremely fast, while expanding/selecting the treeview items reduces speed dramatically 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