Saturday, March 29, 2008

My Treeview Project | Episode Four: Expand All and Collapse All Buttons

In episode 4 we'll take the treeview we designed in episode 3 and add buttons for "collapse all" and "expand all". This will let us get started working with the nodes in a treeview.

In previous episodes I told you to make sure you'd built the treeview from the last episode so we could add to it. This time you can download the completed treeview including this episode. Download the episode 4 database. All we've added this time are the command buttons for expanding and collapsing the nodes. Here's the code for the collapse all button:

Private Sub cmdCollapseAll_Click()
  Dim nodThis As MSComctlLib.Node
  For Each nodThis In Me.xProductTreeview.Nodes ' loop through all nodes
    nodThis.Expanded = False
  Next nodThis
  Me.xProductTreeview.SetFocus
End Sub

There are actually a few different ways to process all the nodes in a treeview. I prefer to use For Each...Next whenever I can. It just seems the most "self documenting". In this case we declare a variable of type Node. (I specified MSComctlLib.Node because it's good practice to be explicit when delcaring variables of object types from libraries outside of Access. I have one application that uses both Word and Excel automation. Both Word and Excel have a Range object. If I don't specify, which one will I get?) This variable will represent one node of the tree. The for each...next loop tells Access to do a block of code once for each member of the collection of nodes in the treeview. Then it's as simple as settting each node's Expanded property to False.

The last line just sets focus back to the treeview. I do this because the selected item in a treeview looks different when the tree has focus from when it doesn't. In episode three when we formatted our tree we set the .HideSelection property to False. This means the selected item will still be identified when the tree doesn't have focus, but it still doesn't get the full item highlight, it's more of a dimmed highlight so the user knows it's not in focus. All that being said, the appearance of the tree will be more what the user expects if you set focus back to it after you do something with it.

Here's the expand all button- it's not much different than the collapse all button:

Private Sub cmdExpandAll_Click()
  Dim nodThis As MSComctlLib.Node
  For Each nodThis In Me.xProductTreeview.Nodes ' loop through all nodes
    nodThis.Expanded = True
  Next nodThis
  With Me.xProductTreeview
    .SetFocus ' move focus back to the treeview

    ' make sure the selected item is back into the visible part of the treeview
    .SelectedItem.EnsureVisible
  End With
End Sub

The loop at the beginning was probably pretty predictable- just like the last one but set the Expanded property to True instead. Then there's a With block at the bottom that does a couple of things to the treeview. I use a with block because I will do two things to the same object. The first line sets focus just like in the previous button. The line .SelectedItem.EnsureVisible makes sure that with all the additional rows we're showing that the selected node still shows up. A treeview's .SelectedItem is the node currently selected, and the .EnsureVisible method scrolls the treeview if necessary and expands nodes as needed to make sure a particular node is visible.

That's it for episode 4. In epsiode 5 we'll make the tree really do something- we'll use it to select and edit records.

Check out all the posts in MyTreeviewProject.

13 comments:

Anonymous said...

Great article!

I just began playing around with the treeview control today and have it almost to where I need it. Episode 3's use of "with" should help me some more.

2 questions:
1-How do you go about assign an image to a node - including how you load in a set of "ico" files into an imagelist?
2-The recordset that I'm using to populate the treeview already tells me whether or not a particular record is a "parent" or "child". How do I make the "parent" nodes BOLD?

Anonymous said...

Using the "with" statement, I was able to bold the parents. I even changed the color!

Now I just need to be able to assign an image to each node. Any thoughts?

Stephen said...

Well first you need to add an Imagelist control to your form. Then you need to add images to the imagelist, which you can do through the form designer. Then you have to tell the treeview that its images come from your image list. Then when you add nodes you specify an image from the imae list using the key you specified when you added the images to the imagelist. I haven't done a search for examples of this. I'll get to it in my tutorial in six or seven weeks, but that won't help you now....

Anonymous said...

I've gotten almost everything done now. I added the images. I was able to change the parent nodes to bold and red.

In my recordset, there is a field that tells me whether that node is "active" or not; if it is not, I make it gray.

What I've done at the moment is create 2 command buttons that ask, first, whether to "remove" the inactive nodes. If this one is clicked on, then a second button becomes visible asking whether to "show" the inactive nodes. Both of these processes involve removing all of the nodes and then repopulating the tree with logic determining whether to include or exclude the inactive record.

With a couple of hundred nodes, it's not too bad. But, just for grins, I created a tree that had close to 50,000 nodes - that took awhile! Even if there were only 1 inactive node, to remove it takes cycling through the tree twice - once to remove all the nodes and then again to rebuild it. Not real efficient!

I've thought about doing something like setting the "tag" property to "inactive" for those records that are and then cycle through all of the nodes and "remove" the node if its tag is "inactive; that will take care of that aspect. But how about adding back in the inactive records when that particular button is clicked?

Along a similar vein, I'd like the user to be able to "duplicate" an existing (child) node and have it show up directly below the node selected. It would be a sibling of the existing node. From what I've been able to find, I can add the new child node but it's going to show up at the bottom for that particular parent - and that simply won't do!

Any ideas?

It is SOOOOO hard to find any descent discussion and/or examples on Treeview and yours has been the best I've found so far!

Keep up the good work!

Anonymous said...

Thank you for this tutorial! This is the first thing I've found that gives this novice any hope of understanding how to implement the treeview control - I'm anxiously looking forward to Episode 5!

Wayne and Netty said...

Episode 5????
I would like to know how to open a filtered form based on a selected node, for example all orders of cheese, when a user clicks on cheese in the treeview.

Anonymous said...

Great article.

I am getting started.

Can you demonstrate checkboxes in tree view?

~~ Destiny ~~ said...

Hi, It is fun to play this tree control in Access.

I got problem to add the content which was in hyperlink field type into tree ?

I appreciate some 1 have an ideal of how to allow / add it ?

Anonymous said...

Thanks a lot man. This was very helpful.

Stephen said...

I see there are lots of questions about images- that will be episode 6. The long awaited Episode 5 was just posted and covers showing a subform based on the clicked node. I'll do a pop-up form based on a double click in 7 or 8. And as to checkboxes- I've just doen one of those for the first time myself and it worked great, so look for that within the next few episodes as well.

Anonymous said...

These Q&A comments are extremely valuable! I have a question: I've been trying to return to a specific node programmatically (VBA) after the Treeview has been rebuilt. I capture and store the node's index key but I just can't get the Treeview to expand 'back' to the node I had selected. Are there any solutions to my delimma?

Joe in Virginia Beach said...

This was a wonderful 7 Episode FAQ!!! I have my TreeView Humming!

I used your ColapseAll function, gutted it and turned it into an Instant Search Function!

If nodthis.Key = SearchString then
nodthis.selected = true
nodthis.expanded = true
Call myTreeView_Click
end if

Thats not the exact code I used, but it gives you the idea!

Again... Thanx TONS!
Joe

Anonymous said...

thank you so much for this tutorial!

cheers from sweden!