Level Extreme platform
Subscription
Corporate profile
Products & Services
Support
Legal
Français
Articles
Search: 

The Treeview ActiveX control - the basics
Jim Nelson, February 1, 2003
You’ve decided that you need to use the Treeview and now you need to learn how. But man, the “documentation” leaves you in more doubt, leaving far too many questions unanswered. You’ve also searched the UT and referenced the few articles available, and while they help to fill in many gaps, they more...
You’ve decided that you need to use the Treeview and now you need to learn how. But man, the “documentation” leaves you in more doubt, leaving far too many questions unanswered. You’ve also searched the UT and referenced the few articles available, and while they help to fill in many gaps, they more “hand you a fish” rather than “teach you to fish”, and you’re the kind of person who needs to know the ‘whys’ of things. I feel your pain, because I just went through the exact same thing last month.

The following is intended to describe the basic factors relating to implementing the ActiveX “Treeview” component supplied with Visual FoxPro. In this case the information is applicable to VFP7 SP1.

This document does not include the “ImageList” control that can be used to add images to nodes, nor does it include the “Listview” control often seen used in conjunction with the Treeview control (Windows Explorer, for example, as the right side display pane).

Adding the control to a form

This is started in the same way as any other control is added. In this case the “ActiveX Control (OLEControl)” icon is clicked on the (standard) “Form Controls” toolbar. Then the mouse is moved to the area of the form where the top left corner of the control is to be positioned, downclicked, then dragged to where the bottom right corner of the control is to be.

Releasing the mouse at the appropriate point leads to a small delay and then presentation of the “Insert Object” dialogue (Figure 1 below). A listbox in the dialogue, titled “Control Type”, shows the available controls installed in the system. Hitting the “m” key positions the listbox to the first one with the name starting with “m”. In my case this was the “Macromedia Flash Factory Object”. Clicking on the scroll bar (downward) of the listbox eventually revealed the “Microsoft Treeview Control” – two in my case: “Microsoft Treeview Control 6.0 (SP4)” and “Microsoft Treeview Control, version 5.0 (SP2)”.


Figure 1

I initially selected the latest version (6.0 SP4) but found that later use of the F1 key to obtain its help produced nothing. Trying the other control instead (version 5.0 SP2) did result in a display of its help when I pressed the F1 key. My guess is that the “6.0 SP4” version came with the VFP8 public beta that I had downloaded and installed on the same machine. The F1 key does present help for the control but it is very poorly organized and there are missing properties and methods. I recommend the use, in addition to F1, of the Object Browser supplied with VFP7 and later versions.
Figure 2
Figure 3
Double-clicking on the “Microsoft Treeview Control version 5.0 SP2” results in the designated form area being filled as shown in figure 2 to the left and the property sheet as shown in figure 3 at the right here. The property sheet effectively lists a “merged” set of properties – those applicable to VFP’s control and those specific to the Treeview control. The latter are shown in blue font in the values side of the property sheet.

Working with the Treeview control properties

Once the Treeview control is shown on the form design surface, clicking anywhere on it to make it the selected control and then hitting the F1 key will present a Help file for it. In addition, right-clicking on the (selected) Treeview control presents a popup menu with the selection “TreeCtrl Properties” as the last one. Clicking on that item presents the “TreeCtrl Properties” dialogue as shown in figure 4. An example of its use is shown below (figure 5), obtained by clicking on the “Checkboxes” checkbox in the dialogue and then clicking “Apply” and then clicking “OK”. Notice too that the dialogue has three tabs.

Figure 4


Figure 5

When you wish to manipulate the Treeview properties (above) programmatically you must use the “Object” property name within the name structure. Based on the figures here, and assuming the Treeview control has been placed on the form named “Form1”, the control would be (programmatically) disabled by coding:
Form1.Olecontrol1.Object.Enabled = .F.
I could not find this property of the VFP OLEControl mentioned in the property sheet or anywhere one might regularly refer to during development. However, it is mentioned in the section titled “Manipulation of Objects with Automation” under the topic “Using ActiveX Controls”, under the topic “Adding OLE Objects to Applications”, under the topic “Sharing Information and Adding OLE”, under the topic “Interoperability and the Internet”, under the topic “Extending Applications” in the “Using Visual FoxPro” part of the online Help. Phewww! The only way I found it was by using the Search option. Going through the “Content” I stopped clicking deeper in the topic tree once I came upon the topic “Interoperability and the Internet” because it seemed unrelated to the object (pun) of my need. It is noteworthy that the VFP documentation content itself is presented in a Treeview control.

Programming the Treeview control

In essence, the Treeview can be used to present any data that is hierarchical in nature. It can also be programmed to permit the user to make changes to the data presented, though of course if you do so you must also program to change the actual data in addition to accepting the user-typed revisions. For example, Windows Explorer allows you to rename a directory name presented in its left pane and in the background it also performs an actual rename of the directory.

Much of the data in our VFP applications is hierarchical. The Treeview can be used to give a user access to a list of top-level entities with the ability to "drill-down" to obtain details pertinent to a specific item. An example might be a root level list of 'assembly' part numbers, with component part numbers available on expanding the node. Sub-assemblies listed in that expansion could also be made expandable to show their component parts.

The Treeview control itself is just an empty box. To use it you must first fill it with the information you wish to present. Once you’ve done that, you likely want to react to actions that the user performs on the content. You may even want to store pertinent information after the user indicates that they have finished their work with the form or the record(s) displayed on the form.

Inherent in the Treeview control are two additional controls. The Nodes collection object is used to create and maintain the content of the Treeview while the Node object can be used to manipulate the display and/or content of a specific node within the Treeview content. The Nodes object can also be used to manipulate a specific node using its Item property.

The first thing that you need to do is to fill the Treeview with user-viewable content. To do this you will use the Add() method of the Nodes collection object. The syntax of the Add() method is (mostly from the Help file):

ONewNode = tvwRef.Nodes.Add([relative],[relationship],[key],text,[image],[selectedimage])
This method adds a node to the subject Treeview control, positioned based on the “relative” and “relationship” argument content. The first node added is given the (implied) index value of 1 and nodes added subsequently each have their index value incremented by 1. Since nodes can be added in any order, and can also be Remove()d, the index cannot be used reliably to step sequentially through the tree as it is displayed to the user. This is also the case when the Sorted property is set to TRUE. The “key” property may be a better way to directly access some specific node. It is possible, though, that your use will not even need to access a specific node, in which case neither the index nor the key property is relevant. Many consider the Treeview to be a “slow” control, particularly depending on the data source and its record count. In such cases it may be appropriate to dynamically add nodes to the (next) child level only as the user expands the node.

The arguments for the Add() method are defined below (it returns a reference to the added node):

Argument Explanation
relative Optional and, when specified, identifies a pre-existing node by either its index value or its key. The relationship of the node referenced in this parameter and the new node being added by this statement is defined in the next parameter. When this argument is omitted, the node added is placed in the last position of the top node. Note that “relative” is used here in the sense of ‘family’ (child, parent, etc.).
relationship Optional and, when specified, states the placement of the node being added in relation to the relative identified above. The permissible values are:

Value Description Constant
0 First. Node is placed before all other nodes at the same level of the node named in relative. tvwFirst
1 Last. Node is placed after all other nodes at the same level of the node named in relative. Any Node added subsequently may be placed after the one added as Last. tvwLast
2 (default) Next. Node is placed after the node named in relative. tvwNext
3 Previous. Node is placed before the node named in relative. tvwPrevious
4 Child. Node becomes a child node of the node named in relative. tvwChild
key Optional and, when specified, is a unique string expression that can be used to access this specific node later. Safest to ensure at least one alphabetic in the string as one that is all numbers may be interpreted as numeric, causing an error. Note that a node can be accessed directly in the Nodes collection by index or by key value. Using the key value may be the most practical.
text Required. The string that is displayed in the Treeview control for the node being added.
image Optional. An integer value to set the icon from the (optional) associated ImageList control that is identified in the “ImageList” property of the Treeview control.
selectedimage Optional. An integer value to set the icon from the (optional) associated ImageList control, to be displayed when the node is selected.

Shown below is some sample code used to fill a very simple Treeview on a form. It is taken from the sub-classed Treeview, coded in a method named “PopulateTheTree()” invoked in the form’s Init(). The input is a table of two field records where “TypeName” will constitute a “top” (root) node and “SubType” will be a child of that “TypeName”. The records are sourced from a local view which specifies DISTINCT and sorts the records ascending by “TypeName” and “SubType”. The record format in this case assures that every top (root) node will have at least one child.

SCAN
   IF EMPTY(SubType) OR EMPTY(TypeName)   && guard against an invalid record
   ELSE                                   && we have content that is valid 
*  When the "TypeName" changes, we need to create a new 'root' (parent) item
      IF TypeName <> m.LastType
         m.LastType       = TypeName
         m.LastRootNumber = m.LastRootNumber + 1 
         m.LastRootKey    = ALLTRIM(TypeName)  ;
                           + PADL(ALLTRIM(STR(m.LastRootNumber, 4, 0)), 4, "0")

         This.Nodes.Add( , ;              && existing key string or index number
                         tvwNext, ;       && relationship to above
                         m.LastRootKey, ; && key (string)
                         TypeName, ;      && text to be displayed
                         , ;              && image# in ImageList
                         )                && SelectedImage# in ImageList
      ENDIF  
* Now we add the "SubType" as a child node of the current parent 

      This.Nodes.Add( m.LastRootKey, ; && existing key string or index number
                      tvwChild, ;      && relationship to above
                      , ;              && key (string)
                      SubType, ;       && text to be displayed
                      , ;              && image# in ImageList
                      )                && SelectedImage# in ImageList
   ENDIF [EMPTY(SubType) OR EMPTY(TypeName)]
ENDSCAN
Other properties and methods of the Nodes collection are:

Properties
Count returns the total number of items in the collection.
Item returns a specific node (reference), by position (index) or by key.

Examples:

oNodeRef = tvwRef.Nodes.Item(index)
oNodeRef = tvwRef.Nodes.Item(key-value)

Methods
Clear removes all node objects from the Treeview.
Remove removes a specific node (reference), by position (index) or by key.

Examples:

=tvwRef.Nodes.Remove(index)
=tvwRef.Nodes.Remove(key-value)

The Count property is useful if you have the need to step through the entire Nodes collection because it always reflects the exact count of nodes in the entire tree.

The Remove() method will remove a specific node, and if you have chosen to dynamically add child nodes as a parent node is expanded then this method can be used to remove those same nodes once the user has collapsed the parent node. Every node you Remove() decrements the Count property by one.

Once the Treeview has been populated (all nodes or just the top node level) the users can access and manipulate things in it. So the next thing you will do is to react to the user’s actions. While there are more (all Treeview PEMs are summarized, listed alphabetically at the end of this article), the most common events of the Treeview control that you will code for are:

Action Explanation
Collapse() occurs when a Node object is collapsed. By definition the node has children.
Expand() occurs when a Node object is expanded, exposing its children to user view.
NodeCheck() occurs only when the CheckBoxes property is TRUE, when a checkbox is clicked.
NodeClick() occurs when a Node object is clicked, but not when a (node) checkbox is clicked.

In all cases above a node object (reference) is passed as the LOCAL parameter, named “node”.

The Node object has several properties and a single method. I have broken the properties down into two categories – regular and object (references). The properties are:

Regular
Checked*, 1 Logical Applies when CheckBoxes is TRUE. .F. means UNchecked.
Children Numeric Returns the number of children for the node. 0 means none.
Expanded* Logical .T. means the node is expanded, .F. that it is collapsed.
ExpandedImage* Integer Specifies an image in an ImageList control.
FullPath String Returns the fully qualified path (top node to this node).
Image* Integer Specifies an image in an ImageList control.
Index Numeric Returns the unique index of this node in the collection.
Key* String Unique value to identify this specific node of the collection.
Selected* Logical TRUE indicates the node is selected, FALSE that it is not.
SelectedImage* Integer Specifies an image in an ImageList control.
Sorted* Logical Specifies if nodes at level of passed node are sorted or not.
Text* String The string value that appears in the treeview for this node.

*These properties can be set as well as interrogated.
1The Checked property was not in the Help, but rather found using the Object Browser.

Object
Child To obtain an object reference to the first child of this (passed) node.
FirstSibling To obtain an object reference to the first node at same level as this node.
LastSibling To obtain an object reference to the last node at same level as this node.
Next To obtain an object reference to the next node at same level as this node.
Parent To obtain (or set?) an obj. ref. that is (or to be set?) parent of this node.
Previous To obtain an object reference to the previous node at same level as this.
Root To obtain an object reference to the root node of the Treeview.

The sole method is EnsureVisible() and takes a node object reference as its parameter. It will expand Treeview node(s) and/or scroll the Treeview as necessary to ensure that the passed node is made visible to the user.

The documentation for the Selected property mentions another property named “MultiSelect” (of the Treeview?) but I could find nothing to confirm that it exists as a real property of the Treeview control and Treeview’s observed operation suggests that it is not an applicable property.

Using the Object Browser (VFP7 and later) to review ComctlLib (which is the Microsoft Windows Common Controls 5.0 (SP2)) and MSComctlLib (which is the Microsoft Windows Common Controls 6.0 (SP4)), the following differences were noted between the properties enumerated in the Help versus those listed. I don’t know that any of the named properties below can actually be used in a program (save “Checked”, which can for sure).

Found in both classes using the object browser:

Property Difference
Tag Stores any extra data needed for your program.
Visible Returns/sets logical controlling if object is visible or hidden.
Found only in MSComctlLib (6.0 (SP4)):

Property Difference
BackColor Returns/sets the background color used for displayed text of a Node object.
Bold Returns/sets logical controlling if text of Node is displayed in bold font.
Checked Returns/sets logical controlling if the Node object is checked or not.
ForeColor Returns/sets the foreground color used for displayed text of a Node object.

As noted earlier, all four of the most used events of the Treeview control have a node object reference passed as the single parameter. This fact leads to some interesting capabilities as far as coding to refer directly to other related nodes is concerned. Some examples are shown below. Keep in mind that “node” is the LOCAL parameter name passed to the event.

IF node.Children > 0                         && node has children
* For illustrative purposes we will go backwards checkmarking each child
   PriorChildRef = node.Child.LastSibling    && < -------- #1
   FOR X = 1 TO node.Children
      PriorChildRef.Checked = .T.            && checkmark this child
      PriorChildRef = PriorChildRef.Previous && < -------- #2
   NEXT X
ENDIF
The line commented #1 above shows how an object reference to the last child node can be obtained directly using the (object reference) properties of the passed node. This works because each property is actually a Node object (reference) itself, so each has all of the properties of a node object. This line of code is actually ‘saying’ “give me an object reference to the last sibling (last node at level (.LastSibling)) node of the child node (.Child) of the node in process (passed in parameter (node))”. The same line might alternately have been coded as follows:
ChildOfPassed = node.Child
PriorChildRef = ChildOfPassed.LastSibling
The line commented #2 above simply shows how the (memvar) object reference created by the line annotated #1 can itself be used to reference the prior (child) node. Because the Nodes collection object’s Item property returns a Node object reference, all of the Node PEMs can be addressed in a …Nodes.Item… statement. Examples (unrelated to above) are:
ChildCount = ThisForm.tvwRef.Nodes.Item(1).Children
FirstOfDaddys = ThisForm.tvwRef.Nodes.Item(“KEY007”).Parent.FirstSibling

Miscellaneous notes about the Treeview control

While I could find nothing definitive on the matter, there likely are limits inherent in the control itself.

One source put the limit of nodes in a Treeview at 32,000. If this is in fact the case, I assume that dynamically adding nodes as the user expands a parent node and removing those (added) children once the user collapses that parent can still make the control practical for most uses. Of course this would also be dependent on the user’s collapsing some of those expanded nodes from time to time.

I imagine, too that there is a limit regarding the length of any key value (string) that you can use. Can’t say if there might be a limit on the cumulative length of all key string values.

I could not find any limit stated for the text (label) property of a node but again I suspect that there is one.

I couldn’t locate anything defining/describing errors that might occur when using the Treeview control, nor do I know if such errors are trappable within VFP.

The Treeview is the control used in the Windows Explorer application’s left pane to display the volumes, directories and special files of the system (the right pane is presented using the “Listview” control). The Treeview is also used in the “Project Manager” window in VFP.

The Treeview control is often used by software installation routines to present selectable options for inclusion. In this case the “CheckBoxes” property is often TRUE.

Finally, it is worth keeping in mind that while the functionality of the Treeview control is well understood by systems people, the same cannot be said for your average clerical user. So you will be wise to explain its use in some detail in your application documentation and/or spend significant time going over its usage in user training sessions.

I hope that this article has helped you to implement your own Treeview controls with a little more ease than I experienced. There are more complex and powerful methods and events available in the control and I expect that you will be able to play with them once you have succeeded in implementing your first one.

Summary of all PEMs for the Treeview control

This summary does not include the Nodes collection object or the Node object because their PEMs are all documented in the body of the article.

The Treeview control itself has several properties, events and methods available. Their names and a summary of their functionality are listed below.

AfterLabelEdit Event

Occurs after a user edits the label* of the currently selected Node or ListItem object. I suspect that this event only occurs when the “LabelEdit” property is set .T. *I believe this refers to the “text” property of the node (refer to Nodes.Add()).

BeforeLabelEdit Event

Occurs when a user attempts to edit the label* of the currently selected ListItem or Node object. *I believe this refers to the “text” property of the node (refer to Nodes.Add()).I suspect that this event only occurs when the “LabelEdit” property is set .T.

Checkboxes Property

Returns or sets a value that determines if checkboxes appear left of each displayed node’s text.

Collapse Event

Generated when any Node object in a TreeView control is collapsed.

DropHighlight Property

Returns or sets a reference to a Node or ListItem object that is highlighted with the system highlight color when the cursor moves over it. [given this description, I have no idea what the “Drop” word is doing in its name]

Expand Event

Occurs when a Node object in a TreeView control is expanded. That is, when its child nodes become visible. FullRowSelect Property

Returns or sets a value that specifies if the entire row is selected. I suspect that this refers specifically to the selected highlight colour and that a .T. value causes the checkbox and/or image, when either is present, to also be highlighted.

GetVisibleCount Method

Returns the number of Node objects that fit in the internal area of a TreeView control.

HitTest Method

Returns a reference to the ListItem object or Node object located at the coordinates of x and y. Most often used with drag-and-drop operations to determine if a drop target item is available at the present location.

HotTracking Property

Returns a value that determines whether mouse-sensitive highlighting is enabled. [not sure what this means, actually, because when I have the property Unchecked in the “TreeCtrl Properties” dialogue the ‘tooltip’ still is displayed when I mouse over node text that extends near or beyond the right edge of the display]

ImageList Property

Specifies the name (object reference) of a separately instantiated (and filled) ImageList control. This property is not described in the documentation, other than appearing in the “TreeCtrl Properties” dialogue.

Indentation Property

Returns or sets the width of the indentation of objects in a control.

LabelEdit Property

Returns or sets a value that determines if a user can edit labels of ListItem or Node objects.

LineStyle Property

Returns or sets the style of lines displayed between Node objects.

NodeCheck Event

Occurs when the CheckBoxes property equals True and a Node object is checked or unchecked. The checkbox will have the stateas set by the operator upon entry to this event. [this event does not occur when a node is checked or unchecked programmatically] [there seems to be a bug that the node passed in the parameter cannot have its checkbox toggled to the opposite state (from its state on entry)]

NodeClick Event

Occurs when a Node object is clicked. [the node’s checkbox does not appear to be accessible through this event, at least as far as the node passed as the parameter is concerned]

Nodes Property

Returns a reference to a collection of TreeView control Node objects. PathSeparator Property

Returns or sets the delimiter character used for the path returned by the FullPath property.

Scroll Property

Returns or sets a value that specifies if scrollbars are displayed.

SelectedItem Property

Returns a reference to a selected ListItem or Node.

SingleSel Property

Returns or sets a value that specifies if an item is expanded when selected. [another case where the property name doesn’t seem to reflect its functionality]

Sorted Property

  • Returns or sets a value that determines whether the child nodes of a Node object are sorted alphabetically.
  • Returns or sets a value that determines whether the root level nodes of a TreeView control are sorted alphabetically.
When set to TRUE, nodes are likely not accessible in sequential index order.

StartLabelEdit Method

Enables a user to edit a label. [not sure exactly how this fits in]

Style Property

Returns or sets the type of graphics (images, text, plus/minus, and lines) and text that appear for each Node object in a TreeView control.

Jim Nelson
Jim Nelson passed away May 21st 2008. I am his son. I logged onto his computer just the other day and the universal thread came up. He is gone. I continue to miss him.
More articles from this author
Jim Nelson, January 1, 2001
Current behaviour of RELEASE where OBJECT memvars are concerned The Help for the RELEASE command of both VFP 5 and VFP 6 summarizes its function (in the header statement) as follows: "Removes variables and arrays from memory" Now this does not explicitly state that OBJECTs are included in t...