4 Hierarchical Listbox

4.1 TixHList -- The Tix Hierarchical Listbox Widget

TixHList is the Tix Hierarchical Listbox Widget. You can use it to display any data that have a hierarchical structure. For example, the HList widget in figure 4-1 displays a Unix file system directory tree; the HList widget in figure 4-1 displays the corporate hierarchy of a hypothetical company. As shown in these two figures, the entries inside the TixHList widget are indented can be optionally connected by branch lines according to their positions in the hierarchy.

Directory Tree Display

A Corporate Hierarchy

(Figure 4-1) Examples of the TixHList Widget

4.1.1 Creating a Hierarchical List

A TixHList widget can be created by the command tixHList. However, most likely, you would want to create a TixHList with scrollbars attached. Therefore, usually you will use the tixScrolledHList command to create a scrolled hierarchical listbox (line 1 in program 4-2 ). The tixScrolledHList command is very similar to the TixScrolledListBox command we saw in section 2.3.1 . It creates a TixHList subwidget of the name hlist and attaches two scrollbars to it.

As shown in the first five lines in program 4-2 , we create a scrolled TixHList widget, using the -options switch (see section 1.3.5 ) to set several options for the hlist subwidget (we'll talk about these options shortly). Then, we can access the HList subwidget widget using the subwidget hlist method (line 7 in program 4-2 ).

tixScrolledHList .sh -options {
    hlist.itemType text
    hlist.drawBranch false
    hlist.indent     8
pack .sh -expand yes -fill both
set hlist [.sh subwidget hlist]

$hlist add foo -text "foo" $hlist add foo.bar -text "foo's 1st son" $hlist add foo.bor -text "foo's 2nd son" $hlist add foo.bar.bao -text "foo's 1st son's 1st son" $hlist add foo.bar.kao -text "foo's 1st son's 2nd son" $hlist add dor -text "dor, who has no son"

(Figure 4-2) Creating Entries in a HList Widget

(Figure 4-3) Output of Program 4-2

4.1.2 Creating Entries in a HList Widget

Each entry in an HList widget has a unique name, called its entry-path, which determines each entry's position in the HList widget. The entry-paths of the HList entries are very similar to the pathnames of Unix files. Each entry-path is a list of string names separated by a separator character. By default, the separator character is the period character ( .), but it can be configured using the -separator option of the HList widget.

In program 4-3 , we add several new entries foo, foo.bar, foo.bor, foo.bar.bao, .. etc, into the HList widget using the add method. The relationship between the entries is signified by their names, in a way similar to how Unix denotes directories and subdirectories. For example, foo is the parent of foo.bar and foo.bor; foo.bar is the parent of foo.bar.bao, and so on. As far as the terminology goes, we also say that foo.bar a child of foo; foo is an ancestor of foo.bar.bao and foo.bar.bao is a descendant of foo.

The output of program 4-2 is shown in figure 4-3 . As we can see, the entries are displayed under their parents with the amount of indentation control by the -indent option of the HList widget: foo.bar.bao and foo.bar.kao are display under foo.bar, which is in turn displayed under foo.

Entries with no parents, for example, foo and dor in program 4-2 , are called top-level entries. Top-level entries are usually entries with no immediate superiors in a hierarchical. For example, the owner of a company, the principle of a school or the root directory of a Unix file system. Toplevel entries are displayed with no indentation.

As evident from program 4-2 , all entries who entry-path does not contain a separator character are top-level entries. The only exception is the separator character itself is also a toplevel entry. This makes it easy to display Unix file and directory names inside the HList widget, as shown in program 4-4 .

set folder [tix getimage folder]
tixScrolledHList .sh -options {
    hlist.separator     /
    hlist.itemType      imagetext
    hlist.drawBranch    true
    hlist.indent        14
    hlist.wideSelection false
pack .sh -expand yes -fill both
set hlist [.sh subwidget hlist]

foreach directory {/ /usr /usr/bin /usr/local /etc /etc/rc.d} { $hlist add $directory -image $folder -text $directory }

(Figure 4-4) Displaying Directories in a HList Widget

(Figure 4-5) Output of Program 4-4

Each entry is associated with a display item (see section 3.2 about display items). We can use the -itemtype option of the HList widget to specify the default type of display item to be created by the the add method, as shown in program 4-2 and 4-4 . Alternatively, we can also specify the type of display item using the -itemtype option for the add method.

4.1.3 Controlling the Layout of the Entries

There are two options to control the layout of the entries: the -showbranch option specifies whether branch lines should be drawn between parent entries and their children. The -indent option controls the amount of relative indentation between parent and child entries. Notice the -drawbranch option is turned on in figure 4-5 but turned off in figure 4-3 . Usually, you need to set a bigger indentation when the branches are shown --- we used an indentation of 14 pixels in 4-5 compared to 8 pixels in 4-3 .

4.1.4 Handling the Selection and User Event

The handling of the selection and user events for the HList widget is very similar to the TList widget (see section 3.3.5 ), except that for the HList widget all the operations are based on entry-paths, not list indices. The methods info selection, selection set and selection clear can be used to query, set or clear the selection; the option -selectmode controls how many entries can be selected at a time; the options -browsecmd and -command can be used to specify a command to be called to handle user events.

There is one more option worth mentioning: the -wideselection option. When set to true, the selection highlight will be drawn across the whole HList widget (see figure 4-3 ). When set to false, selection highlight will be drawn as wide as the selected entry (see figure 4-5 ). Normally, you would set -wideselection to false when you use imagetext items inside (as we did in program 4-4 ).

4.2 Creating Collapsible Tree Structures with TixTree

The TixTree widget is based on the TixScrolledHList widget; you can use it to create a collapsible hierarchical structure so that the user can conveniently navigate through a large number of list entries. As shown in figure 4-7 , the TixTree puts the little `` +'' and `` -'' icons next to the branches of an HList entry that has descendants. These two icons are knows as the open and close icons, respectively. When the user presses the open icon next to an entry, its immediate children of an entry will be displayed. Conversely, when the user presses the close icon, the entry's children will become hidden.

Program 4-6 shows how to create a collapsible tree. We first create a TixTree widget. Then we add the entries in your hierarchical structure into its hlist subwidget using the add method of this subwidget. When we are finished with adding the entries, we just call the autosetmode method of the TixTree widget, which will automatically adds the open and close icons next to the entries who have children.

set folder [tix getimage folder]
tixTree .tree -command Command -options {
    hlist.separator  /
    hlist.itemType   imagetext
    hlist.drawBranch true
    hlist.indent     18
pack .tree -expand yes -fill both
set hlist [.tree subwidget hlist]

foreach directory {/ /usr /usr/bin /usr/local /etc /etc/rc.d} { $hlist add $directory -image $folder -text $directory } .tree autosetmode

proc Command {entry} { puts "you have selected $entry" }

(Figure 4-6) Creating a Collapsible Hierarchy

(Figure 4-7) Output of Program 4-6

Note that in program 4-6 we use the -command option of the TixTree widget, not the -command option of its hlist subwidget. This is because the TixTree actually used the -command option of its hlist subwidget to process some low-level events. In general, if both a mega-widget and its subwidget have the options of the same name, you would always use the option that belongs to the mega-widget.