Top Ten Tags

Who's Online

You've probably used a TreeView to view a hard drive directory structure before, you click on a folder and expand it to show the folders within that that folder. The top folder is the parent and the folder within it are the children. Each folder is a node. All nodes can have children (subfolders).

The following table shows how I would store a single parent node that has to child nodes.

ParentGroup ParentGroup
Parent 1  
Child 1a Parent 1
Child 1a Parent 1

This is an example of a a self-join table in a database, i.e. table that looks at itself. You could have an Excel table that looks like this, too.

I've created sample files for both a form in Microsoft Access and worksheet in Microsoft Excel. In the article I will be referring to a form in an Access database and populating data from a single table (the sample file also shows populating from multiple sources), but the method of adding nodes is the same; what differs is how you get the data used to populate the TreeView control.

Here's the data I created in the sample database.

Download the sample file to follow along. I will only be post parts of the code and explaining them. It's easier to step through it yourself then for me to try to explain it all.

Here's the highlights of the Microsoft Access sample file

  1. Example 'Groups' TreeView populating using the table described above. Nodes are populated from a DAO recordset using a SQL string statement.


  2. Only the first level nodes are filled out when you open the form (as well as the first child, if any, so that there is a + for that node).

  3. Child nodes are only completely added when you expand a parent node.

  4. Also, includes a 'Music' data form that fills out nodes different levels from different data sources for each level (uses data from this article, Artists-->Albums-->Songs). Nodes are populated from stored queries; each query contains a nodeID and nodeText field that is used to set the .Key and .Text property when adding a node.




  5. Two versions of the 'Music' data example. One that fills out child nodes when you expand a parent node, and another that fills out all the node on the form's open even (could be slow if you have a lot of nodes).

VBA code for working with a Treeview control

Dim nParent As Node, nChild As Node

'Basic formatting of TreeView 
With Me.ctlTreeview
    .LineStyle = 1  'Root lines
    .Style = 7      'TreelinesPlusMinusPictureText
End With

'NODE PROPERTIES
'Node Key = unique identifier for each node, AND must be text (so numbers must be used as '1 and so on).
'- This is not the same as the .Index for a node. The index is a number based on position in tree hierachy. 
'Node Text = Text you see in the tree view 

'Basic code for adding node to TreeView control 
'Set nAdd = GroupTree.Nodes.Add(parent node if any, relationship, node key, text to show with node)

'Add top level node (is not a child of any node)
Set nParent = GroupTree.Nodes.Add(, , "strNodeKey, "strNodeText"))

'Constants used to define relationship of node when adding
'CONSTANT / DESCRIPTION
'tvwFirst / Add as the first node at the level of the relative.
'tvwLast / Add as the last node at the level of the relative.
'tvwNext / Add after immediately following a specified node.
'tvwPrevious / Add after immediately preceding a specified node.
'tvwChild / Add as a child to the specified node.

'Add node that is a child
Set nChild = GroupTree.Nodes.Add(nParent, tvwChild, "strNodeKey, "strNodeText")

'Set a node to a specific node using the Key
Set nParent = GroupTree.Nodes("strNodeKey")

'Properties of Node 
Debug.Print nParent.Index 'Not sure if you can refer to a node using the index number. I haven't found a way to yet.
Debug.Print nParent.Key
Debug.Print nParent.Text

'Expand a node to show it's children
nParent.Expanded = True 

'Collapse a node to hide  it's children
nParent.Expanded = False  

'Clear all nodes
Me.ctlTreeview.Nodes.Clear

Additionally, I also wrote a function to figure out which node level a node is at (i.e. to top-most level = level 1). I've seen people who count the number of "\" in the .FullPath; The .PathSeparator "\" is used to separate levels in the node's path, e.g. "Parent\Child\Grandchild" (Grandchild is Level 3, 2*"\" + 1). However, that method won't work if the node text itself contains a "\", e.g. "This\Wont\Work". You can change what is used as the PathSeparator but the problem would still remain.

The approach I took is to count how many iterations it takes to get up to the top-most level using the .Root and .FirstSibling properties.

Public Function NodeLevel(ByVal nNode As Node) As Integer
    
    '*********************************************************************************************************
    'Function: Return the level of a node
    ' - I thought of using Len(Node.FullPath) - Len(Replace(Node.FullPath, "\", "")),
    '   but that would give an incorrect answer if the a node's text included "\" in it, e.g. 'AC\DC'
    '
    'Written by Azli Hassan, http://AzliHassan.com/apps
    '*********************************************************************************************************
    
    'Set initial level to 1 (TreeView is base 0, but I'm using 1)
    NodeLevel = 1
    
    'Keep 'moving' up a level until we reach one level below the top-most level
    '.Root" Returns a reference to the root Node object of a TreeView control. (i.e. the FIRST node in top-most level)
    '.FirstSibling: Returns a reference to the first Node object in a hierarchy level. (i.e. the FIRST node in level)
    While nNode.Root <> nNode.FirstSibling 'Next 'up' level is the root (if they are the same then we're at level 1)
        NodeLevel = NodeLevel + 1
        Set nNode = nNode.Parent
    Wend

End Function

If I find out more than I know now, I'll be sure to update this article. But this is all you need to add nodes to a TreeView ActiveX control.

[Note: Since this is an ActiveX control, it's possible that it will stop working because of some update Microsoft did (it's happened before). Try searching for 'mscomctl.ocx' in Google.]

Additional Links