The TreeDropper Control
A custom class written for Visual dBASE 7.01
by Dan Howard - Date: March, 1999

| What is the TreeDropper control? Features What’s included in the package Installation How to use the TreeDropper on your forms Some ideas for it’s use Nuts & Bolts Limitations Conclusion Known issues

What is the TreeDropper control?

The TreeDropper is a new control that is similar in functionality to the stock combobox found in dBASE. This one though will drop down a treeview instead of the simple list. This takes advantage of two of the most powerful classes in dBASE: the container class and the treeview class.

#### Features

- Full featured drop down gives you all the properties available to the treeview.
- Produce hierarchical selection lists and/or simple lists with images.
- The results can appear with or without the hierarchy showing.
- Handles a custom `onChange` event handler if you define one.

Move your mouse over the image to see the TreeDropper in action!

#### What’s included in the package

- `DForm.cfm` – A custom form class that the TreeDropper needs.
- `TreeDrop.cc` – The source for the TreeDropper control.
- `TreeDrop.wfm` – A sample form to demonstrate this control.
- `down.bmp` - A bitmap for the drop button.
- `back.png` - The background for the sample form.
- `arrow.ico`,`darrow.ico`,`dot.ico`,`udarrow.ico` - Icons used in the sample form. Sent to me by George Burt. Thanks George!

#### Installation

Simply extract all of the files from `bu01tree.zip` into a directory, open up dBASE, locate the directory you unzipped the files to and double-click on `TreeDrop.wfm` in the Navigator to see the sample form.

#### How to use the TreeDropper on your own forms

The first thing you should do is open up `Dform.cfm` in the Source editor and review the added methods in it. This base form class handles an important feature of the TreeDropper and any other control you may ever use. DForm uses iteration to look for a special method called `INIT()` in either the form or any control on the form. If it finds one, it runs it before the form opens. This gives you the advantage that all initialization of the form itself or any control on the form can be done while the form is off screen. This prevents a lot of flickering when you open the form. The DForm class can be implemented as a base class for your own forms or you can simply cut the code out and paste it in you own base form class. DForm has a few other goodies as well!

To ensure that the TreeDropper is always loaded when dBASE starts up, open up a form in the form designer, right-click on the component pallet and choose Setup Custom Components from the menu. You’ll see a dialog box which lists all of the custom class files which you currently use. Click the Add button and locate the `TreeDrop.cc` file then click OK. Now this class will be added to your `vdb.ini` file and will be automatically loaded next time you fire up dBASE.

Now go to the Custom tab on the Component pallet, find the TreeDropper object and drag in onto the form’s surface. What you’ll see is something similar to what is shown in the image below. Notice that the button is missing? This is because I create this button dynamically before the form opens and position it at the right edge of the entryfield. This saves you the trouble of having to reposition it yourself in the designer. You also don’t have to worry about the widths of the entryfield or the treeview itself. They will resize themselves to the width of the container.

Notice also the thin line under the entryfield. This is the treeview itself. I make it small so as not to take up too much space on your form. This treeview will be resized and repositioned at run-time depending on the width of the TreeDropper control itself. It’s available in the designer so you can customize the treeview any way you want.

If you want to add treeitems to the TreeDropper in the form designer, use your mouse to expand the container downward and then expand the treeview. You can use this treeview the same as any standard one in the Designer.

You can add, edit and delete items all you want and the information will be saved in your form. There are other ways of filling the treeview with items but I’ll get to that later.

The TreeDropper has a few custom properties which you can use as well. Since dBASE does not yet support custom property streaming they have to be defined in either the `Init()` or `onOpen()` methods of your form.

They are:

- `DropDownHeight`: This property specifies the actual height of the treeview when it drops down (in `char` metrics). It defaults to `7`.
- `ShowParents`: This property affects how the result of the user’s selection appears in the entryfield. When set to `true`, the current selection’s text and each of its parent’s texts will appear in the entryfield. When set to `false` it shows only the current selection’s text. It defaults to `false`.
- `Separator`: This property is used in conjunction with the `ShowParents` property. It’s a string which will show as a separator between each treeitem’s text in the entryfield. It defaults to “`.`”.
- `Selected`: This is a reference to the currently selected treeitem object.
- `IsOpen`: This property tells you whether a particular TreeDropper is open or not. Do not assign to this property. It’s for read-only purposes.
- `OnChange`: If defined, this will fire when the user changes their selection on the TreeDropper.

See the TreeDropForm (`TreeDrop.WFM`) to see how these are implemented.

#### Some ideas for its use

- This control could be one component in an attractive help system.
- You could use this to replace a regular combobox. How about a list of states or provinces with their flags as images?
- It could be used to show parents and relations in genealogy.
- If you’re brave you might consider the concept of making this control data-aware. Very doable.

#### Nuts & Bolts

This class implements some interesting techniques. One of the challenges posed by this control is it’s z-order. If it is dropped below pushbutton for instance, the treeview will show up below it. Not exactly what we want. My solution is to use the Win API `SetParent()` function. This function will attach an object to another object. It takes two `hWND` properties as parameters. See the TreeDropper code to see how it works. There is a limitation to this: a combobox’s list will drop outside the form if necessary — the TreeDropper’s list won’t. I haven’t quite figured out how to do this yet so if you come up with a way, let me know.

I like the ability to create and move objects before the form opens. This allows you to define two types of functionality: design-time and run-time. It also simplifies the use of containers in the form designer as you don’t have to deal with repositioning all of the container’s components. You can define your own rules on how the container’s components will look at run-time.

I create a form property called ActiveTreeDropper in this class. It is a pointer to the currently active TreeDropper control. I use it to ensure that only one TreeDropper is open at a time.

I also added several new methods to the treeview which you could move into your own base treeview class.

- `Fill()`: This method will fill the treeview from an array. The array can be a simple array, an array containing other arrays or an array of TreeItemInfo objects. The TreeItemInfo objects are simple objects to hold information about a treeitem like its image properties etc. You could create a table to store this information and then use it to fill the treeview.
- `Iterate()`: This method will run a code block against each item in the treeview. You can see how to use this in the sample form. The TreeDropper uses it to make sure that every treeitem is expanded before it opens up.
- `AddItem()`: This method simplifies adding new treeitems to the treeview for you. Simply call this method with a string parameter and the treeitem will be created with that text. The 2nd parameter is the parent under which you want to create the treeitem. It defaults to the treeview itself.

#### Limitations

Since the lists are objects and not simple strings you should probably not use this control for very large lists. A few hundred will be ok but more than that and you could run out of memory.

I didn’t spend much time testing the positioning logic with different fonts. I normally use `Arial 8 pt` for my forms and controls. You might find that the drop button doesn’t position itself correctly if you standardize on a different font. Improvements in this area would be greatly appreciated. Also this only works with `char` metrics. It would need more tweaking to handle others.

The `DropDownHeight` property doesn’t really do what I want. This should specify how many items will appear in the treeview regardless of the font or font sizes used. Currently it simply sets the treeview’s height to it’s value.

Finally I would definitely not call this a production control. It does the basics but there is a lot of extra functionality that could be added to it. Let me know of any ideas you have for this control and I’ll implement them for the next version.

### Conclusion

You can see that the container class gives us a whole new avenue for custom control creation. With the container we can create composite objects. You can create virtually any type of control that you can dream up. If you’re looking for inspiration for your own controls, have a look at the software sitting on your desktop now. Think about how other controls in different applications operate. How does the user interact with them? How do they interact with each other? When you see something you like, sit down, plan it out and then code away. The possibilities are endless!

Known Issues:

In Visual dBASE 7.01 there is a bug with the `releaseAllChildren()` method. If you add treeitems in the Designer and then try to release them in your code they will still be visible in the inspector.

Workaround: Simply use the treeview either as a static treeview or a dynamic one. Don’t mix them. In other words — if you know that the contents of your treeviews are going to change at some time, don’t add items to them in the designer — use the `Fill()` method instead.

To download the TreeDropper Control code, click here
(it’s a 34Kb zipped file)

Dan Howard has been an independent software developer for almost 10 years using Clipper for DOS and Visual dBASE for Windows. He can be contacted at: sproket_dBulletin_@total.net (take out “_dBulletin_”).