 | Level: Intermediate Adam Cormany (acormany@yahoo.com), UNIX Systems Engineer, Scientific Games Corporation
27 Nov 2007 Although Perl-based Web interfaces have limitations, Perl is one of
the most commonly used Web development languages. UNIX® users who have a
programming background in shell scripting, Perl, or another language can breathe new
life into Perl-based Web interfaces by using the Perl/Tk module. In this second article of the
series, learn about intermediate widgets, including radiobutton, checkbutton, menu, menubutton, and
scrollbar.
Introduction
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:
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:
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:
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":
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\nCheck #2: $check2\nCheck #3: $check3";
$mw->messageBox(-message => "Check Button Summary:\n$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\nCheck #2: $check2\nCheck #3: $check3";
$mw->messageBox(-message => "Check Button Summary:\n$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!\nI like the following too!";
if ( $chk1 eq "yes" ) { $output = "$output\nCats"; }
if ( $chk2 eq "yes" ) { $output = "$output\nDogs"; }
if ( $chk3 eq "yes" ) { $output = "$output\nFish"; }
if ( $chk4 eq "yes" ) { $output = "$output\nSnakes"; }
if ( $chk5 eq "yes" ) { $output = "$output\nHamsters"; }
$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!
Resources Learn
Get products and technologies
- Download
a useful Perl/tk module
tutorial provided by Brett Berry and Lee Minniear.
-
Perl: You can download the latest
version here.
-
ActivePerl:
ActiveState offers a free and ready-to-install Perl distribution for Windows®, Mac,
OS X, Linux®, Solaris, AIX, and HP-UX.
-
IBM trial software:
Build your next development project with software for download directly from
developerWorks.
Discuss
-
developerWorks
blogs:
Get involved in the developerWorks community.
- Participate in the AIX and UNIX forums:
About the author  | |  | Adam Cormany is an UNIX systems engineer and has worked with AIX, Solaris, and Red Hat Linux administration for more than 10 years. He is an IBM eServer® Certified Specialist in pSeries® AIX System Administration. In addition to administration, Adam has extensive knowledge of shell scripting in BASH, CSH, and KSH, as well as programming in C, PHP, and Perl. |
Rate this page
|  |