Create rich user interfaces in Perl
Perl is one of the most popular languages out there, and is used for everything from mission-critical projects to Web applications to "glue." It is not, however, often used for GUI programming and prototyping. Philipp K. Janert thinks it should be, and you probably will too -- after this look at some of the more complex widgets available for Perl/Tk.
In contrast to the widespread use of the Perl language, Perl's GUI toolset, Perl/Tk, is much less popular. This is strange, because it is arguably one of the easiest GUI toolkits to program (at least for UNIX platforms), and therefore suggests itself for user interface prototyping or for quickly providing a user-friendly wrapper around cryptic command-line tools.
One reason for this relative indifference toward Perl/Tk appears to be the perception that it is not very powerful and does not lend itself to sophisticated applications. However, a number of widgets that provide more complex functionality are available as user contributions on CPAN. In this article, I will take a look at some of them and show how they can be used to create a richer user experience. I will also point out some more generally useful techniques for programming with Perl/Tk.
(The other problem with Perl/Tk, of course is, that its widgets look ugly and are not "theme-able." Unfortunately, I cannot do anything about that.)
Prerequisites and availability
A good knowledge of Perl and at least rudimentary experience with Perl/Tk as well as general GUI programming concepts -- events, widgets, callbacks, geometry managers -- are assumed throughout. You can find introductory resources on Perl/Tk in the Resources section of this article.
You can freely download all the widgets discussed in this article from CPAN, the Comprehensive Perl Archive Network. Most have many more options than can be explained here: the perldoc for each widget and -- in some cases -- the source code, provide the ultimate and complete reference.
Tabbed frames: Tk::NoteBook
A common GUI widget, the Tab helps to group a large number of options into smaller subsets and so add structure to, for instance, complicated dialog boxes.
A widget with Tab-like appearance and semantics for Perl/Tk is
Tk::NoteBook. An example, using three tabs,
is shown in Figure 1. Note that the third tab is disabled.
This example was produced by the following code:Listing 1: Using the NoteBook widget
Specifying arguments to callbacks
or as a direct invocation of the callback from within an anonymous subroutine:
The difference between the two methods has to do with variable scoping; more precisely, with the exact time the parameters are evaluated.
In the first case, the parameters are evaluated at the time
that the constructor containing the
In contrast, the contents of the anonymous subroutine used in
the second case are not evaluated until this subroutine is
actually invoked. In other words, the callback sees the
values of the parameters at the time the callback is
executed. This is important in the
Finally, because the body of the
As in any Perl/Tk application, we first specify the modules
we are going to use and then create a
MainWindow. Note that
Tk::NoteBook, as well as the other
contributed widgets on CPAN, are not part of the standard Tk
distribution, and therefore need to be specified explicitly.
We create a
NoteBook widget as child to the
MainWindow and then add three tabs. The
argument to the
add() function is a symbolic
name, by which the generated page can be referred to in the
notebook: we will make use of it below.
I should make two comments on geometry management when using the
NoteBook widget. First, although the
tabs are widgets themselves, they do not need to be
packed. Their geometry management is
handled by the enclosing
NoteBook. Second, if the parent window of
NoteBook widget is resizable, it
is important to specify both the
-fill and the
-expand attributes when
NoteBook. The latter will make sure that
NoteBook's allocation rectangle
will always expand to fill the available space, while the former
ensures that the actual
widget will expand to fill its allocation rectangle.
The tabs accept a variety of attributes. Here we demonstrate
-state. The first two can be used to
register callbacks, which will be invoked when the tab is first
created and whenever it is raised, respectively; while the last
one can take on the values
disabled. We also use the
-raisecmd callback on the second tab to
switch the third tab from its disabled to its active state once
the second tab has been raised for the first time. We do this
pageconfigure() function on
passing the symbolic name of the referenced tab as the first
Versatile graphical display: Tk::ProgressBar
Tk::ProgressBar is a widget that
displays a graphical representation of a scalar value. Progress
bars are commonly used to provide feedback to the user when
downloading large files or
performing similar long-running tasks. The
corresponding widget in Perl/Tk offers some special features
that can make it attractive for other uses as well.
This example contains two
widgets, coupled to a standard
Scale. Moving the slider changes the length
of the displayed color bar by invoking the callback named
fct, which calls the
value function on the
ProgressBars to set the new length. A value
100 corresponds to the full length
of the visible color bar. This value can be changed, as can be
the value corresponding to a zero-length color bar, using the
-from attributes, respectively.
Listing 2 demonstrates some of the ways the appearance
of the color bar can be customized. The bottom
ProgressBar is broken into ten blocks, which
are separated by from one another by one-pixel gaps. These are the
default values; they can be set by explicitly specifying values for
gap attributes. Some experimentation with
-borderwidth attributes is
-colors attribute accepts a
reference to an array containing pairs of positions and colors.
(Note that the positions must be sorted in ascending order!) The last
specified color will be used for the color bar, until the next
position is reached, at which point the color changes. So,
@colors = ( 0, "red", 50, "green" );
yields a color bar that is red on the left
side and green on the other. Here, I provide 100 distinct
values, spanning the colors of the rainbow for the top
ProgressBar. Note that the top
ProgressBar changes its length when the
window is resized.
We specify the callback for the
widget not in its constructor, but later, using the
configure function. The reason is that we
need references to both
as arguments to the callback, and at the time the
Scale constructor is invoked, they are not
all defined yet. Changing the order in which the widget
constructors are called is not possible, since this would change
the order in which the widgets are packed.
This code also demonstrates one way to specify arguments to a callback: as an anonymous list, with a reference to the callback invoked as the first element, followed by the required parameters. If a callback does not require arguments, we do not need to create the anonymous list, since Perl treats scalar values, evaluated in list context, as single-element arrays. (For more information on lists in Perl, see Learning Perl, 2nd edition, listed in Resources.) We will encounter a different method for sending parameters to a callback below; check the Sidebar for a discussion of the differences between the two methods.
The freedom to choose arbitrary colors for any segment of the
color bar makes the
interesting for uses as a general display widget: for instance, the
be used to indicate whether the displayed variable is within the
"normal" parameter range or not. Unfortunately, the widget does
not support an
ProgressBars are always oriented