Populating TreeViews

You must write a script to add items to a TreeView. You cannot add items in the painter as with other list controls. Although you can populate all the levels of the TreeView at once, TreeView events allow you to populate only branches the user looks at, which saves unnecessary processing.

Typically, you populate the first level of the TreeView when the control is displayed. This code might be in a window's Open event, a user event triggered from the Open event, or the TreeView's Constructor event. Then a script for the control's ItemPopulate event would insert an item's children when the user chooses to expand it.

The ItemPopulate event is triggered when the user clicks on an item's plus button or double-clicks the item, but only if the item's Children property is TRUE. Therefore, when you insert an item that will have children, you must set its Children property to TRUE so that it can be populated with child items when the user expands it.

You are not restricted to adding items in the ItemPopulate event. For example, you might let the user insert items by dragging from a ListBox or filling in a text box.

Functions for inserting items

There are several functions for adding items to a TreeView control, as shown in the following table.

This function

Adds an item here

InsertItem

After a sibling item for the specified parent.

If no siblings exist, you must use one of the other insertion functions.

InsertItemFirst

First child of the parent item.

InsertItemLast

Last child of the parent item.

InsertItemSort

As a child of the parent item in alphabetic order, if possible.


For all the InsertItem functions, the SortType property can also affect the position of the added item.

There are two ways to supply information about the item you add, depending on the item properties that need to be set.

Method 1: specifying the label and picture index only

You can add an item by supplying the picture index and label. All the other properties of the item will have default values. You can set additional properties later as needed, using the item's handle.

Example

This example inserts a new item after the currently selected item on the same level as that item. First it gets the handles of the currently selected item and its parent, and then it inserts an item labeled Hindemith after the currently selected item. The item's picture index is 2:

long ll_tvi, ll_tvparent

ll_tvi = tv_list.FindItem(CurrentTreeItem!, 0)
ll_tvparent = tv_list.FindItem(ParentTreeItem!, &
   ll_tvi)
tv_list.InsertItem(ll_tvparent, ll_tvi, &
   "Hindemith", 2)

Method 2: setting item properties in a TreeViewItem structure

You can add items by supplying a TreeViewItem structure with properties set to specific values. The only required property is a label. Properties you might set are shown in the following table.

Property

Value

Label

The text that is displayed for the item.

PictureIndex

A value from the regular picture list.

SelectedPictureIndex

A value from the regular picture list, specifying a picture that is displayed only when the item is selected. If 0, no picture is displayed for the item when selected.

StatePictureIndex

A value from the State picture list. The picture is displayed to the left of the regular picture.

Children

Must be TRUE if you want double-clicking to trigger the ItemPopulate event. That event script can insert child items.

Data

An optional value of any datatype that you want to associate with the item. You might use the value to control sorting or to make a database query.


Example

This example sets all these properties in a TreeViewItem structure before adding the item to the TreeView control. The item is inserted as a child of the current item:

treeviewitem tvi
long h_item = 0, h_parent = 0

h_parent = tv_1.FindItem(CurrentTreeItem!, 0)
tvi.Label = "Choral"
tvi.PictureIndex = 1
tvi.SelectedPictureIndex = 2
tvi.Children = true
tvi.StatePictureIndex = 0
h_item = tv_1.InsertItemSort(h_parent, tvi)

For more information about inserting items into a TreeView control, see the section called “InsertItem” in PowerScript Reference.

Inserting items at the root level

The very first item you insert does not have any sibling for specifying a relative position, so you cannot use the InsertItem function -- you must use InsertItemFirst or InsertItemLast. For an item inserted at the root level, you specify 0 as its parent.

This sample code is in a user event triggered from the Open event of the window containing the TreeView. It assumes two instance variable arrays:

  • A string array called item_label that contains labels for all the items that will be inserted at the root level (here composer names)

  • An integer array that has values for the Data property (the century for each composer); the century value is for user-defined sorting:

    int ct
    long h_item = 0
    treeviewitem tvi
    
    FOR ct = 1 TO UpperBound(item_label)
          tvi.Label = item_label[ct]
          tvi.Data = item_data[ct]
          tvi.PictureIndex = 1
          tvi.SelectedPictureIndex = 2
          tvi.Children = TRUE
          tvi.StatePictureIndex = 0
          tvi.DropHighlighted = TRUE
          h_item = tv_1.InsertItemSort(0, tvi)
    NEXT

After inserting all the items, this code scrolls the TreeView back to the top and makes the first item current:

// Scroll back to top
h_item = tv_1.FindItem(RootTreeItem!, 0)
tv_1.SetFirstVisible(h_item)
tv_1.SelectItem(h_item)

Inserting items below the root level

The first time a user tries to expand an item to see its children, PowerBuilder triggers the ItemPopulate event if and only if the value of the item's Children property is TRUE. In the ItemPopulate event, you can add child items for the item being expanded.

Parent item's Children property

If the ItemPopulate event does not occur when you expect, make sure the Children property for the expanding item is TRUE. It should be set to TRUE for any item that will have children.

Inserting items not restricted to the ItemPopulate event

The ItemPopulate event helps you design an efficient program. It will not populate an item that the user never looks at. However, you do not have to wait until the user wants to view an item's children. You can add children in any script, just as you added items at the root level.

For example, you might fully populate a small TreeView when its window opens and use the ExpandAll function to display its items fully expanded.

Has an item been populated?

You can check an item's ExpandedOnce property to find out if the user has looked at the item's children. If the user is currently looking at an item's children, the Expanded property is also TRUE.

Example

This TreeView lists composers and their music organized into categories. The script for its ItemPopulate event checks whether the item being expanded is at level 1 (a composer) or level 2 (a category). Level 3 items are not expandable.

For a level 1 item, the script adds three standard categories. For a level 2 item, it adds pieces of music to the category being expanded, in this pattern:

Mozart
   Orchestral
      Symphony No. 33
      Overture to the Magic Flute
   Chamber
      Quintet in Eb for Horn and Strings
      Eine Kleine Nachtmusik
   Vocal
      Don Giovanni
      Idomeneo

This is the script for ItemPopulate:

TreeViewItem tvi_current, tvi_child, tvi_root
long hdl_root
Integer ct
string categ[]

// The current item is the parent for the new itemsThis.GetItem(handle, tvi_current)

IF tvi_current.Level = 1 THEN
   // Populate level 2 with some standard categories
   categ[1] = "Orchestral"
   categ[2] = "Chamber"
   categ[3] = "Vocal"

      tvi_child.StatePictureIndex = 0
   tvi_child.PictureIndex = 3
   tvi_child.SelectedPictureIndex = 4
   tvi_child.OverlayPictureIndex = 0
   tvi_child.Children = TRUE

   FOR ct = 1 to UpperBound(categ)
      tvi_child.Label = categ[ct]
      This.InsertItemLast(handle, tvi_child)
   NEXT
END IF

// Populate level 3 with music titles
IF tvi_current.Level = 2 THEN

   // Get parent of current item - it's the root of
   // this branch and is part of the key for choosing
   // the children

   hdl_root = This.FindItem(ParentTreeItem!, handle)
   This.GetItem(hdl_root, tvi_root) 

   FOR ct = 1 to 4
      // This statement constructs a label -
      // it is more realistic to look up data in a
      // table or database or accept user input   
      This.InsertItemLast(handle, &
      tvi_root.Label + " Music " &
      + tvi_current.Label + String(ct), 3)
   NEXT
END IF