Learn the Perl/Tk module, Part 2

Intermediate widgets

Content series: This content is part # of # in the series: Learn the Perl/Tk module, Part 2 Stay tuned for additional content in this series. This content is part of the series: Learn the Perl/Tk module, Part 2 Stay tuned for additional content in this series.

The Perl language is commonly used by the IBM® AIX® operating system (AIX) administrators and developers. Perl can be found on nearly every successful Web site and on most AIX systems. Although Perl scripts are powerful, they produce a Web interface that lacks a graphical front end and forces the user to type information instead of using the mouse, which can be an unsatisfying experience for the customer. This problem has been resolved with the introduction to the Tk module in Perl. An admin or developer can quickly breathe new life into Perl scripts with the Tk module and satisfy customers' desires for X11 products.

Understanding widgets

As discussed in Part 1, a widget is a graphical object that performs a specific function. Any graphical object in the Perl/Tk module can be considered a widget. In a GUI application, the buttons, text, frames, and scrollbars are all widgets. This second article discusses such widgets as:

Radiobutton

Checkbutton

Menu

Menubutton

Scrollbar

Packing widgets

One of the most commonly used functions and also one of the more complicated methods is pack . The pack function is a geometry or placement manager in the Perl/Tk module. When the developer defines a widget, it is simply that: defined. The widget isn't displayed until space is properly allocated by a geometry manager—and this is where pack comes in to do its job. The pack function calculates space allocated on the widget's parent and displays the widget.

Creating multiple windows

Depending on the end user's needs, an application might require multiple windows. Creating multiple windows is simple. It extends the methods used in Part 1. The first question to be answered is whether the application should create and display the windows at the same time, or whether a user's action should trigger the creation and display of the new windows. This section discusses both methods. Creating an application that displays several windows at the same time is an extension of creating a single window with the addition of the TopLevel widget:

#!/usr/bin/perl -w # Create multiple windows at once use Tk; use strict; my $mw = MainWindow->new; $mw->geometry("200x100"); $mw->title("Multiple Windows Test"); my $subwin1 = $mw->Toplevel; $subwin1->title("Sub Window #1"); my $subwin2 = $mw->Toplevel; $subwin2->title("Sub Window #2"); MainLoop;

Running the script generates the GUI application shown in Figure 1.

Figure 1. An example of multiple windows opening at once

This article reviews the first section of the code once in order to review what was discussed in Part 1 of this series. The first part (/usr/bin/perl) defines the location where the Perl executable resides on the computer, and it instructs the computer to use this copy of the Perl executable to execute the file multiple_windows_at_once-demo.pl:

#!/usr/bin/perl -w

The second part of this line of code ( -w ) is a valuable tool in Perl. It enables warnings when executing the script, informing the end user of any possible errors found. Comments and text that aren't to be evaluated at execution are preceded with a pound sign ( # ). For example:

# Create multiple windows at once

In order for a Perl script to use the Tk module, it must be included: hence the use Tk code. For example:

use Tk; use strict;

Adding the use strict statement to a Perl script helps find typos and logic errors. To create the application's primary window, use MainWindow , and assign it to $mw . For example:

my $mw = MainWindow->new;

$mw acts as the parent of all other widgets, as discussed further in this article. Set the main window size to 200x100, and title the main window Multiple Windows Test. For example:

$mw->geometry("200x100"); $mw->title("Multiple Windows Test");

To create an additional window in the application, use TopLevel and assign it to $subwin1 . For example:

my $subwin1 = $mw->Toplevel; $subwin1->title("Sub Window #1");

Similar to creating the first additional window, create another window and assign it to $subwin2 . For example:

my $subwin2 = $mw->Toplevel; $subwin2->title("Sub Window #2");

Before executing MainLoop , everything in the script is read, defined, and prepared to execute. Then, when MainLoop is called, all functions and data read previously are executed, and the GUI is displayed. For example:

MainLoop;

Creating an application that displays additional windows as triggered by the user is equally easy. For example:

#!/usr/bin/perl -w # Create a sub window at the request of the user use Tk; use strict; my $mw = MainWindow->new; $mw->geometry("400x100"); $mw->title("Multiple Windows Test"); my $button1 = $mw->Button(-text => "Open new window", -command => \&button1_sub)->pack(-side => "top"); $mw->Button(-text => "Exit", -command => sub{exit})->pack(); sub button1_sub { my $subwin1 = $mw->Toplevel; $subwin1->geometry("300x150"); $subwin1->title("Sub Window #1"); my $subwin_button = $subwin1->Button(-text => "Close window", -command => [$subwin1 => 'destroy'])->pack(); } MainLoop;

Executing the script generates the GUI application shown in Figure 2.

Figure 2. An example of multiple windows opening individually

When the script executes, only the main window is displayed. However, clicking the Open new window button creates and displays the subwindow (see Figure 3).

Figure 3. An open subwindow

First, create a button labeled Open new window, and assign its function to the subroutine button1_sub . Also create an Exit button that executes the subroutine to exit the Perl script. For example:

my $button1 = $mw->Button(-text => "Open new window", -command => \&button1_sub)->pack(-side => "top"); $mw->Button(-text => "Exit", -command => sub{exit})->pack();

The button1_sub subroutine creates a new window with the TopLevel widget setting the size and title. It also creates a Close Window button that lets the user destroy the child window. For example:

sub button1_sub { my $subwin1 = $mw->Toplevel; $subwin1->geometry("300x150"); $subwin1->title("Sub Window #1"); my $subwin_button = $subwin1->Button(-text => "Close window", -command => [$subwin1 => 'destroy'])->pack(); }

Using intermediate widgets

This section discusses intermediate widgets, which logically follows from the discussion of introductory widgets in Part 1. These intermediate widgets include the radiobutton, checkbutton, menu, menubutton, and scrollbar widgets.

Radiobutton

The radiobutton widget displays one or several radio buttons; the user must decide among the buttons. The following example demonstrates how to introduce the radiobutton widget into an application.

#!/usr/bin/perl -w # create radio buttons use Tk; use strict; my $mw = MainWindow->new; $mw->geometry("300x100"); $mw->title("Radio Button Test"); my $color = "Red"; my $radio_frame = $mw->Frame()->pack(-side => "top"); $radio_frame->Label(-text=>"My favorite primary color is ")->pack(-side => "left"); my $radio_blue = $radio_frame->Radiobutton(-text => "Blue", -value => "Blue", -variable=> \$color)->pack(-side => "right"); my $radio_yellow = $radio_frame->Radiobutton(-text => "Yellow", -value => "Yellow", -variable=> \$color)->pack(-side => "right"); my $radio_red = $radio_frame->Radiobutton(-text => "Red", -value => "Red", -variable=> \$color)->pack(-side => "right"); my $button_frame = $mw->Frame()->pack(-side => "bottom"); my $button_color = $button_frame->Button(-text => "OK", -command => \&color_sub)->pack(-side => "left"); my $button_exit = $button_frame->Button(-text => "Exit", -command => sub{exit})->pack(-side => "right"); sub color_sub { $mw->messageBox(-message => "You selected $color!", -type => "ok"); } MainLoop;

Executing the script generates the GUI application shown in Figure 4.

Figure 4. A radiobutton widget example

You first define the variable $color and set its value to "Red":

my $color = "Red";

Creating a frame to hold the radio buttons and label gives the widget a clean, aligned, professional look. Create a label widget to let the user know what the program expects from him. For example:

my $radio_frame = $mw->Frame()->pack(-side => "top"); $radio_frame->Label(-text=>"My favorite primary color is ")->pack(-side => "left"); my $radio_blue = $radio_frame->Radiobutton(-text => "Blue", -value => "Blue", -variable=> \$color)->pack(-side => "right"); my $radio_yellow = $radio_frame->Radiobutton(-text => "Yellow", -value => "Yellow", -variable=> \$color)->pack(-side => "right"); my $radio_red = $radio_frame->Radiobutton(-text => "Red", -value => "Red", -variable=> \$color)->pack(-side => "right");

Create three radiobutton widgets, and assign them to the predefined variable $color . Each radio button has text and a value assigned as a color. Because you defined the variable $color with the value "Red", the $radio_red widget is the default value, and it is set to true. Now add a second frame to hold the window's buttons. Inside the frame, create two buttons. The first is labeled OK and executes the subroutine color_sub when the user clicks the button. The second button is labeled Exit; when clicked, it exits the program. For example:

my $button_frame = $mw->Frame()->pack(-side => "bottom"); my $button_color = $button_frame->Button(-text => "OK", -command => \&color_sub)->pack(-side => "left"); my $button_exit = $button_frame->Button(-text => "Exit", -command => sub{exit})->pack(-side => "right");

The following subroutine displays a message box notifying the user which color they selected. When they click OK, the message box is destroyed. For example:

sub color_sub { $mw->messageBox(-message => "You selected $color!", -type => "ok"); }

Checkbutton

The checkbutton widget displays one or several check boxes. The user can select one or more of them. The following example illustrates using the checkbutton widget:

#!/usr/bin/perl -w use Tk; use strict; my $mw = MainWindow->new; $mw->geometry("300x150"); $mw->title("Check Button Test"); my $check1 = 'NOT CHECKED'; my $check2 = 'NOT CHECKED'; my $check3 = 'NOT CHECKED'; my $check_frame = $mw->Frame()->pack(-side => "top"); $check_frame->Label(-text=>"Select some check buttons.")->pack(-side => "top")->pack(); my $chk1 = $check_frame->Checkbutton(-text => 'Check #1', -variable => \$check1, -onvalue => 'CHECKED', -offvalue => 'NOT CHECKED')->pack(); my $chk2 = $check_frame->Checkbutton(-text => 'Check #2', -variable => \$check2, -onvalue => 'CHECKED', -offvalue => 'NOT CHECKED')->pack(); my $chk3 = $check_frame->Checkbutton(-text => 'Check #3', -variable => \$check3, -onvalue => 'CHECKED', -offvalue => 'NOT CHECKED')->pack(); my $button_frame = $mw->Frame()->pack(-side => "bottom"); my $ok_button = $button_frame->Button(-text => 'OK', -command => \&check_sub)->pack(-side => "left"); my $exit_button = $button_frame->Button(-text => 'Exit', -command => sub{exit})->pack(-side => "right"); sub check_sub { my $check_msg = "Check #1: $check1

Check #2: $check2

Check #3: $check3"; $mw->messageBox(-message => "Check Button Summary:

$check_msg", -type => "ok"); } MainLoop;

Executing the script generates the GUI application shown in Figure 5.

Figure 5. A checkbutton widget example

First, define three variables for the checkbuttons, and set a default value of "NOT CHECKED". For example:

my $check1 = 'NOT CHECKED'; my $check2 = 'NOT CHECKED'; my $check3 = 'NOT CHECKED';

Next, create a frame to organize the label widget and checkbutton widgets. Also create the label and pack it, aligning it to the top of the frame. For example:

my $check_frame = $mw->Frame()->pack(-side => "top"); $check_frame->Label(-text=>"Select some check buttons.")->pack(-side => "top")->pack();

Create three checkbuttons labeled Check #1, Check #2, and Check #3. Assign them the predefined variables $check1 through $check3 , and set the onvalue and offvalue attributes to display the appropriate text to the user. For example:

my $chk1 = $check_frame->Checkbutton(-text => 'Check #1', -variable => \$check1, -onvalue => 'CHECKED', -offvalue => 'NOT CHECKED')->pack(); my $chk2 = $check_frame->Checkbutton(-text => 'Check #2', -variable => \$check2, -onvalue => 'CHECKED', -offvalue => 'NOT CHECKED')->pack(); my $chk3 = $check_frame->Checkbutton(-text => 'Check #3', -variable => \$check3, -onvalue => 'CHECKED', -offvalue => 'NOT CHECKED')->pack();

Create a second frame to organize the buttons. Two buttons are created in this frame. The first, labeled OK, triggers the subroutine check_sub . The second executes the subroutine to exit the Perl script. For example:

my $button_frame = $mw->Frame()->pack(-side => "bottom"); my $ok_button = $button_frame->Button(-text => 'OK', -command => \&check_sub)->pack(-side => "left"); my $exit_button = $button_frame->Button(-text => 'Exit', -command => sub{exit})->pack(-side => "right");

The subroutine check_sub defines a variable named $check_msg with the status of each checkbutton, and it displays the output to the variable $check_msg using the messageBox widget. For example:

sub check_sub { my $check_msg = "Check #1: $check1

Check #2: $check2

Check #3: $check3"; $mw->messageBox(-message => "Check Button Summary:

$check_msg", -type => "ok"); }

Menu and menubuttons

The menu widget is an easy way to display items in a single, clean column. The majority of complex GUI applications contain some form of a menu that might contain only an exit function or 20 selections. The following script demonstrates how easy it is to create a menu:

#!/usr/bin/perl -w use Tk; use strict; my $mw = MainWindow->new; $mw->geometry("300x150"); $mw->title("Menu Test"); my $main_menu = $mw->Menu(); $mw->configure(-menu => $main_menu); my $file_menu = $main_menu->cascade(-label=>"File", -underline => 0, -tearoff=>0); $file_menu->command(-label=>"Exit", -underline=>0, -command=>sub{exit}); $main_menu->command(-label=>"Say Hello", -underline => 0, -command=>sub{$mw->messageBox(-message=>"Hello!", -type => "ok")}); MainLoop;

Executing the script generates the GUI application shown in Figure 6.

Figure 6. A menu widget example

Create the menu widget, and begin to configure it, preparing it for menu items. For example:

my $main_menu = $mw->Menu(); $mw->configure(-menu => $main_menu);

Now, create a File menu. For example:

my $file_menu = $main_menu->cascade(-label=>"File", -underline => 0, -tearoff=>0);

Create an Exit command under the File menu, with a subroutine to exit the script. For example:

$file_menu->command(-label=>"Exit", -underline=>0, -command=>sub{exit});

Create another menu, and label it Say Hello. For example:

$main_menu->command(-label=>"Say Hello", -underline => 0, -command=>sub{$mw->messageBox(-message=>"Hello!", -type => "ok")});

Instead of including commands under this menu, a command is configured onto the menu itself. When you select this menu, a message box appears that says "Hello!" The menubutton widget is similar to the menu widget, but it includes a means to display text or images associated with the menu. The following example describes how to add the menubutton widget into an application and how to add a little color to the commands.

#!/usr/bin/perl -w use Tk; use strict; my $mw = MainWindow->new; $mw->geometry("300x150"); $mw->title("Menubutton Test"); my $main_menu = $mw->Menu(); $mw->configure(-menu => $main_menu); my $btn = $main_menu->Menubutton(-text => "Colorful Buttons...", -underline => 0, -tearoff=>0); $btn->command(-label => "Button #1", -activebackground => "blue", -foreground => "blue", -command => sub{$mw->messageBox(-message => "Button #1 Pressed")}); $btn->command(-label => "Button #2", -activebackground => "red", -activeforeground => "black", -background => "yellow", -foreground => "green", -command => sub{$mw->messageBox(-message => "Button #2 Pressed")}); $btn->command(-label => "Exit", -command => sub{exit}); MainLoop;

Running the script generates the GUI application shown in Figures 7, 8, and 9.

Figure 7. A menubutton widget example

Figure 8. Menubutton widget example: mouse over Button #1

Figure 9. Menubutton widget example: mouse over Button #2

First, create the menubutton widget, and prepare to add commands to it. For example:

my $btn = $main_menu->Menubutton(-text => "Colorful Buttons...", -underline => 0, -tearoff=>0);

Now create three commands on the $btn menubutton. For example:

$btn->command(-label => "Button #1", -activebackground => "blue", -foreground => "blue", -command => sub{$mw->messageBox(-message => "Button #1 Pressed")}); $btn->command(-label => "Button #2", -activebackground => "red", -activeforeground => "black", -background => "yellow", -foreground => "green", -command => sub{$mw->messageBox(-message => "Button #2 Pressed")}); $btn->command(-label => "Exit", -command => sub{exit});

The first command has a blue foreground: When the command is not highlighted, the background remains the default grey with blue text. The command also has an active blue background: When the command is highlighted, the background turns blue, while the text remains the default grey. When the menubutton is activated, a message box appears and states that the button has been clicked. The second command performs a similar action when selected. However, the active background is red, the active foreground is black, the background is yellow, and the foreground is green. The third command exits the script.

Scrollbar

The scrollbar widget controls the view of other widgets, such as text and entry widgets. Adding this widget enables the user to move the target widget up and down using a scrolling bar. Adding the scrollbar widget to an application is quick and simple. For example:

#!/usr/bin/perl -w use Tk; use strict; my $mw = MainWindow->new; $mw->geometry("200x100"); $mw->title("Scrollbar Test"); my $scroll_text = $mw->Scrollbar(); my $main_text = $mw->Text(-yscrollcommand => ['set', $scroll_text], -background => 'black', -foreground => 'red'); $scroll_text->configure(-command => ['yview', $main_text]); $scroll_text->pack(-side=>"right", -expand => "no", -fill => "y"); $main_text->pack(-side => "left", -anchor => "w", -expand => "yes", -fill => "both"); MainLoop;

Running the script generates the GUI application shown in Figure 10.

Figure 10. Scrollbar widget example

First create the scrollbar widget. For example:

my $scroll_text = $mw->Scrollbar();

Create a text widget with colors other than the default, and bind the scrollbar widget ($scroll_text) as a scrollcommand on the y (vertical) axis of the application. For example:

my $main_text = $mw->Text(-yscrollcommand => ['set', $scroll_text], -background => 'black', -foreground => 'red');

Allow the user to interact with the scrollbar widget by moving the scrollbar to control the target widget's movement. For example:

$scroll_text->configure(-command => ['yview', $main_text]);

Pack the text widget as well as the scrollbar widget, positioning them nicely. For example:

$scroll_text->pack(-side=>"right", -expand => "no", -fill => "y"); $main_text->pack(-side => "left", -anchor => "w", -expand => "yes", -fill => "both");

Putting it all together

Now you put together a few of the intermediate widgets in one script. For example:

#!/usr/bin/perl -w use Tk; use strict; my $ver = "1.0.0"; my $mw = MainWindow->new; $mw->geometry("500x150"); $mw->title("All-In-One Demo #2"); my $main_menu = $mw->Menu(); $mw->configure(-menu => $main_menu); # give the user a way to exit the script my $file_menu = $main_menu->cascade(-label=>"File", -underline => 0, -tearoff=>0); $file_menu->command(-label=>"Exit", -underline=>0, -command => sub{exit}); # everyone needs a little help my $help_menu = $main_menu->cascade(-label => "Help", -underline => 0, -tearoff => 0); $help_menu->command(-label => "Version", -underline => 0, -command => sub{$mw->messageBox(-message => "Version: $ver", -type => "ok")}); $help_menu->command(-label => "About Program", -underline => 0, -command => \&show_about); my $greeting_frame = $mw->Frame()->pack(-side => "top"); $greeting_frame->Label(-text => "Tell me a little about yourself...")->pack(); my $info_frame = $mw->Frame()->pack(-side => "top"); my $last_name = $info_frame->Entry()->pack(-side => "right"); $info_frame->Label(-text => "Last Name")->pack(-side => "right"); my $stat = "Mr"; $info_frame->Radiobutton(-text => "Mr", -value => "Mr", -variable => \$stat)->pack(-side => "right"); $info_frame->Radiobutton(-text => "Mrs", -value => "Mrs", -variable => \$stat)->pack(-side => "right"); $info_frame->Radiobutton(-text => "Miss", -value => "Miss", -variable => \$stat)->pack(-side => "right"); my $pet_info_frame = $mw->Frame()->pack(-side => "top"); $pet_info_frame->Label(-text => "Check all pets you like?")->pack(-side => "left"); my $chk1 = "no"; my $chk2 = "no"; my $chk3 = "no"; my $chk4 = "no"; my $chk5 = "no"; my $pet1_chk = $pet_info_frame->Checkbutton(-text => "Cat", -variable => \$chk1, -onvalue => "yes", -offvalue => "no")->pack(-side => "right"); my $pet2_chk = $pet_info_frame->Checkbutton(-text => "Dog", -variable => \$chk2, -onvalue => "yes", -offvalue => "no")->pack(-side => "right"); my $pet3_chk = $pet_info_frame->Checkbutton(-text => "Fish", -variable => \$chk3, -onvalue => "yes", -offvalue => "no")->pack(-side => "right"); my $pet4_chk = $pet_info_frame->Checkbutton(-text => "Snake", -variable => \$chk4, -onvalue => "yes", -offvalue => "no")->pack(-side => "right"); my $pet5_chk = $pet_info_frame->Checkbutton(-text => "Hamster", -variable => \$chk5, -onvalue => "yes", -offvalue => "no")->pack(-side => "right"); my $button_frame = $mw->Frame()->pack(-side => "top"); $button_frame->Button(-text => "Ok", -command => \&update_output)->pack(); my $output_frame = $mw->Frame()->pack(-side => "bottom"); my $output_scroll = $output_frame->Scrollbar(); my $output_text = $output_frame->Text(-yscrollcommand => ['set', $output_scroll]); $output_scroll->configure(-command => ['yview', $output_text]); $output_scroll->pack(-side => "right", -expand => "no", -fill => "y"); $output_text->pack(); sub update_output { my $lname = $last_name->get(); if ($lname eq "") { $lname = "No Name"; } my $output = "Hello $stat. $lname!

I like the following too!"; if ( $chk1 eq "yes" ) { $output = "$output

Cats"; } if ( $chk2 eq "yes" ) { $output = "$output

Dogs"; } if ( $chk3 eq "yes" ) { $output = "$output

Fish"; } if ( $chk4 eq "yes" ) { $output = "$output

Snakes"; } if ( $chk5 eq "yes" ) { $output = "$output

Hamsters"; } $output_text->delete('0.0', 'end'); $output_text->insert("end", $output); } sub show_about { my $help_win = $mw->Toplevel; $help_win->geometry("300x50"); $help_win->title("About Program"); my $help_msg = "This help page is an example of using multiple windows."; $help_win->Label(-text => $help_msg)->pack(); $help_win->Button(-text => "Ok", -command => [$help_win => 'destroy'])->pack(); } MainLoop;

Running the script generates the GUI application shown in Figure 11.

Figure 11. All the described widgets, in one example

Conclusion

Introducing Perl with the Perl/Tk module into an AIX environment can benefit the developer, administrator, and end user. What begins as a script that may look dull to the customer can be enhanced into a professional-looking GUI application. It might take a little while to get the hang of the widgets, but once you've mastered them, you'll agree that the results are worth the effort and time!

Downloadable resources

Related topics