Enough history. The remainder of this chapter is about the basics of using Perl/Tk, including how to create simple widgets and display them, a quick introduction to event-based programming, and an obligatory "Hello World" example. Before we continue, let's make sure you have everything installed properly.
Since the Tk extension to Perl doesn't come with the standard Perl distribution, the first thing you should do is make sure you have a working Perl/Tk distribution.
Whether you're running Unix or Win32, the perl program should be in your path. Type the following at a command prompt to make the determination:
% perl -v
If you receive a "command not found" error message, see Appendix A, "Installing Perl/Tk" and install Perl. If perl is found, you'll see output similar to this:
This is perl, v5.6.0 built for i686-linux Copyright 1987-2000, Larry Wall Perl may be copied only under the terms of either the Artistic License or the GNU General Public License, which may be found in the Perl 5.0 source kit. Complete documentation for Perl, including FAQ lists, should be found on this system using `man perl' or `perldoc perl'. If you have access to the Internet, point your browser at http://www.perl.com/, the Perl Home Page.
In particular, note the version number in the first line; anything earlier than 5.6.0 may not produce the results depicted in this book. Perl 5.005_03 may work, but nothing earlier will, guaranteed.
Now determine if the Tk module is available by using this command:
% perl -e "use Tk"
If you don't get the following error, you're ready to go:
Can't locate Tk.pm in @INC (@INC contains: C:\PERL\lib\site ...
Once again, to install Tk refer to Appendix A, "Installing Perl/Tk".
Assuming that Perl/Tk is up and running, you can determine its version with this command:
% perl -MTk -e 'print "$Tk::VERSION\n"' 800.022
Ideally, you want Version 800.022 or higher.
The best way to verify that all is well is to run the widget demonstration program. widget should already be in your path, so just invoke the command by typing widget at a command prompt. This program demonstrates most of the Perl/Tk widget set and lets you examine the Perl/Tk code, modify it, and rerun individual demonstrations. Clicking on About shows you the installed Perl and Tk versions.
Perl/Tk Versions
This book is based on the stable releases of Perl 5.6.0 and Tk 800.022. At the time of this writing, Perl 5.6.1 has been released, yet Tk continues to work as before, and all examples are known to work. Down the pipe is a major release of Tk, based on Tcl/Tk Version 8.3. Nick has seeded Tk 803.023 to a few Perl/Tk hackers, but the code is still far from prime-time ready.
When Perl/Tk 803.xxx becomes available, expect it to be thread-safe and Unicode (UTF-8) aware, but beware that if your application uses high-bit ISO-8859-1 characters, it will most likely break.
All widgets in Perl/Tk programs are created in the same basic fashion, with a few exceptions. Each widget must have a parent widget to watch over it as it is created and keep track of it while it exists in the application. When you create an application, you'll have a central window that will contain other widgets. Usually that window will be the parent of all the widgets inside it and of any other windows you create in your application. You are creating an order to the widgets so that the communication between child and parent widgets can happen automatically without any intervention from you once you set it all up.
Assuming that the $parent widget already exists, the generic usage when you create widget Widgettype is as follows:
$child = $parent->Widgettype( [ -option => value, . . . ] );
Note that the variables that store the widgets are scalars. (Actually, they are references to widget objects, but you don't need to know that right now.) If you aren't familiar with object-oriented syntax in Perl, using the -> between $parent and Widgettype invokes the method Widgettype from the $parent object. It makes the $parent related to the child $child. As you might guess, the $parent becomes the parent of the widget being created. A parent can have many children, but a child can have only one parent.
When you invoke the Widgettype method, you usually specify configuration parameters to set up the widget and the interactions within the application. The configuration parameters will occur in pairs: an option (such as -text, -state, or -variable) and its associated value. Each option starts with a dash, but that's only by convention; the options are just strings used to indicate how to interpret their associated values.
Usually, it is not necessary to put quotation marks around option names because Perl is smart enough to recognize them as strings. However, if you are using the -w switch, Perl may complain about an option that it thinks is not text. You can stick quotes around all your options all the time to avoid this, but it shouldn't be necessary. The option names are all lowercase, except in a few rare cases that we'll note as we cover them.
Options are specified in list form:
(-option => value, -option => value, -option => value)
If you've never seen => in Perl before, don't be thrown by it. It's just a different way of saying "comma," except that the => operator auto-quotes the word to its left, eliminating possible ambiguities. For instance, the following code works properly because the auto-quoting resolves -text as a string:
sub text {} $mw->Label(-text => 123);
With the comma syntax, however, -text resolves to -&text( ):
$mw->Label(-text, 123);
With this in mind, you can still use just the commas and not the => notation, such as:
(-option, value, -option, value, -option, value)
However, it's much harder to tell which are the option/value pairs. Consider the following syntactically equal statements (each of which create a Button widget that is 10 by 10 pixels, displays the word "Exit," and performs the action of quitting the application when pressed):
$bttn = $parent->Button(-text, "Exit", -command, sub { exit }, -width, 10, -height, 10); $bttn = $parent->Button(-text => "Exit", -command => sub { exit }, -width => 10, -height => 10);
In the second line, it is much more obvious which arguments are paired together. The option must be directly before the value associated with it: -text is paired with "Exit", -command has the value sub { exit }, and -width and -height both have values of 10.
Another favorite option/value specification syntax uses Perl's qw operator, which treats its arguments as a list of strings:
$bttn = $parent->Button(qw/-text Exit -width 10 -height 10 -command/ => sub { exit }/);
This style is more reminiscent of Tcl's look, with whitespace-separated tokens. You tend to type fewer characters too. The string delimiter is often ( ) or {}, but // is most popular since it doesn't require a shift. Note that qw splits on simple words, so that option values can be only simple words, not multiword quoted strings, code references, and so on. That's why we moved the -command option to the end of the qw string.
Time for another detour. In the next few chapters we'll be using widgets in our examples that we might not have covered yet. We trust that you'll figure out what most of them mean from the context in which they are presented, but a few require a short introduction.
MainWindow and Toplevel are the windows (or widgets—we often interchange the terms) that contain other widgets. MainWindow is a special version of a Toplevel widget, in that the MainWindow is the first window you create in your application.
The other type of widget you need to know about is a Frame widget. A Frame is a container that can also contain other widgets. It is usually invisible and is used just to arrange the widgets as desired.
Of course, there's more to it, but that's enough to know for now. For more information, see Chapter 11, " Frame, MainWindow,and Toplevel Widgets".
Creating a widget isn't the same as displaying it in Perl/Tk. You need to use two separate commands to create a widget and display it, although sometimes they are combined into the same line and look like a single command. In the examples so far, we've used the Button method to create the Button, but nothing is displayed by using that method alone. Instead you have to use a geometry manager to cause the widget to be displayed in its parent widget or in another widget. The most commonly used geometry manager is pack. To use it, you simply call the pack method on the widget object, as follows:
$widget->pack( );
For example:
$button->pack( );
The arguments you can send to the pack method are covered in Chapter 2, "Geometry Management".
It is not necessary to invoke the pack method on a separate line. ->pack can be added to the creation of the widget:
$parent->Button(-text => "Bye!", -command => sub { exit })->pack( );
The other geometry managers available are grid, form, and place. All four behave differently; use what works best for your application. Again, look for information on the geometry managers in Chapter 2, "Geometry Management".
When programming an application that uses a graphical interface rather than a textual interface, you need to rethink the way you approach the flow of the application. In a text-based application, you can read from standard input (STDIN), use command-line options, read files, or prompt the user for specific information. The keyboard is your main avenue of input from the user. In a GUI, input comes not only from those places but also from the mouse and the window manager.[6] Although this extra input allows more flexibility in our applications, it also makes our programming job more difficult. As long as we tell it what to do, Perl/Tk helps us handle all that extra input gracefully.
[6] For example, a "close" directive from a window manager such as mwm or MS Windows.
Input in a GUI is defined by events. Events are typically different combinations of using the keyboard and mouse at the same, or different, times. If the user pushes the left mouse button on Button "B," that is one type of event. Pushing the right mouse button on Button "C" is another event. Typing the letter "a" is another event. Holding down the Control key and clicking with the middle mouse button is yet another event. Events can also come from input and output operations or be generated virtually under program control. For an in-depth examination of the Tk event loop, see Chapter 15, "Anatomy of the MainLoop".
Events are processed during an event loop. The event loop, as its name implies, handles events during a loop. It determines what subroutines to call based on what type of event has happened. Here is a pseudocode event loop:
while (1) { get_event_info if event is left-mouse-click call process_left_mouse_click else if event is right-mouse-click call process_right_mouse_click else if event is keyboard-input call type_it else handle events for redrawing, resizing etc }
This is obviously a simplistic approach to an event loop, yet it shows the basic idea. The event loop is a weeding-out process to determine what type of input has been given to the application. For example, the subroutine process_left_mouse_click might determine where the pointer was when the mouseclick occurred and then call other subroutines based on that information.
In Perl/Tk, the event loop is initiated by calling a routine called MainLoop. Anything prior to this statement is just setting up the interface. Any code after this call will not execute until after the GUI has exited using $mw->destroy.[7]
[7] Throughout the book, we use $mw to indicate the variable that refers to the MainWindow created at the beginning of the application.
If we forget to include the MainLoop statement, the program will think about things for a while and then go right back to the command prompt. None of the windows, Buttons, or widgets will be drawn at all. The first things that occur after calling MainLoop are the interface is drawn and the event loop is started.
Before we get too much further into the event loop and what it does (and what you need to do so it works properly), let's look at a working example program, Hello World. (You were expecting something else?)