Navigation around an environment is often one of the most overlooked portions of an application, yet it is one of the most critical aspects of any application. Being able to quickly and effortlessly move around and locate the items a user needs is one of the characteristics of a well defined application.
One reader wrote in asking how to utilize the 'TreeView' and 'ListView' objects in combination with each other. He was creating an application that required the user to navigate around a folder structure until the proper file was located. There are numerous examples of this in C# or VB.NET, but he couldn't locate a COBOL based example. Working with one of our Architects we were able to provide an example and thought it would also make a great topic for an article.
We split the article into two segments, the first one dealing with the TreeView object and the second dealing with the ListView object.
According to Wikipedia, "A tree view or an outline view is a graphical user interface element (widget) that presents a hierarchical view of information. Each item (often called a branch or a node) can have a number of sub-items." So basically a tree view is a way to graphically present information, enabling a user to browse the information and selecting the item (or node) they wish to interact with. Our completed example will look similar to the following:
Our example will have a predefined folder to search, namely "C:\Temp". If you do not have this folder in your environment simply update the code to reflect a folder where you have the proper rights to read from. As we stated earlier, we will design and enable the TreeView portion of the above screen for this article and the ListView portion in the next article.
Designing the Form
Begin by creating a Windows Forms Application project. To make things easier I named the project 'TreeView'. When the project is created you will have a blank form and are now ready to begin adding the objects we will need.
Before adding the controls I like to 'clean-up' the form and update the Title bar and icons. I changed the Title to be "Micro Focus Tree View Sample" and the icon to my favorite icon, "favicon.ico". I've also included the icon in the zip file for you. I also resized the image to be a bit wider. Now let's start adding the objects to build our form.
First, select the TreeView control from the Toolbox in the left pane. When you first drag the Tree View control onto the drawing palette the image appears as below.
Resize the image to approximately one-third of the Form window.
I accepted all the defaults for the control. We now need to start adding some code to populate the TreeView. If you select the form (make sure you select the Form and not the TreeView), right mouse click and select 'View Code' the following screen will be displayed.
We are going to add three sections of code, one we are going to add some .NET classes to help enable our coding to function, two an update to the 'NEW' method, and three we are going to create a new method to populate the Tree View. Before we begin updating our methods though we need to enable a mechanism to let us specify classes we will be using without having to fully qualify the location. The 'ilusing' directive permits this functionality. 'ilusing' allows us to reference .NET classes in abbreviated form, so that for instance, when ilusing 'System.IO' we can say "01 subDir type "DirectoryInfo" instead of "01 subDir type "System.IO.DirectoryInfo". Just above the Class-ID token add the following:
Make sure the '$' is in column 07 when you add these. Using the 'ilusing' directive enables us to place these references inline and makes it easier to see what is available. I won't go into detail about these references other than to say they are required as part of our coding. If you would like additional information on any of the namespaces, use the Help System to research what the namespace provides and why it is required. Now let's begin adding our code.
Updating the NEW method
The 'NEW' method is the standard method employed when a form is created. It invokes the necessary assemblies within the environment to allocate the resources that actually 'paint the page' with our design. We are going to expand the functionality of the method to also enable the form to populate our Tree View control when it is first created. Before we can add a line to our method we have to know what the method will be named. For our example we will name our method "PopulateTreeView". In the 'NEW' method, add a line after the call to 'InitializeComponent' to call our "PopulateTreeView" method using the following syntax:
When you are done your 'NEW' method should appear as follows:
Populate the Tree View method
We now need to add a new method called "PopulateTreeView". We can add the method outline manually, but that means we have to remember the proper syntax, column locations and spelling of the template. Or we can use a snippet. To use snippets do the following:
- Position your cursor in column 8, right below the line "end method NEW".
- Right mouse click. The following menu should be displayed.
- Select Insert Snippet.
- The following menu will be displayed
- Using the slider on the right side of the menu navigate to the 'Method' snippet and double click.
- A new method will be inserted into your code.
- Now we can begin updating the method.
Populate TreeView Method
Our first order of business is to update our new method with the proper name. Change the name of the method to 'PopulateTreeView' and press tab. Notice a couple of things that happen when you do this:
- The 'end method' tag is updated with the method name
- A dropdown list box appears with the type of method.
- Select 'private' from the dropdown list box and press enter or double click.
Now let's start coding up our method. To begin we need to define some Working-Storage variables. These aren't going to be the typical COBOL style definitions though, we're going to be using some .NET elements to define our directory structures, tree nodes and strings. Remember, one has to expand one's knowledge in order to progress and this exercise will help further expand your knowledge into the .NET arena. Let's start. Below is the completed working-storage section for you to review. We'll explain each line below.
- rootNode type "TreeNode" : this will be used when we select the node in
the tree we are interested in.
- info type "DirectoryInfo" : the information related to a directory. The
namespace is used for exposing instance methods for creating, moving and
enumerating through directories and sub-directories.
- infoArray type "DirectoryInfo" occurs any : Same as above but a
collection of directories and sub-directories. Notice the 'occurs any'
syntax? This is how we identify an array in COBOL.NET. In C# terms this
would be defined as "DirectoryInfo"
- wsName string : basic string variable to identify the name of the
Our method is going to start at a particular location, in this case "C:\Temp" and loop through each sub-directory until all of them have been processed. We'll take advantage of the .NET environment and use a Boolean condition to tell us if more sub-directories exist or not. We will also call a new method to load the directories into the array, more on that in a bit. First our completed PopulateTreeView method looks like the following:
While this may seem a bit confusing initially, once you work through the code it becomes more understandable.
- set info to new "DirectoryInfo(C:\temp)" : This sets our starting
location and gathers the information about the structure.
- if info::"Exists" : A check to make sure our directory exists. If it
does we proceed, if not we exit.
- set rootNode to new "TreeNode"(info::"Name") : create a new instance of
the TreeNode class using as a reference our starting point.
- set rootNode:: "Tag" to info : gets the object, in this case 'info',
that contains data about the tree node and moves it to the object that
contains the DirectoryInfo we will be using, in this case 'rootNode'.
- set wsName to info::"FullName" : Save the full name of the folder we're
- set infoArray to info::"GetDirectories"() : Get the list of
- invoke self::"LoadDirectories"(infoArray, rootNode) : Call a method 'LoadDirectories"
to walk through the directories and identify the information contained in
each. We'll code this up next.
- invoke treeView1::"Nodes"::"Add"(rootNode) : Add the node to our tree.
Now let's define the LoadDirectories method.
Load Directories Method
The LoadDirectories method will do as its name implies, walk through each folder and load the sub-directories into the array. The coding to accomplish this looks similar to the following:
Again, looks a bit overwhelming but let's take it apart. Notice this time we didn't break out the Working-Storage section and there's a Linkage Section too. These sections are self-explanatory as they are similar to the previous discussion. The Procedure Division for the method though is:
- perform varying subDir the subDirs : subDirs contains our list of
sub-directories. We'll use it to 'walk the list' of sub-directories,
processing each in turn.
- set aNode to new "TreeNode"(subDir::"Name", 0, 0): Create a new TreeNode
using the information supplied from the current iteration of subDir and
place it at the default location (identified by the zero, zero).
- set aNode::"Tag" to subDir : gets the object, in this case 'subDir',
that contains data about the tree node and moves it to the object that
contains the TreeNode we will be using, in this case 'aNode'.
- set aNode::"ImageKey" to "sp2" : Sets an icon to be used for the folder
- set subSubDirs to subDir::"GetDirectories"() : Gets a list of
sub-directories to be processed
- if subSubDirs::"GetLength"(0) <> zero : checks to make sure we have
sub-directories to process. This is a great example of using the built in
functions of the object to supply us with data. If this wasn't available we
would have to create some code to walk through the list trying to identify
if we have any sub-directories, which could become quite a long program in
and of itself!
- invoke "LoadDirectories" using subSubDirs aNode : Another cool feature
of .NET, recursion. We are recursively calling the method we are in, 'LoadDirectories'
to process the current sub-directory. A very useful technique.
- invoke nodeToAddTo::"Nodes"::"Add"(aNode) : Finally add the node to the
You should be able to build and execute the project. When it executes you will have a display similar to the one below:
I understand, it's not a really pretty picture but it does accomplish our first goal of being able to walk through a directory structure. Save and build the project then run it without debugging to make sure the project executes. Once you have it running, set a break-point and walk through the code. Understand what each step is doing. Try changing the code to a location on your machine with a lot of sub-directories and see what happens (be careful, make sure you have access to them first). Our next article will add the ListView control to the right side of the screen and show you the files and sub-directories contained in each of the directories.