Jump to content

GUI Tree View and loops


Go to solution Solved by LarsJ,

Recommended Posts

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

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...

#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

#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 by spudw2k
Link to comment
Share on other sites

  • Solution

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
Link to comment
Share on other sites

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.

11j0ks5.png

Edited by Jewtus
Link to comment
Share on other sites

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 by LarsJ
Link to comment
Share on other sites

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

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 account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...