Tips_gui   >   Treelists   >   Treelists

Treelists

: a hierachical list with expandable and collapsable nodes.

Picture a tree in the forest, this is the picture you need to have in your mind when you think and talk about treelist objects in the computer world. Every branch of a tree is connected to a parent branch, which is connected to another parent branch, and eventually the branches connect all the way back to the root of the tree. There is only one root for each tree.

Treelists are among the last hold outs in my Omnis Studio learning experience. I remember attending a class on treelists at my first Omnis conference. After that session my thoughts were "Treelists are too much work, I'll stick with lists, they are a lot easier".

Treelists might be more work for the programmer, but in the right situation they are the best GUI.

Imagine trying to navigate the StudioTips Browser without treelists! Treelists are great for presenting lots of information in a format that allows the user to explore the layers on their own.

Treelist Naming Conventions

When dealing with treelists, it is important to clearly understand the some of the different terms used:

  1. Treelist Object - The actual window field object that is used to display the treelist to the user.
  2. Root Node - Any node at the first level of the treelist.
  3. Parent Node - The node one level above a child nodes as viewed by the child node.
  4. Child Node - Any node which is attached to a parent node as viewed by the parent node.

Think of the treelist object itself as the level zero (0) parent node. The treelist object is the parent node of all the level one (1) root nodes. Each of the level one (1) parent nodes can have level two (2) child nodes, etc.

The naming conventions used in the sample code in this section are as follows:

A Run Demo button will appear at the bottom of the StudioTips Browser window if a demo is available for a particular tip. Clicking the Run Demo button will open up a demo window.

For most of the demos in this section, you can play around clicking on different nodes in the treelist and then clicking the pushbutton to test the method on different nodes.

Holding down the shift key while clicking the button in the demo window will take you to a breakpoint in the method code allowing you to step through the actual code so you can see what is happening behind the scenes.

Populating a Treelist

You can populate a treelist object from a list variable using the $setnodelist method. See $setnodelist and $getnodelist in the Treelist Methods & Properties topic for more information.

There are 3 types of lists which you can use in the $setnodelist method.

  1. kRelationalList - simplest form.
  2. kFlatList - lets you specify the node properties.
  3. kTreeColList - lets you specify the node properties and display columns.

When I was first learning to use treelists I prepared the appropriate list and then used the $setnodelist method to populate the treelist. Preparing the list was a lot of work and one of the reason I steered clear of using treelists.

Later I learned how to populate the treelist object on-the-fly using notation.

Typically I build the root level nodes with the expand node icons. When the user clicks to expand a node I trap the evTreeExpand event and using pNodeItem to find out which node is being expanded, clear the child nodes and add the child nodes one at a time in a loop. As each node is added you use the node reference to set the node properties.

Populating treelists on-the-fly is fast, flexible, and in my opinion much less work than populating them from lists.

The following sample code shows how to build the root nodes of a treelist object.

; Treelist Method: buildTreelist

; Call this method from the $construct method of the treelist object.

; Build a treelist which displays all object classes in the current library.

; Clear all the treelist nodes.
Do irTreeObj.$clearallnodes()

; Make a list of all the object classes in the current library.
Do $clib.$objects.$makelist($ref().$name,$ref) Returns ClassesList
Do ClassesList.$cols.1.$name.$assign('name')
Do ClassesList.$cols.2.$name.$assign('ref')
Do ClassesList.$sort(upp($ref.name))

; Loop through the classes list, building the treelist root nodes.
For ClassesList.$line from 1 to ClassesList.$linecount step 1
   
   ; Add the root node and set the $tag to reference the class.
   Do irTreeObj.$add(ClassesList.name) Returns rNode
   Do rNode.$showexpandalways.$assign(kTrue)
   Do rNode.$tag.$assign(ClassesList.ref)
   
End For

Quit method kTrue

The following sample code shows how to add child nodes on-the-fly.

; Treelist Method: addChildNodes (prParentNode, prClass)

; Build a list of the methods for the specified class.
Do prClass.$methods.$makelist($ref().$name,$ref) Returns MethodsList
Do MethodsList.$cols.1.$name.$assign('name')
Do MethodsList.$cols.2.$name.$assign('ref')
Do MethodsList.$sort(upp($ref.name))

; Loop through the methods list.
For MethodsList.$line from 1 to MethodsList.$linecount step 1
   
   ; Add a child node.
   Do prParentNode.$add(MethodsList.name) Returns rNode
   Do rNode.$tag.$assign(MethodsList.ref)
   ; Note: You can set any additional node properties here.
   
End For

Quit method kTrue

The following code traps evTreeExpand in the $event method of the treelist object and calls the addChildNodes method.

; Treelist Method: $event

On evTreeExpand

; Clear the child nodes.
Do pNodeItem.$clearallnodes()

; Add the child nodes.
Do method addChildNodes (pNodeItem,pNodeItem.$tag)

The following sample code shows how $constuct method of the treelist object points the instance variable irTreeObj to itself and then calls the buildTreelist method.

; Treelist Method: $construct

; Point the irTreeObj ivar to this treelist object.
Set reference irTreeObj to $cfield

; Build the treelist.
Do method buildTreelist Returns FlagOK

Quit method FlagOK

Click the Run Demo button in the StudioTips Browser window to view a demo window which use the above code.

Store and Restore Treelist

In the StudioTips Browser I needed to be able to store and restore the exact state of each treelist which you look at in the StudioTips Browser. That way if you close the StudioTips Browser window, when you reopen the window each treelist will be reopened in the same state that you last looked at them.

Tech Support gave me the solution. You simply use the parameter #NULL in the $getnodelist and $setnodelist methods.

The following sample code saves the current state and current node.

; Save the current treelist 'state' and selected node.

; Get the current state of the treelist. Tip from Tech Support.
Do rTree.$getnodelist(kTreeColList,#NULL,List)

; Get the current node of the treelist
Do rTree.$currentnode() Returns rNode
Do rTree.$getvisibleline(rNode) Returns VisLineNum

; Save the list and visible line number.
Do method saveTreelistState (rTree,List,VisLineNum) Returns FlagOK

Quit method FlagOK

The following sample code restores the last state and last current node.

; Restore the last treelist 'state' and selected node.

; Get the last state list and visble line number for this treelist.
Do method getTreelistState (rTree,List,VisLineNum) Returns FlagOK
If FlagOK
   
   ; Clear all the nodes
   Do rTree.$clearallnodes()
   
   ; Set the treelist
   Do rTree.$setnodelist(kTreeColList,#NULL,List)
   
   ; Get a reference to the last selected visible node
   Do rTree.$getvisiblenode(VisLineNum) Returns rNode
   
   ; Set the current node
   Do rTree.$setcurrentnode(rNode)
   
End If
Quit method FlagOK

Warning

The $tag property can not be saved back to any of the nodes lists (kFlatList,kRelationalList,kTreeColsList). If you need to save the $tag value to a nodes list considering adding/using a column in the $rowdata property instead.