BUY THIS BOOK
Add to Cart

Print Book $44.95


Add to Cart

Print+PDF $58.44

Add to Cart

PDF $35.99

Safari Books Online

What is this?

Add to UK Cart

Print Book £31.95

What is this?

Looking to Reprint or License this content?


Mastering Perl/Tk
Mastering Perl/Tk Graphical User Interfaces in Perl By Stephen Lidie, Nancy Walsh
January 2002
Pages: 768

Cover | Table of Contents | Colophon


Table of Contents

Chapter 1: Hello, Perl/Tk
Tk is a module that gives you the ability to create graphical interfaces with Perl. Most Perl programs are written with command-line interfaces, which can be cumbersome and intimidating to end users. Perl/Tk lets you communicate with buttons, menus, dialog boxes, scrolled text areas, and so on—all the features you need to develop simple or sophisticated GUI applications.
Why use a graphical interface? In the course of your programming experience, you've probably come across situations in which a text-based interface was insufficient for your needs, if not downright awkward. Certain applications can run with no input, but others, such as installation scripts, require the user to feed information to them constantly. They ask such questions as: Do you want to install this file? Can I overwrite this DLL? Do you want to create this directory? Do you want the help files?
A graphical user interface (GUI) adds a little flair and professionalism to an application. Here are some examples of good uses for a GUI:
  • A mini web client that connects to a dictionary server
  • An application that displays a map in a scrollable window
  • A program that interfaces with a database and displays query results in several widgets, with labels to describe the data
  • A mail reader that interfaces with your inbox and can also send out mail messages
A GUI can also be helpful when your boss just says "make it easy to use!," which usually means either adding a wrapper around a script or an interface that makes it easy for users to understand the decisions they have to make.
But don't take this to mean that you should start adding GUIs to all your Perl scripts. There are times when it would be overkill to add a GUI to a script. If all you are doing is reading one file, munging a bit with no user input, and generating another file, a GUI would be silly and unnecessary. GUIs work best when you require a lot of decisions and input from the user, such as in the installation scenario mentioned earlier.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Perl/Tk Concepts
Perl/Tk programs are written in an object-oriented (OO) style, but you don't need previous Perl object-oriented programming experience to code in Perl/Tk. You'll pick it up easily enough after seeing the first few examples. In a nutshell, Perl/Tk widgets (such as Buttons and Listboxes) are objects that have methods we invoke to control them. Besides widgets, Perl/Tk has images, which are also objects, and fonts, which can be objects or simple strings.
A Perl/Tk program is composed of a hierarchy of widgets. At the top of the hierarchy is the MainWindow, the parent widget for all other widgets in the application. The MainWindow widget acts as a container, within which we arrange child widgets using a geometry manager. The widget hierarchy is important for several reasons. Among other things, it's used by geometry managers to control the screen layout and the menu system to arrange menu items.
Each different widget belongs to a class. A widget's class defines its initial appearance and behavior, but individual widgets of the same class can be customized. As an example, you might create two Buttons that have different textual labels but are otherwise identical. Sometimes you'll read about instantiating a widget. This is simply OO-speak for creating a widget (a widget instance). The class constructor is responsible for creating widget instances.
The class also defines a widget's initial behavior by creating bindings. A binding associates an event such as a button press with a callback, which is a subroutine that handles the event. You can add additional bindings (indeed, even change and remove them) to alter a widget's standard behavior. Callbacks have several formats, but we mostly use simple references to Perl subroutines.
You'll learn all about these topics as you continue reading.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Some Perl/Tk History
Perl/Tk has its roots in the X Window System and the Tcl language. So let's take a detour into the pages of history, to give you an idea of where Perl/Tk came from and how it got here.
The X Window System (known to its friends as just "X" or "X11") was first released in 1987 as a graphical platform for Unix systems. Like most Unix software, X applications are almost universally written in the C language, using a library such as Xt, Motif, or (if you were really unlucky or just really brave) the underlying library for X-based applications, Xlib.
Xlib has the advantage that you can do anything, at the expense of dealing with everything. For instance, here's one way to make a simple pull-down menu using Xlib (which is one statement in Tk). First, determine the dimensions of the longest menu item. For argument's sake, assume the menu label string is in the C variable menu_item. Subroutine XTextExtents determines several metrics about menu_item, such as its overall width in pixels in the current font and its pixel height, computed by summing the maximum ascent and descent (the number of pixels above and below the baseline, respectively). After accounting for the number of menu items, border widths, and including some slop for good luck, we arrive at the dimensions of the menu window itself, and its relative (x, y) position in the MainWindow.
  XTextExtents( font_info, menu_item, strlen( menu_item ),
    &direction, &ascent, &descent, &overall );
  menu_width = overall.width + 4;
  menu_pane_height = overall.ascent + overall.descent + 4;
  menu_height = menu_pane_height * menu_pane_count;
  x = window_width - menu_width - ( 2 * menu_border_width );
  y = 0;
XCreateSimpleWindow draws the menu with the proper border and background colors, although nothing appears on the display because the window hasn't yet been mapped.
  theMenu = XCreateSimpleWindow( theDisplay, theWindow,
    x, y, menu_width, menu_height,
    menu_border_width, theBorderPixel,
    theBackgroundPixel );
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Getting Started with Perl/Tk
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 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.
Assuming that Perl/Tk is up and running, you can determine its version with this command:
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Hello World Example
Every programming language goes through the Hello World example, which is a complete program that prints a string (typically "Hello World") and exits. "Hello World" may get its share of ridicule, but it's a remarkably effective tool that shows readers how to write and execute a working program while they're still in the first chapter of the book. In our Hello World example, we'll have the title of our window say "Hello World" and create a Button that will dismiss the application:
#!/usr/bin/perl
use Tk;
my $mw = MainWindow->new;
$mw->title("Hello World");
$mw->Button(-text => "Done", -command => sub { exit })->pack;
MainLoop;
Despite being only six lines long, there is quite a bit going on in our little program. The first line, as any Perl programmer knows, invokes Perl. The second line tells Perl to use the Tk module.
The third line:
my $mw = MainWindow->new; 
is how we create a window. The window will have the same basic window manager decorations as all your other windows.
The title of our window is changed using the title method. If we hadn't used this method, the text across the top of the window would be the same as the name of the file containing the code, excluding any extension. For instance, if the code were stored in a file named hello_world, the string "Hello_world" would appear across the title bar of the application (Tk automatically capitalizes the first character for you). Using the title method is not required, but it makes the application look more polished.
Any string we put as an argument becomes the title. If we wanted the title to be "Hey! Look at my great program!," this would be the place. This is akin to using the -title option when starting any standard X Windows application. We cover more methods for a MainWindow object later in Chapter 11.
The next line creates a Button widget, sets basic properties, and packs the widget. (See Chapter 4 for all available configuration options for Button.)
The Button is set to display the text "Done" and to perform the Perl command
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Unsolicited Advice
Before we end this chapter, and you become engrossed in the details of Perl/Tk, we'd like to give you some suggestions on programming style and window design. Bear with us, this won't take long and might save you a lot of time in the future.
The code in a Perl/Tk script can get quite cumbersome and clunky because of all the option/value pairs used to define and configure each widget. There are several ways to format the code to deal with readability (and in some cases, "edit-ability"). Most just involve adding extra spaces or tabs to line up different portions of code. Once you get used to seeing the code, it won't seem quite so mysterious and unwieldy.
One coding style places each option/value pair on a separate line:
$bttn = $parent->Button(-text => "my text",
                        -command => sub { exit }, 
                        -width => 10, 
                        -height => 10);
With this style, it is extremely obvious what the pairs are and what value is associated with which option. (You could also go to the extreme of aligning each => to make nice columns, depending on how much time you have to press the spacebar.) Some people like to start the option/value pairs on the next line and put the ending ); on its own separate line, after the last option/value pair, which retains the comma for formatting ease:
$bttn = $parent->Button(
   -text => "Exit", 
   -command => sub { exit }, 
   -width => 10, 
   -height => 10,
);
This makes the code easier to edit; an option/value pair can be added or deleted on each line without having to mess with parentheses, semicolons, or commas. It also keeps the next lines closer to the left side of the page, so if you have several indentation levels, you don't end up with code quite so deeply nested to the right.
In either case, Emacs users may find the functionality of cperl-mode.el handy. This is an Emacs initialization file that adds color highlighting and special formatting that makes editing Perl code more efficient. You can find the file in the standard Perl distribution, in the
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Debugging and PrototypingPerl/Tk Programs
Debugging a Perl/Tk program need not be different from debugging a nongraphical program; you can always sprinkle warn statements throughout the code to track progress and display intermediate results. We suggest using warn rather than print for three reasons: it adds the newline to the message automatically; the output includes the line number of the warn statement; and the output goes to STDERR, which is not normally buffered, thus the output appears immediately. Furthermore, you type fewer characters.
You normally run programs by typing the program name at the command prompt:
% hello_world
         
or:
C:\>perl hello_world
         
When you invoke the program this way, any printed output goes to that terminal window. If you don't put a \n on the end of the string to be printed, you won't see the information actually printed until you quit the program. You may have to unbuffer a file handle by setting the special Perl variable $|. If you use warn rather than print, these drawbacks are eliminated.
If that old-fashioned way isn't to your liking, perhaps the slightly newer old-fashioned way of using the standard Perl debugger is. The debugger has built-in Tk support, though you must use the O command and enable it by setting the variable tkRunning:
[bug@Pandy atk]$ perl -de 0
Default die handler restored.

Loading DB routines from perl5db.pl version 1.07
Editor support available.

Enter h or `h h' for help, or `man perldebug' for more help.

main::(-e:1):   0
  DB<1> O tkRunning
           tkRunning = '1'
  DB<2> use Tk    
  DB<3> $mw = MainWindow->new
  DB<4> $b = $mw->Button(-text => 'Beep', -command => sub{$mw->bell})
  DB<5> $b->pack
  DB<6> x $b
0  Tk::Button=HASH(0x82ed434)
   '_TkValue_' => '.button'
  DB<7> q
         
As you see, we can not only print debug information, but also do simple prototyping.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Chapter 2: Geometry Management
To display widgets on the screen, they must be passed to a geometry manager. The geometry manager controls the position and size of the widgets in the display window. Several geometry managers are available with Perl/Tk: pack, place, grid, and form.
All the geometry managers are invoked as methods on the widget, but they all have their own methodologies and arguments to change where and how the widgets are put on the screen:
$widget1->pack(); $widget2->place(); $widget3->grid(); $widget4->form(  );
When you organize the widgets in your window, it is often necessary to separate groups of widgets to get a certain look and feel. For instance, when you use pack, it is difficult to have widgets stacked both horizontally and vertically without grouping them in some fashion. We use a Frame widget or another window (a Toplevel widget) to group widgets inside a window.
We create our first window by calling MainWindow. The MainWindow is a special form of a Toplevel widget. For more detailed information on how to create/configure Frame and Toplevel widgets, see Chapter 11.
With the exception of place, differences between the geometry managers make it difficult (not entirely impossible, but definitely not recommended) to use more than one geometry manager within the same area. In $mw, we can display many types of widgets, but if we start using pack, we should continue to use pack on all the widgets contained directly in $mw. Don't switch to grid in the middle, because the two geometry managers will get into a race condition: one will create its layout, which affects the geometry calculations of the other, which affects the layout of the first, causing it to recompute its geometries, ad infinitum. However, let's assume our MainWindow contains a Frame, which in turn contains other widgets. We could use pack to pack the Frame inside the MainWindow and then we could use grid to manage the widgets inside the Frame. See Figure 2-1.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
The pack Geometry Manager
Remember when you were a child and you had those wooden puzzles to put together? Each piece in the puzzle had exactly one place where it could go and there weren't any overlaps allowed between pieces.
With the pack geometry manager, our windows are similar to the wooden puzzle, because widgets cannot overlap or cover each other, partially or completely (see Figure 2-2). If a Button is packed in a certain space on the window, the next Button (or any widget) will have to fit around the already packed Button. Luckily, our windows will be dealing only with rectangular shapes instead of funny-shaped puzzle pieces.
Figure 2-2: Overlap error
The order in which you pack your widgets is very important because it directly affects what you see on the screen. Each Frame or Toplevel maintains a list of items that are displayed within it. This list has an order to it: if widget A is packed before widget B, then widget A will get preference if space becomes scarce. This will become clear as we go through some examples. You will often get a different look to your window just by packing the widgets in a different order.
If you don't care what the window looks like and how the widgets are put in it, you can use pack with no arguments and skip the rest of this chapter. Here it is again:
$widget->pack( );
To make your window look nicer and more manageable (and user friendly), there are arguments that can be sent to the pack method that will change the way the widgets and the window look. As with anything in Perl/Tk, the arguments are arranged in key/value pairs. So the more sophisticated usage would be:
$widget->pack( [ option => value, ... ] );
Here is the code to create a window that doesn't use any pack options. We haven't covered all the widgets used in this example, but hang in there; it's pretty simple.
#!/usr/bin/perl -w
use Tk;

my $mw = MainWindow->new;
$mw->title("Bad Window");
$mw->Label(-text => "This is an example of a window that looks bad\nwhen you don't
 send any options to pack")->pack;

$mw->Checkbutton(-text => "I like it!")->pack;
$mw->Checkbutton(-text => "I hate it!")->pack;
$mw->Checkbutton(-text => "I don't care")->pack;
$mw->Button(-text => "Exit",
            -command => sub { exit })->pack;
MainLoop;
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
The grid Geometry Manager
The grid geometry manager divides the window into a grid composed of columns and rows starting at (0, 0) in the upper-left corner. Figure 2-29 shows a sample grid.
Figure 2-29: A window divided into grids
Rather than using the sides of a window as reference points, grid divides the screen into columns and rows. It looks a lot like a spreadsheet, doesn't it? Each widget is assigned a grid cell using the options available to grid.
The grid method takes a list of widgets instead of operating on only one widget at a time. Here is the generic usage:
$widget1->grid( [ $widget2, ... , ] [ option => value, ... ] );
A specific example is:
$widget1->grid($widget2, $widget3);
Instead of using three separate calls, you can use one grid call to display all three widgets. You can also invoke grid on each widget independently, just as you can pack. Each call to grid will create another row in the window. So in our example, $widget1, $widget2, and$widget3 will be placed in the first row. Another call to grid creates a second row. This is what happens when you do not specify any additional options to the grid call.
The previous example can be rewritten like this:
Tk::grid($widget1, $widget2, $widget3);
But beware, this is not necessarily equivalent to the previous statement, due to inheritance, an object-oriented concept. For more information, please refer to Chapter 14. Essentially, using Tk::grid is the same as calling a subroutine directly, whereas the method call searches the widget's class hierarchy for a subroutine grid. It's certainly possible that $widget1 has its own special grid method, which we would rudely bypass. Is this a likely possibility? No. Just be aware when you make a procedural versus a method call.
For greater control, you can specify explicit -row
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
The place Geometry Manager
The place geometry manager is different than grid or pack. Rather than referencing against a cell location or a window's side, most of the time you'll be using a relative form of x and y coordinates. You can also use place to overlap portions of widgets, which isn't allowed in either grid or pack.
Invoking place is similar to calling the other geometry managers:
$widget->place( [ option => value, . . . ] );
The options specified when you call place affect how the widgets are put on the screen.
The following options can be used with place:
-anchor => 'n' | 'ne' | 'e' | 'se' | 's' | 'sw' | 'w' | ' nw ' | 'center'
Sets the position in the widget that will be placed at the specified coordinates.
-bordermode => ' inside ' | 'outside' | 'ignore'
Determines whether or not the border portion of the widget is included in the coordinate system.
-height => amount
Sets the absolute height of the widget.
-in => $window
Indicates that the child widget will be packed inside $window instead of in the parent that created it. Any relative coordinates or sizes will still refer to the parent.
-relheight => ratio
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
The form Geometry Manager
The final geometry manager we want to cover is form. Recently added into the Perl/Tk distribution, form is a very different geometry manager than those we've seen so far. To try and compare it with what we already know, it behaves like a combination of pack and place. Using form, it is legal to overlap widgets (as you would with place), but you can also display the widgets relative to each other and stretch them out to fill the entire available area and resize with the window (as you would with pack). The combination of all these abilities results in a powerful geometry manager.
When using form, each edge of a widget can be attached to something: the container's grid, another widget, or nothing at all. You can also use springs to push your widgets around in the window based on the strength (or weight) of the spring. As with the other geometry managers, you can add padding to your widget.
Let's look at the options briefly, then go into more detail on how to use them.
The following are all the legal options for form. The following sections show you how to use these options to the best effect.
-bottom => attachment
Uses the given attachment on the bottom side of the widget.
-bottomspring => weight
Uses the given weight for a spring on the bottom side of the widget.
-fill => 'x' | 'y' | 'both' | 'none'
Specifies the direction in which to fill when springs are used. There is no default value.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Geometry Management Summary
You now know more about the different geometry managers than you'll ever need to write a successful Perl/Tk application. Here are some helpful hints on deciding which geometry manager to use:
  • pack is good for general purpose use and will be your choice about 95% of the time.
  • grid is perfect for those situations in which you would like to create a columnar layout similar to a spreadsheet. Options allow you to change the sizes of rows and/or columns easily.
  • place is most useful when you want your widget to stay in a position or size that is relative to the widget that created it. When used correctly, it can be very powerful.
  • form is powerful, but difficult to get used to; not for the faint of heart. Check future releases of the Tk module for updates to this geometry manager.
No matter which manager you use, take the time to get the widgets on your window where they belong (or more likely, where you want them). There's nothing more unsettling than a Button that looks like it just doesn't belong in the window.
As you read through this book, you'll notice that some of the option names for the geometry managers are also option names when you are creating or configuring a widget type. For example, you can specify the -width of a Button without using place. Always keep in mind the context in which the option is used. Sometimes the functional difference is very subtle.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Chapter 3: Fonts
Every computer system uses fonts. In Perl/Tk applications, you can change any of the fonts for items inside the application, but not the fonts used in the window decoration for titles (which are handled by the window manager). In this chapter, we'll show you how to use fonts in your Perl/Tk application.
What fonts do you have available? For MS Windows users, the available fonts can be found in the Font control panel. Users of the X Window System can get a font list by running xlsfonts. The font used in this chapter is Linotype Birka. While you can't do anything about the font used in this book, you can do something about the fonts in the applications you create or run in Perl/Tk.
The simplest way of altering an application's font is changing the base font for the entire application. You can do that with any Perl/Tk application by using a command-line option:
perl myTkApp.pl -font "Times 12"
Using the -font command-line option doesn't require any changes to your Perl script. The -font option works because of the way Tk::CmdLine works, described in Chapter 16. Note that you specify the -font option after the name of the program to run. As long as you haven't explicitly specified the font for any widgets in your application, all widgets will use the new font.
To change the font for only some widgets, you can use the option database, described in Chapter 16. For example, if you wanted to change only the font for Text widgets in your application, specify *text*font=Courier 16 in the option database.
You don't generally want to hardcode font specifications in your programs. Simply put, it prevents your users from customizing your applications. There are extenuating circumstances, though; you might have an HP calculator that has a specific look that shouldn't be changed (see Chapter 15). Creating such a specific look might require one or more particular fonts.
One way to determine what font to use is to write a program using the
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Experimenting with Fonts
You don't generally want to hardcode font specifications in your programs. Simply put, it prevents your users from customizing your applications. There are extenuating circumstances, though; you might have an HP calculator that has a specific look that shouldn't be changed (see Chapter 15). Creating such a specific look might require one or more particular fonts.
One way to determine what font to use is to write a program using the fontFamilies method that displays various font specifications. So, before we get into the details of creating a font definition, let's look at a program that lets us play around with the fonts on our system. This program is useful no matter what operating system you're on.
use Tk;
use Tk::BrowseEntry;
use strict;

my $mw = MainWindow->new(-title => 'Font Viewer');
my $f = $mw->Frame->pack(-side => 'top');

my $family = 'Courier';
my $be = $f->BrowseEntry(-label => 'Family:', -variable => \$family,
  -browsecmd => \&apply_font)->pack(-fill => 'x', -side => 'left');
$be->insert('end', sort $mw->fontFamilies);

my $size = 24;
my $bentry = $f->BrowseEntry(-label => 'Size:', -variable => \$size, 
  -browsecmd => \&apply_font)->pack(-side => 'left');
$bentry->insert('end', (3 .. 32));

my $weight = 'normal';
$f->Checkbutton(-onvalue => 'bold', -offvalue => 'normal', 
  -text => 'Weight', -variable => \$weight, 
  -command => \&apply_font)->pack(-side => 'left');

my $slant = 'roman';
$f->Checkbutton(-onvalue => 'italic', -offvalue => 'roman', 
  -text => 'Slant', -variable => \$slant, 
  -command => \&apply_font)->pack(-side => 'left');

my $underline = 0;
$f->Checkbutton(-text => 'Underline', -variable => \$underline, 
  -command => \&apply_font)->pack(-side => 'left');

my $overstrike = 0; 
$f->Checkbutton(-text => 'Overstrike', -variable => \$overstrike, 
  -command => \&apply_font)->pack(-side => 'left');

my $stext = 'Sample Text';
my $sample = $mw->Entry(-textvariable => \$stext)->pack(-fill => 'x');

&apply_font;

MainLoop;

sub apply_font {
  # Specify all options for font in an anonymous array
  $sample->configure(-font => 
    [-family => $family,
     -size => $size,
     -weight => $weight,
     -slant => $slant,
     -underline => $underline,
     -overstrike => $overstrike]);
}
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Dissecting a Font
In the font viewer, we see that the Entry's font is changed with the -font option using an anonymous array. From this we know a font consists of the following things:
Family
The actual name of the font, e.g., 'Courier', 'Times', and so on.
Size
The size of the font in points. The larger the size, the larger the text displayed on the screen. A point is 1/72 of an inch. Negative values are interpreted as pixels.
Weight
Determines if the font is shown boldor not. The value 'normal' means it is not shown bold, and 'bold' makes the font thicker.
Slant
Shows straight up and down if 'roman' is used, and slanted if 'italic' is used.
Underline
If the value used with -underline is true, the text will be underlined. If false, the text will not be underlined.
Overstrike
If true, a line will be drawn through the center of the text.
If you are used to working with fonts on a Unix system, you are probably familiar with X Logical Font Descriptions (XFLD). This is the dash-delimited format used for fonts under X, for example:
*-helvetica-bold-r-*-*-*-240-*-*-*-*-*-*
This font description indicates a 24-point bold Helvetica font with Roman slant. The field order is as follows: -foundry-family-weight-slant-sWdth-adstyl-pixelsize-pointsize-resx-resy-spacing-avgWidth-registry-encoding
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Using Fonts
Now that we know what comprises a font, let's look at a few ways we can specify them in code.
We simplify things in our Perl/Tk applications by being able to create a single name that refers to a combination of family, size, weight, slant, underline, and overstrike:
$code_font = $mw->fontCreate('code', -family => 'courier',
                             -size => 12);
Once we have created our new font, you can refer to the font by the variable $code_font or by the name, 'code':
$mw->Button(-text => "Show Code", -font => 'code');
$mw->Button(-text => "Show Code2", -font => $code_font);
It is much simpler to specify all the desired font options once and refer to them using the name or variable later in the program. If you don't want to use a name for the font, don't specify it; the system will generate a name for you automatically.
$code_font = $mw->fontCreate(-family => 'courier',
                             -size => 12);
Once the font is created, you can change any of its settings using the fontConfigure method, using the font name or reference as the first argument:
$mw->fontConfigure($code_font, -family => 'Verdana');
The changes will take effect immediately on any widgets using that font, making it very useful for on-the-fly changes.
The -font option will also accept an anonymous array containing the right parts, with or without the identifiers:
-font => ['courier', '14', 'bold']
# The same thing, but more verbose:
-font => [-family => 'courier',
          -size => '14',
          -weight => 'bold']
The second way is much more verbose, and easier to read, but those of us who prefer to keep our code small and compact might want to stick with the first method. You must specify at minimum the family name; all other specifications are optional.
If creating an anonymous array isn't to your liking, try just using a string containing the relevant parts:
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Using Fonts Dynamically
Let's look at a program that creates fonts dynamically. This code will display each selected font in a window much the way Microsoft Windows does when you look at the Font control panel. To display the font in its different sizes, we simply use the ROText widget so the text is read-only (see Chapter 8 for further information on ROText widgets). The font changes are applied in the show_font sub using tags.
use Tk;
require Tk::TList;
require Tk::ROText;
use strict;

my $mw = MainWindow->new(-title => "Fonts");
$mw->minsize(700,400);
my $tl = $mw->Scrolled("TList", -font => ['Arial', '12'], -command => \&show_font)->
pack(-fill => 'both', -expand => 1);

# using a tlist, we have to insert each item individually
foreach (sort $mw->fontFamilies)
{
		$tl->insert('end', -itemtype => 'text', -text => $_);
}

MainLoop;

# called when user double clicks on a font name in the tlist.
sub show_font
{
		my ($index) = @_;
		my $name = $tl->entrycget($index, -text);
		my $top = $mw->Toplevel(-title => $name);
		my $text = $top->Scrolled("ROText", -wrap => 'none')
      ->pack(-expand => 1, -fill => 'both');
		
		$text->tagConfigure('number', -font => ['courier', '12']);

    # since we don't know what font they picked, we dynamically
    # create a tag w/that font formatting
		$text->tagConfigure('abc', -font => [$name, '18']);
		$text->insert('end', "abcdefghijklmnopqrstuvwxyz\
nABCDEFGHIJKLMNOPQRSTUVWXYZ\n1234567890.;,;(*!?')\n\n", 'abc');
		
		foreach (qw/12 18 24 36 48 60 72/)
		{
			$text->tagConfigure("$name$_", -font => [$name, $_]);
			$text->insert('end', "$_ ", 'number');
 			$text->insert('end', 
 "The quick brown fox jumps over the lazy dog. 1234567890\n", "$name$_");
		}
}
Figure 3-2 and Figure 3-3 show the resulting windows.
Figure 3-2: MainWindow in our control panel-like Font viewer
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Font Manipulation Methods
Once you've created a font using fontCreate, you can use the following methods.
For a description of the font's attributes (some or all), use fontActual to query the font:
$mw->fontCreate('bigfont', -family => 'Arial', -size => 48);

%big = $mw->fontActual('bigfont');
print %big;
# prints:
-size 48 -overstrike 0 -underline 0 
-weight normal -slant roman -family Arial

$size = $mw->fontActual('bigfont', -size);
print $size;
#prints: 
48
To change (or query) a property of a font once it has been created, use fontConfigure:
if ($mw->fontConfigure('bigfont', -size) < 24) {
  $mw->fontConfigure('bigfont', -size => 48);
}

# same as $mw->fontActual('bigfont');
%bigfont = $mw->fontConfigure('bigfont');
If you'd like to delete a font definition, use fontDelete:
$mw->fontDelete('bigfont');
If you delete a font that is being used, the widgets using it won't change what they display. They display whatever font they were last. If you try to manipulate the font programmatically after it's been deleted, you will get an error.
To get a list of all the font families available on your system, use fontFamilies:
@families = $mw->fontFamilies;
To get a list of the currently defined named fonts on your system, use fontNames:
@definedfonts = $mw->fontNames;
The fontNames method returns a list of object references to Font objects. The list will be empty if there aren't any fonts defined on your system. Keep in mind this list contains only those fonts defined using the fontCreate method.
If you want to determine how much horizontal space a piece of text will take up with a given font, use fontMeasure. The answer is given in pixels. Don't count on this figure to be the exact size; it's more of an estimate.
print $mw->fontMeasure('bigfont', "SHORT"), "\n";
225
print $mw->fontMeasure('bigfont', "MUCH LONGER"), "\n";
480
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Chapter 4: Button, Checkbutton, and Radiobutton Widgets
Almost all Perl/Tk applications use Buttons in one way or another. There are three different types of Button widgets available in the standard Perl/Tk set: Button, Checkbutton, and Radiobutton. This chapter covers all three types of Buttons and includes examples of where you might use one over the other.
Each of the Buttons we cover in this chapter look different, primarily in their use of selection indicators. The Button widget doesn't use indicators at all, but Checkbutton and Radiobutton widgets use them to indicate whether the Button has been selected or not. The Button widgets are:
Button
A plain Button, shown in Figure 4-1. The user can press it and usually an immediate action results.
Figure 4-1: Button widget
Checkbutton
A Checkbutton, shown checked in Figure 4-2. When checked or unchecked, only the visual representation is changed; the state is not validated until later in the program. Checkbuttons can be used singly or in groups.
Figure 4-2: Checkbutton widget
Radiobutton
A Radiobutton, shown unchecked in Figure 4-3. When checked or unchecked, only the visual representation is changed; the state is not validated until later in the program. Radiobuttons are always used in groups of two or more.
Figure 4-3: Radiobutton widget
A Button is one of the simplest Perl/Tk widgets: the user presses it and something immediately happens. The label of the Button should make the action clear; for example, text such as Quit, Save, or Print gives the user a good idea of what will happen when she clicks the Button. After the Button has been clicked, it will look exactly the same as before, unless programmed to change text or color.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Creating Button Widgets
As with any widgets you create, you call a method from the parent widget that matches the name of the widget:
$button = $mw->Button->pack;
$rb = $mw->Radiobutton->pack;
$cb = $mw->Checkbutton->pack;
These are unrealistic examples as you will most likely use some options when creating each different Button type:
# Create a Button widget
$mw->Button(-text => 'Go', -command => \&go_go_go)->pack;

# Create a Checkbutton
$cb = $mw->Checkbutton(-text => 'Red', -onvalue => 'Red', 
	-offvalue => '')->pack;

# Create three Radiobuttons in Frame widget $f1
# Link them using $favcolor
foreach (qw/red blue green/) {
    $f1->Radiobutton(-text => $_, -variable => \$favcolor, 
        -value => $_)->pack(-anchor => 'w');
}
We'll explain the options used in the previous examples in upcoming sections. In particular, -command expects a callback, which we'll mention briefly in Section 4.9, but we won't fully describe until Chapter 15.
The only time you might not want to save a reference is when you create a Button, set the text, and set a simple callback for it all at once:
$mw->Button(-text => 'Quit', -command => sub { print 'Bye!'; exit; })->pack;
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Standard Options for Each Button Type
Before we get into all the options available for each of the Button widgets, let's take a look at the most common ones.
When creating a Button, use the -text and -command options. The -text option lets the user know what the Button is for, and the -command option makes something happen when the user clicks the Button.
$b = $mw->Button(-text => 'Exit', -command => sub { exit; } )->pack;

# Use the same sub for many Buttons
$b = $mw->Button(-text => 'Red', -command => [\&change_color, 'red'])->pack;
$b = $mw->Button(-text => 'Blue', 
	-command => [\&change_color, 'blue'])->pack;
$b = $mw->Button(-text => 'Green', 
	-command => [\&change_color, 'green'])->pack;
When creating Checkbuttons, you use -variable in addition to -text. Using -variable gives you an easy way to find out whether the Checkbutton is checked. (You will rarely use -command with a Checkbutton):
$mw->Checkbutton(-text => 'Print Header', -variable => \$print_header);

sub print_document {
	if ($print_header) {
		# Code to print header here...
	}
}
The value stored in $print_header is 1 or 0. A simple test will tell you if the Checkbutton was checked.
When creating Radiobuttons, we always create more than one and use the -text, -variable, and -value options:
$group1 = 100; # set default value
foreach (qw/1 10 100 10000 100000 1000000/) {
	$mw->Radiobutton(-text => '$' . $_, -variable => \$group1, 
		-value => $_)->pack(-side => 'left');
}

print "User selected: $group1";
The variable $group1 relates all of the Radiobuttons, making it so the user can select only one at a time. Each Radiobutton must be given a -value to store in $group1 (there is no default).
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Table of Options for Button-Type Widgets
The Button widgets share almost all of the same options. Table 4-1 shows a complete list of options and which widget they apply to. We'll cover these options in more detail as we explore what Buttons can do.
In the details following Table 4-1, all information applies equally to Buttons, Checkbuttons, and Radiobuttons unless explictly stated otherwise.
Table 4-1: Options for Button-type widgets
Option
Button
Checkbutton
Radiobutton
-activebackground => color
Sets the color the background should be when the mouse cursor is over the Button. A color is a text string such as "red".
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Displaying Text on Buttons
To show what the Button will do when it is pressed, set its text string with the -text or -textvariable option. The descriptive text string should be short and simple.
The -text option is the more common way to assign a text string:
-text => 'Submit'
The string can be anything: alphanumeric, newline(s), or variables. The text string is just like any other string in Perl in that if it is put in single quotes, it is taken literally; if it is put in double quotes, it is interpolated. The interpolation only happens once (the first time the option is parsed). If a variable changes later in the program, it has no