2 Container Widgets

In addition to providing some nice-looking interface elements, Tix offers some useful ways to organize the elements that you create. It does this by providing container widgets, which are widgets designed to contain whatever you want to put into them.

Different container widgets have different policies as to how they arrange the widgets inside them. In this chapter, we'll talk about TixNoteBook, which arranges its subwidgets using a notebook metaphor, TixPanedWindow, which arranges its subwidgets in non-overlapping horizontal or vertical panes, and a family of ``Scrolled Widgets'', which attach scrollbars to their subwidgets.

2.1 TixNoteBook

When your need to put a lot of information into your interface, you may find out that your window has to grow intolerably big in order to hold all the information. Having a window that's 10000 pixels wide and 5000 pixels high doesn't seem to be the perfect solution. Of course, you can ``chop up'' your big window into a set of smaller dialog boxes, but the user will most likely find it impossible to manage 20 different dialog boxes on their desktop.

The TixNoteBook (fig 2-1 ) widget comes into rescue. It allows you to pack a large interface into manageable ``pages'' using a notebook metaphor: it contains multiple pages with anything you want on them, displays one at a time, and attaches a tab to each page so the user can bring it forward with a single click on the tab.

(Figure 2-1) The TixNoteBook Widget

2.1.1 Adding Pages to a TixNoteBook

The example program in figure 2-2 creates the TixNoteBook widget shown in figure 2-1 . In the first three lines, we create the notebook widget and two pages inside it. While we create the pages, we also set the labels on the tabs associated with each page and use the -underline option to indicate the keyboard accelerator for each page.

Each time we create a page in the notebook using the add method, a frame subwidget is created for us automatically. This frame subwidget has the same name as the page (the first parameter passed to the add method). We can use the subwidget method to find out the pathname of this frame subwidget and pack everything we want to display on the page into this frame widget. Lines 4-10 of program 2-2 shows how to create the widgets inside the ``Hard Disk'' page. Creating the widgets inside the ``Network'' page will be similar.

tixNoteBook .n
.n add hd  -label "Hard Disk" -underline 0
.n add net -label "Network"   -underline 0

set frame [.n subwidget hd] tixControl $frame.access -label "Access Time:" tixControl $frame.write -label "Write Throughput:" tixControl $frame.read -label "Read Througput:" tixControl $frame.capacity -label "Capacity:" pack $frame.access $frame.write $frame.read $frame.capacity
-side top -fill x

(Figure 2-2) Using The TixNoteBook Widget

2.1.2 Keyboard Accelerators

Note that in line 2-3 of program 2-2 , we have indicated the keyboard accelerators for the two pages using the -underline option. The value of this option is the position of the character to be underlined in the string, where zero represents the first character. When the user presses <Alt-N> or <Meta-N> the ``Network'' page will be activated; on the other hand, if he presses <Alt-H> or <Meta-H> the ``Hard Disk'' page will be activated. The TixNoteBook widget will automatically create the keyboard bindings for these accelerators for us, in a way similar to what the menu widget does, so there is no need to set the keyboard bindings ourself.

2.1.3 Delaying the Creation of New Pages

If your notebook contains many complicated pages, it may take quite a while to create all widgets inside these pages and your program will probably freezes for a few seconds when it pops up the notebook for the first time. To avoid embarrassing moments like this, we can use the ``delayed page creation'' feature of the TixNoteBook widget.

When we create a page using the add method, we can specify the optional parameter -createcmd so that we only need to create the page when the user wants to see it. This is illustrated in program 2-3 :

tixNoteBook .n
.n add hd  -label "Hard Disk" -underline 0 -createcmd CreateHd
.n add net -label "Network"   -underline 0 -createCmd CreateNet

proc CreateHd {frame} { tixControl $frame.access -label "Access Time:" tixControl $frame.write -label "Write Throughput:" tixControl $frame.read -label "Read Througput:" tixControl $frame.capacity -label "Capacity:" pack $frame.access $frame.write $frame.read $frame.capacity
-side top -fill x }

proc CreateNet {frame} { ... }

(Figure 2-3) Delayed Page Creation

In line 2 of program 2-3 , we use the -createcmd option to specify that the procedure CreateHd should be called when the ``Hard Disk'' page needs to be created. CreateHd takes one argument, the frame subwidget of the page. As we can see, program program 2-3 is not very different than program 2-2 , except now we can issue less commands during the set-up of the NoteBook widget and the interface can be started up more quickly.

2.1.4 Changing Page Tabs and Deleting Pages

To change the information in the tabs of the pages, we can use the pageconfigure method. For example, the following command:

.nb pageconfigure hd -label "Fixed Disk"
changes the label from ``Hard Disk'' to ``Fixed Disk''. To delete a page, we can use the delete method.

You should avoid using the pageconfigure and delete. Your users will just feel annoyed if the interface changes all the time and notebook pages appear and disappear every now and then.

2.2 PanedWindow

The TixPanedWindow widget arranges arranges its subwidgets in non-overlapping panes. As we can see in figure 2-4 , the PanedWindow widget puts a resize handle between the panes for the user to manipulate the sizes of the panes interactively. The panes can be arranged either vertically (figure 2-4 ) or horizontally (2-4 ).

Each individual pane may have upper and lower limits of its size. The user changes the sizes of the panes by dragging the resize handle between two panes.

Vertical Panes

Horizontal Panes

(Figure 2-4) The TixPane Widget

2.2.1 Adding Panes Inside a TixPanedWindow Widget

You can create a TixPanedWindow widget using the tixPanedWindow command. After that, you can add panes into this widget using the add method (see program 2-5 ).

When you use the add method, there are several optional parameters which you can use to control the size of each of the pane. The -min parameter controls the minimum size of the pane and the -max parameter controls its maximum size. These two parameters controls how much the user can expand or shrink a pane. If neither is specified, then the pane can be expanded or shrunk without restrictions.

In addition, the -size parameter specifies the initial size of the pane. If it is not specified, then the initial size of the pane will be its natural size.

In program 2-5 , we set the initial size of pane1 to 100 pixels using the -size parameter. We don't set the -size parameter for pane2 so it will appear in its natural size. However, we use the -max option for pane2 so that the user can never expand the size of pane2 to more than 300 pixels.

tixPanedWindow .p
.p add pane1 -size 100
.p add pane2 -max 300

set p1 [.p subwidget pane1] button $p1.b1 -text Button1 button $p1.b2 -text Button2 pack $p1.b1 $p1.b2 -side left -expand yes

set p2 [.p subwidget pane2] button $p2.b -text "Another Button" pack $p2.b -side left -expand yes -fill both

pack .p -expand yes -fill both

(Figure 2-5) Adding Panes into a TixPanedWindow Widget

2.2.2 Putting Widgets Inside the Panes

Each pane we have created using the add method is essentially a frame widget. After we have created the panes, we can put widgets inside them. As shown inside program 2-5 , we can use the subwidget method to find out the name of the pane subwidgets. Then we can just create new widgets as their children and pack these new widgets inside the panes. The output of program 2-5 is shown in figure 2-6

(Figure 2-6) Output of Program 2-5

2.2.3 Setting the Order of the Panes

Usually, when you create a new pane, it is always added to the bottom or right of the list of panes. If you want to control the order in which the panes appear inside the TixPanedWindow widget, you can use the two optional parameters, -before and -after, for the add method. For example, the call:

.p add pane2 -after pane1
will place the new pane immediately after pane1. The call:
.p add pane2 -before pane1
will place the new pane immediately in front of pane1.

2.2.4 Changing the Sizes of the Panes

If you want to change the sizes of the existing panes or change their maximum/minimum size constraints, you can use the paneconfigure method. For example, the following code changes the size of pane2 to 100 pixels and adjusts its minimum size constraint to no less than 10 pixels:

.p paneconfigure pane2 -size 100 -min 10
Notice that after you call the paneconfigure method, the PanedWindow may jitter and that may annoy the user. Therefore, use this method only when it is necessary.

2.3 The Family of Scrolled Widgets

With plain Tcl/Tk, the widgets do not automatically come with scrollbars. If you want to use scrollbars with the text, canvas or listbox widgets, you will need to create scrollbars separately and attach them to the widgets. This can be a lot of hassle because you would almost always need scrollbars for these widgets. Sometimes you will wonder why you need to write the same boring code again and again just to get the scrollbars to working.

The Tix scrolled widgets are here to make your life easier. With a single command such as tixScrolledListBox or tixScrolledText, you can create a listbox or text widget that comes automatically with scrollbars attached.

Another advantage of the Tix scrolled widgets is that you can specify their scrolling policy so that the scrollbars appear only when they are needed. This feature is especially useful if you are displaying a lot of widgets and running out of screen real estate.

2.3.1 The Scrolled Listbox Widget

You can create a scrolled listbox widget using the tixScrolledListBox command. Notice that the widget created by the tixScrolledListBox command is not itself a listbox widget. Rather, it is a frame widget which contains two scrollbar subwidgets: one is called hsb (the horizontal scrollbar) and the other is called vsb (the vertical scrollbar). Similarly, the listbox being scrolled is also a subwidget which is appropriately called listbox. Therefore, if we need to put things into the listbox (as we always do!), we can use the subwidget method. As shown in program 2-7 , we first find the pathname of the listbox subwidget by calling `` .sl subwidget listbox''. Then, we insert some items into the listbox subwidget.

tixScrolledListBox .sl -scrollbar auto
set listbox [.sl subwidget listbox]

for {set x 0} {$x < 6} {incr x} { $listbox insert end "This is item $x" }

pack .sl -side left -expand yes -fill both

(Figure 2-7) Scrolled Listbox Widget

Scrollbars not displayed

Scrollbars displayed only when needed

(Figure 2-8) Scrolled ListBox with Automatic Scrollbars

Also, as seen in the first line of program 2-7 , we use the -scrollbar option to control the scrolling policy of the TixScrolledListBox widget. Usually, we'll set it to `` auto'': the scrollbars are displayed only if they are needed. Other possible values are `` both'': the two scrollbars are always displayed; `` x'': the horizontal scrollbar is always displayed, while the vertical scrollbar is always hidden; `` y'': the opposite of `` x''; `` none'': the two scrollbars are always hidden. The result of program 2-7 is shown in figure 2-8 .

2.3.2 Other Scrolled Widgets

The TixScrolledText widget is very similar to the TixScrolledListBox widget, except it scrolls a text subwidget, which is called text. One problem with the TixScrolledText widget, though, is its -scrollbar option doesn't work in the auto mode. This is due to a bug in Tk which doesn't report the width of the text subwidget correctly. Until this bug is fixed in TK, the auto mode will behave the same way as the both mode for the TixScrolledText widget.

Another scrolled-widget is TixScrolledWindow. Sometimes you have a large number of widgets that can't possibly be shown in the screen all at once and your application doesn't allow you to divide the widgets into several pages of a TixNoteBook. In this case you can use TixScrolledWindow. It contains a frame subwidget called window. You can just create as many widgets as you need as children of the window subwidget. An example is shown in program 2-9 , which uses the TixScrolledWindow widget to implement a ``cheap'' spreadsheet application. The boxes of the spreadsheet are just entry widgets and they are packed inside the window subwidget. The user will be able to scroll to different parts of the spreadsheet if it is too large to fit in one screen.

tixScrolledWindow .sw -scrollbar auto
set f [.sw subwidget window]

for {set x 0} {$x < 10} {incr x} { frame $f.f$x pack $f.f$x -side top -expand yes -fill both for {set y 0} {$y < 10} {incr y} { entry $f.f$x.e$y -width 10 pack $f.f$x.e$y -side left -fill x } }

pack .sw -side left -expand yes -fill both

(Figure 2-9) Cheap Spreadsheet Application with TixScrolledWindow

There are two more scrolled-widgets in the Tix library: TixScrolledTList scrolls a TixTList widget and TixScrolledHList scrolls a TixHList widget. The subwidgets that they scroll are called tlist and hlist, respectively. The use of the TList and HList widgets will be described in the next chapters.