Jewtus Posted March 5, 2015 Share Posted March 5, 2015 I'm trying to find out if there is a way to setup a loop that will handle a SQLite database with a table that has a parent child relationship. The schema of the table is pretty simple: ID,Parent,Owner,Name,Description and I'm trying to setup a loop that will build this in a tree view. I looked at the tree view example and tried to adapt it, but it looks like I need to assign a variable for each line, which I'm not sure how to accomplish. This is my code: $idTreeView_1=GUICtrlCreateTreeView(16, 45, 546, 278, BitOR($TVS_HASBUTTONS, $TVS_HASLINES, $TVS_LINESATROOT, $TVS_CHECKBOXES), $WS_EX_CLIENTEDGE) $hTreeView_1 = ControlGetHandle($FormMain, "", $idTreeView_1) $Process=_GetRecords($sqliteDB,"Select * from Process where ParentID = ''") For $z=1 to UBound($Process) -1 GUICtrlCreateTreeViewItem($Process[$z][3], $idTreeView_1) ; Column 3 is the Name $test=_GetRecords($sqliteDB,"Select * from Process where ParentID = "&$Process[$z][0]) ; Column 0 is the ID For $q=1 to UBound($test) -1 GUICtrlCreateTreeViewItem($test[$q][0], -1) Next Next Can someone push me in the right direction to figure this out? Link to comment Share on other sites More sharing options...
spudw2k Posted March 5, 2015 Share Posted March 5, 2015 (edited) With having very little code to work with I had to kludge together the missing pieces. Forgive me for the mess. I also don't think it's working right for me because I don't have admin rights to the machine I wrote this on. Maybe you'll have better luck. For the DB portion I used a set of functions I created for ADO. They can be found here (so download it first): The script creates an MDB file (JetDB) and deletes it at the end, so please acknowledge the prompts when they occur...otherwise this demo won't go very far. I also used WMI to collect/gen some process info...Yes it is a different structure and most certainly different method than you used...but I wasn't going to guess how you do it. Anyways... expandcollapse popup#include <GUIConstantsEx.au3> #include <MsgBoxConstants.au3> #include <StaticConstants.au3> #include <TreeViewConstants.au3> #include <WindowsConstants.au3> #include <Array.au3> #include <_ADODB.au3> ;------Collect Processes Info using WMI------ $objWMIService = WMIService(@ComputerName) ;WMIService Object - Establish Connection If $objWMIService = 0 Then Exit Local $strData[3]= ["ProcessId","ParentProcessId","Name"] ;Data to Return from WMI Query $arrResults = WMIQuery($objWMIService,"SELECT * FROM Win32_Process",$strData) ;Run WMI Query against WMIService Object $objWMIService = 0 ;Termninate WMIService Object ;------Collect Processes Info using WMI------ ;------Create and Populate JetDB------ $adCurrentProvider = $adProviderMSJET4 ;Microsoft.Jet.OLEDB.4.0 $adCurrentDataSource = @ScriptDir & "\TEMPDB.MDB" ;Establish ADO Connection _OpenConnection($adCurrentProvider,$adCurrentDataSource) ;Create Table Dim $arrFields[3]=["ProcessID Integer","ParentProcessID Integer","Name VARCHAR(50)"] ;Init Fields for Table Creation _CreateTable("TestTable",$arrFields) ;Insert Records _InsertRecords("TestTable",$arrResults) ;------Create and Populate JetDB------ $gui = GUICreate("Process TreeView Demo",546,278,-1,-1) $idTreeView_1=GUICtrlCreateTreeView(0, 0, 546, 278, BitOR($TVS_HASBUTTONS, $TVS_HASLINES, $TVS_LINESATROOT, $TVS_CHECKBOXES), $WS_EX_CLIENTEDGE) $hTreeView_1 = ControlGetHandle($gui, "", $idTreeView_1) _PopulateTreeView(0, $idTreeView_1) GUISetState(@SW_SHOW) Func _PopulateTreeView($parentpid, $parenttreeviewitem) ;Retrieve Records from Table with Where Clause Dim $arrSelectFields[3]=["ProcessID","ParentProcessID","Name"] ;Init Select Fields for Recordset Dim $arrWhereFields[1]=["ParentProcessID = "& $parentpid] $Process = _GetRecords("TestTable",$arrSelectFields,$arrWhereFields) If Not IsArray($Process) Then Return 0 For $z=1 to UBound($Process) -1 $treeviewitem = GuiCtrlCreateTreeViewItem($Process[$z][2], $parenttreeviewitem) If $Process[$z][0] <> $Process[$z][1] Then _PopulateTreeView($Process[$z][0], $treeviewitem) Next EndFunc While 1 $msg = GUIGetmsg() If $msg = -3 Then ExitLoop WEnd GUIDelete($gui) ;Drop Database _DropDatabase() ;Closes ADO Connection first if using MS.JET.OLEDB.4.0 ;------Supporting Functions for Demo------ Func WMIService($host) ;Connects to WMI Service $objWMIService = ObjGet("winmgmts:{impersonationLevel=impersonate}!\\" & $host & "\root\cimv2") If not IsObj($objWMIService) Then return 0 return $objWMIService EndFunc Func WMIQuery($objWMIService,$strWMIQuery,$arrData) ;Perform WMI Query with Query String and Data Return Parameters If not IsArray($arrData) then return 0 $colItems = $objWMIService.ExecQuery ($strWMIQuery) ;Execute query against WMI Service Object Local $arrResults[$colItems.Count+1][UBound($arrData)] ;Two-Dimension Array to store query Results For $i = 0 to UBound($arrData)-1 $arrResults[0][$i] = $arrData[$i] Next $idx = 1 For $objItem in $colItems For $i = 0 to UBound($arrData)-1 $arrResults[$idx][$i] = Execute("$objitem." & $arrData[$i]) ;Result Next $idx += 1 Next return $arrResults ;Return Result Array EndFunc ;------Supporting Functions for Demo------ Basically I tried to make a recursive function to populate the treeview. I hope this gives you an idea and feel free to ask me any questions so I can clarify my added nonsense. edit: Actually. I think there are some issues with my logic. I was assuming that child processes don't persist if their parent process dies...but looks like that is not the case. I think I would create an array with each process and track the handles/ids of the treeview items as they are created...loop through the process list and create children that way instead. Was a nice exercise though in my opinion...just not practical. I'll try to make a better example with that idea in place. See below expandcollapse popup#include <GUIConstantsEx.au3> #include <GuiTreeView.au3> #include <MsgBoxConstants.au3> #include <StaticConstants.au3> #include <TreeViewConstants.au3> #include <WindowsConstants.au3> #include <Array.au3> #include <_ADODB.au3> ;------Collect Processes Info using WMI------ $objWMIService = WMIService(@ComputerName) ;WMIService Object - Establish Connection If $objWMIService = 0 Then Exit Local $strData[3]= ["ProcessId","ParentProcessId","Name"] ;Data to Return from WMI Query $arrResults = WMIQuery($objWMIService,"SELECT * FROM Win32_Process",$strData) ;Run WMI Query against WMIService Object $objWMIService = 0 ;Termninate WMIService Object ;------Collect Processes Info using WMI------ ;------Create and Populate JetDB------ $adCurrentProvider = $adProviderMSJET4 ;Microsoft.Jet.OLEDB.4.0 $adCurrentDataSource = @ScriptDir & "\TEMPDB.MDB" ;Establish ADO Connection _OpenConnection($adCurrentProvider,$adCurrentDataSource) ;Create Table Dim $arrFields[3]=["ProcessID Integer","ParentProcessID Integer","Name VARCHAR(50)"] ;Init Fields for Table Creation _CreateTable("TestTable",$arrFields) ;Insert Records _InsertRecords("TestTable",$arrResults) ;------Create and Populate JetDB------ $gui = GUICreate("Process TreeView Demo",546,278,-1,-1) $idTreeView_1=GUICtrlCreateTreeView(0, 0, 546, 278, BitOR($TVS_HASBUTTONS, $TVS_HASLINES, $TVS_LINESATROOT, $TVS_CHECKBOXES), $WS_EX_CLIENTEDGE) $hTreeView_1 = ControlGetHandle($gui, "", $idTreeView_1) _PopulateTreeView() GUISetState(@SW_SHOW) Func _PopulateTreeView() ;Retrieve Records from Table Dim $arrSelectFields[3]=["ProcessID","ParentProcessID","Name"] ;Init Select Fields for Recordset $Process = _GetRecords("TestTable",$arrSelectFields) If Not IsArray($Process) Then Return 0 $processcount = UBound($Process) Local $treeviewitems[$processcount][2] $idx = 0 For $x = 1 to $processcount-1 $id = _ArraySearch($treeviewitems,$Process[$x][1]) If $id > -1 Then $treeviewitems[$idx][1] = GuiCtrlCreateTreeViewItem($Process[$x][2], $treeviewitems[$id][1]) Else $treeviewitems[$idx][1] = GuiCtrlCreateTreeViewItem($Process[$x][2], $idTreeView_1) EndIf $treeviewitems[$idx][0] = $Process[$x][0] $idx += 1 Next _GUICtrlTreeView_Sort($hTreeView_1) EndFunc While 1 $msg = GUIGetmsg() If $msg = -3 Then ExitLoop WEnd GUIDelete($gui) ;Drop Database _DropDatabase() ;Closes ADO Connection first if using MS.JET.OLEDB.4.0 ;------Supporting Functions for Demo------ Func WMIService($host) ;Connects to WMI Service $objWMIService = ObjGet("winmgmts:{impersonationLevel=impersonate}!\\" & $host & "\root\cimv2") If not IsObj($objWMIService) Then return 0 return $objWMIService EndFunc Func WMIQuery($objWMIService,$strWMIQuery,$arrData) ;Perform WMI Query with Query String and Data Return Parameters If not IsArray($arrData) then return 0 $colItems = $objWMIService.ExecQuery ($strWMIQuery) ;Execute query against WMI Service Object Local $arrResults[$colItems.Count+1][UBound($arrData)] ;Two-Dimension Array to store query Results For $i = 0 to UBound($arrData)-1 $arrResults[0][$i] = $arrData[$i] Next $idx = 1 For $objItem in $colItems For $i = 0 to UBound($arrData)-1 $arrResults[$idx][$i] = Execute("$objitem." & $arrData[$i]) ;Result Next $idx += 1 Next return $arrResults ;Return Result Array EndFunc ;------Supporting Functions for Demo------ edit: Sorted Treeview to make it look nice Edited March 6, 2015 by spudw2k Spoiler Things I've Made: Always On Top Tool ◊ AU History ◊ Deck of Cards ◊ HideIt ◊ ICU ◊ Icon Freezer ◊ Ipod Ejector ◊ Junos Configuration Explorer ◊ Link Downloader ◊ MD5 Folder Enumerator ◊ PassGen ◊ Ping Tool ◊ Quick NIC ◊ Read OCR ◊ RemoteIT ◊ SchTasksGui ◊ SpyCam ◊ System Scan Report Tool ◊ System UpTime ◊ Transparency Machine ◊ VMWare ESX BuilderMisc Code Snippets: ADODB Example ◊ CheckHover ◊ Detect SafeMode ◊ DynEnumArray ◊ GetNetStatData ◊ HashArray ◊ IsBetweenDates ◊ Local Admins ◊ Make Choice ◊ Recursive File List ◊ Remove Sizebox Style ◊ Retrieve PNPDeviceID ◊ Retreive SysListView32 Contents ◊ Set IE Homepage ◊ Tickle Expired Password ◊ Transpose ArrayProjects: Drive Space Usage GUI ◊ LEDkIT ◊ Plasma_kIt ◊ Scan Engine Builder ◊ SpeeDBurner ◊ SubnetCalcCool Stuff: AutoItObject UDF ◊ Extract Icon From Proc ◊ GuiCtrlFontRotate ◊ Hex Edit Funcs ◊ Run binary ◊ Service_UDF Link to comment Share on other sites More sharing options...
Solution LarsJ Posted March 6, 2015 Solution Share Posted March 6, 2015 Jewtus, You can benefit from the features of the GuiTreeView UDF. Then it's much easier to control where the parents and children are inserted into the TV. This is the code (not tested): $hParent = 0 For $z=1 to UBound($Process) - 1 ; Add a new parent at top level, all parents are siblings $hParent = _GUICtrlTreeView_Add( $hTreeView_1, $hParent, $Process[$z][3] ) $test=_GetRecords($sqliteDB,"Select * from Process where ParentID = "&$Process[$z][0]) ; Column 0 is the ID For $q=1 to UBound($test) - 1 ; Add all child rows as children of current parent _GUICtrlTreeView_AddChild( $hTreeView_1, $hParent, $test[$q][0] ) Next Next 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...
Jewtus Posted March 9, 2015 Author Share Posted March 9, 2015 (edited) Thanks Lars, but I'm still struggling with that. It does help, but once I get past the first two tier, I start having trouble: $Process=_GetRecords($sqliteDB,$query1) $hParent = 0 For $z=1 to UBound($Process) - 1 $hParent = _GUICtrlTreeView_Add( $hTreeView_1, $hParent, $Process[$z][0] ) $Child=_GetRecords($sqliteDB,$query2) ; Column 0 is the ID For $q=1 to UBound($Child) - 1 $hChild=_GUICtrlTreeView_AddChild( $hTreeView_1, $hParent, $Child[$q][0]) $Child2=_GetRecords($sqliteDB,$query3) For $z=1 to UBound($Child2) - 1 $hChild=_GUICtrlTreeView_AddChildFirst( $hTreeView_1, $hChild, $Child2[$z][0]) Next Next Next The first tier works fine, the second tier works fine. The first two levels work fine, but when I try to add a level beyond that, it starts cascading them. When there is only 1 result, it works fine, but if there are more, it starts going haywire. Like this: Group1 SubGroup1 Sub-SubGroup1 (this works fine because there is one result) Group2 SubGroup2 Sub-SubGroup2 (if there are multiple results, it just adds them as another layer down) Sub-SubGroup2 Instead of like this: Group2 Subgroup2 Sub-SubGroup2 Sub-SubGroup2 I tried using addchild and addchildfirst hoping to get around that, but I'm assuming it has something to do with the parent I'm selecting in my second loop. EDIT: When I use this: $Process=_GetRecords($sqliteDB,$query1) $hParent = 0 For $z=1 to UBound($Process) - 1 $hParent = _GUICtrlTreeView_Add( $hTreeView_1, $hParent, $Process[$z][0] ) $Child=_GetRecords($sqliteDB,$query2) ; Column 0 is the ID For $q=1 to UBound($Child) - 1 $hChild=_GUICtrlTreeView_AddChild( $hTreeView_1, $hParent, $Child[$q][0]) $Child2=_GetRecords($sqliteDB,$query3) ; For $z=1 to UBound($Child2) - 1 ; $hChild=_GUICtrlTreeView_AddChildFirst( $hTreeView_1, $hChild, $Child2[$z][0]) ; Next Next Next it works fine for the first 2 queries, but when I add the next loop, it actually seems to break the first loop as well. The first query has 3 results with child items. The second query puts the items into the correct parent/child location. The third query causes the first results 2nd and 3rd results to disappear from the TV. Edited March 9, 2015 by Jewtus Link to comment Share on other sites More sharing options...
LarsJ Posted March 9, 2015 Share Posted March 9, 2015 (edited) I think you just have to delete "$hChild=" in the third loop. The rest seems to be OK.And don't use $z in both first and third loop. Edited March 9, 2015 by LarsJ 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...
Jewtus Posted March 9, 2015 Author Share Posted March 9, 2015 I think you just have to delete "$hChild=" in the third loop. The rest seems to be OK. And don't use $z in both first and third loop. *facepalm* That was it. Thanks! 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