The HList widget is the basis for the two other Tix widgets we are examining: Tree and DirTree. The HList widget is a hierarchical list that uses the idea of paths to create the hierarchy it displays. You could also display a flat hierarchy and use HList as a type of Listbox that can have columns and column headings. Tree and DirTree are specialized versions of HList. DirTree is used to display a directory structure from a given starting point. All three of the widgets use display items.
The simplest way to use the HList widget is similar to a Listbox or TList. Create it and then add items to it:
use Tk; use Tk::HList; my $mw = MainWindow->new(-title => 'HList'); my $hlist = $mw->HList->pack; foreach (qw/one two three four five/) { $hlist->add($_, -text => $_); } MainLoop;
Looking at this example, it isn't obvious at all that you can have display items or styles with an HList. The only non-self-explanatory item (given that you understand Listbox) is the first argument to the add method, which is a path. Since this example doesn't take advantage of any of the special hierarchical features of the HList, we're not going to bother showing a screenshot yet.
Just like a Listbox, the HList contains a list of entries. Each time you call the add method, you create another entry in the list. Each entry can contain one or more display items. If you want more than one display item with each entry, use the -columns option. Unlike TList, which automatically manages multiple columns based on its orientation, you need to manage columns manually for the HList. A later example will make this clear.
You need to give each entry in the HList a path (the first argument to the add method). The path for each entry must be unique; if it isn't, an immediate error will result.
A hierarchy results when you use the separator character in a path. Here is a simple hierarchy of colors using the separator character of .:
orange orange.red orange.yellow green green.blue green.yellow purple purple.red purple.blue
Changing our previous code to use these paths instead of one two three four five, we get the screen shown in Figure 18-5.
The branches drawn on the left indicate which entries are below the others. orange is the parent of both orange.red and orange.yellow. If we tried to use a path of orange.green.blue, the call to add would fail, because we haven't set up the intermediate path of orange.green yet.
Another way to think of paths is like directory paths. If you don't have the parent directory of /home created, you can't create /home/nwalsh.
If you don't like the branch lines drawn between each parent and its children, you can always turn them off using the -drawbranch option with a value of 0. An empty space will be left in front of each child entry instead of the drawn branch. The amount of space or branch shown in front of each child entry is determined by the -indent option.
One advantage HList offers over Listbox is that it simplifies assigning a callback to be invoked when one of the entries in the list is double-clicked or when the Return key is pressed while one of the entries is active. To utilize this functionality, use the -command option to the HList constructor.
The information displayed in Chapter 18, " A Tk Interface Extension Tour" is static, meaning you can't manipulate the hierarchy (opening and closing various branches) without doing a lot of coding first. The most common feature people want in a hierarchical list is the ability to expand and collapse subtrees by clicking an indicator in the parent item. We don't see the indicators in Chapter 18, " A Tk Interface Extension Tour" because we haven't created any for the items in the list. The indicator can be any display item, and it is displayed to the left of the entry, on top of the branch line. Typical indicators are plus and minus signs, or open and closed folders.
The easiest way to create and use indicators with an HList is to use the Tree widget, because it's already coded internally in the widget. For example, if you don't mind thumbing ahead a few pages, you'll see that we used the Tree widget to create the screenshot shown in Figure 18-7. The indicators in the figure are the default Tree indicators of plus and minus images, displayed only on the entries that have children.
The work involved in setting up your own indicators with HList goes like this: create your HList with the -indicator option set to 1 and create an -indicatorcmd callback. For each entry in the list you want shown with an indicator, call indicatorCreate. Later, to change the appearance of the indicator inside the callback assigned to -indicatorcmd, you can use indicatorConfigure. Here's a version of our example that creates and uses indicators on every entry in the list:
use Tk; use Tk::HList; sub icmd { my ($path, $state) = @_; print "path is '$path', state is '$state'\n"; } my $mw = MainWindow->new; my $list = $mw->HList(-indicator => 1, -indicatorcmd => \&icmd) ->pack(qw/-fill both -expand yes/); foreach (qw/orange orange.red orange.yellow green green.blue green.yellow purple purple.red purple.blue/) { $list->add($_, -text => $_); $list->indicator('create', $_, -itemtype => 'image', -image => $mw->Getimage('plus')); } MainLoop;
The best example of using indicators is in the source code for the Tree widget, included with every distribution of the Tk module.
So what else might you want to use a HList widget for? You can create a list that has columns and column headings. Let's change our initial code example to do just that:
my $hlist = $mw->HList(-columns => 4, -header => 1) ->pack(-expand => 1, -fill => 'both'); $hlist->headerCreate(0, -text => "Color Name"); $hlist->headerCreate(1, -text => "Red value"); $hlist->headerCreate(2, -text => "Green value"); $hlist->headerCreate(3, -text => "Blue value"); foreach (qw/orange red green blue purple/) { my ($r, $g, $b) = $mw->rgb($_); $hlist->add($_); $hlist->itemCreate($_, 0, -text => $_); $hlist->itemCreate($_, 1, -text => sprintf "%#x", $r); $hlist->itemCreate($_, 2, -text => sprintf "%#x", $g); $hlist->itemCreate($_, 3, -text => sprintf "%#x", $b); }
We specified two options when creating the HList, -columns and -header. We want to display four columns, and we'd like to be able to see the headings we give them as well. After creating the HList, we create the headings, one for each column. The columns are numbered starting at zero. We don't create a hierarchy in this example, so none of our path entries contain separator characters. (You can still create a hierarchy when using columns. The branch lines are drawn to the left of everything at that point.) We want to display the color name in the first column and the RGB values in the subsequent columns.
We still have to call add to create the entry with a path. After that, we can use the itemXXX methods to put a text display item in each column. We call itemCreate with the path to use, the column number, and then the text to display. As you can see in Figure 18-6, a selection selects the whole entry, not just an individual column. There is no way to select a single column entry in an HList.
Since we're using colors, we can change the background color of the HList when double-clicking on an entry. We'll add the -command option and a subroutine to our code:
my $hlist = $mw->HList(-columns => 4, -header => 1, -command => \&change_background) ->pack(-expand => 1, -fill => 'both'); . . . sub change_background { my ($path) = @_; print "color = $path\n"; $hlist->configure(-background => $path); }
Since we are using the color name as the path of the entry, we don't need to do any additional work, because we are given the pathname as the first argument to the callback. You could also get the text entered at one of the columns by calling itemCget:
$col0 = $hlist->itemCget($path, 0, -text); # Text at column 0
If the text being displayed isn't what you want to retrieve, you can always store a piece of data using the -data option with the entry itself:
$hlist->add($_, -data => 'something else..'); ... $data = $hlist->infoData($path);
So now that we've seen some HList examples and how to use a few of the options and methods, here's a list of all the options and methods with short descriptions. HList uses these standard options (which behave as expected): -command, -foreground, -height, -selectbackground, -selectborderwidth, -selectforeground, -selectmode, and -width. The following options are specific to the HList widget:
If the HList entry doesn't have an indicator created by using the indicator method, this callback will never be invoked for that entry.
The following methods can be called on an HList:
You can also specify any options that are valid for the item type this entry uses.
The Tree widget is based on HList, but it has a lot more built-in functionality. We mentioned earlier that if you want to be able to open and close parts of the heirarchy, you might as well use the Tree widget rather than recoding everything yourself. Here's our color hierarchy example again, but using Tree:
use Tk; use Tk::Tree; my $mw = MainWindow->new(-title => 'Tree'); my $tree = $mw->Tree->pack(-fill => 'both', -expand => 1); foreach (qw/orange orange.red orange.yellow green green.blue green.yellow purple purple.red purple.blue/) { $tree->add($_, -text => $_); } $tree->autosetmode( ); MainLoop;
Figure 18-7 illustrates this.
The only changes in our code are that we replaced HList with Tree and we made an additional call to autosetmode. This call is necessary for the widget to set up all its internal variables so it knows which branches are open. If you forget to make this call, the plus and minus indicators won't appear. Other than those small changes, everything else about a Tree is the same as an HList. All the HList methods and options apply to Trees as well. Here are a few additional options and methods:
my $closecmd = [ sub { print "args=@_!\n"; my $tree = shift; my $closecmd_orig = $tree->{'closecmd_orig'}; $tree->$closecmd_orig(@_); }, $tree, ]; $tree->configure(-closecmd => $closecmd);
The following methods are available for the Tree widget:
The DirTree widget extends the Tree widget (which extends the HList widget) and inherits all the methods and options from both Tree and HList. A DirTree is designed to show directories from a given starting point (similar to the lefthand side of an MS Windows Explorer window). Here's a simple example showing DirTree reading the directories off a CD-ROM drive:
use Tk; use Tk::DirTree; my $mw = MainWindow->new(-title => 'Tree'); $mw->DirTree(-directory => "D:/")->pack(-fill => 'both', -expand => 1); MainLoop;
Figure 18-8 shows the outcome.
The following options can be used with DirTree:
There is only one method specific to a DirTree widget. You can call chdir at any time to add to the directory listing:
$dirtree->chdir($directoryname);
If you take a peek at the actual code in DirTree.pm, you'll see that setting the -directory option calls chdir as well. When you call chdir, the widget doesn't remove any of the previous directory entries. If you want to remove other directories, you must use the delete method first to avoid confusion.
Copyright © 2002 O'Reilly & Associates. All rights reserved.