home *** CD-ROM | disk | FTP | other *** search
- =head1 NAME
-
- perl/Tk - Writing Tk applications in perl5.
-
- =head1 DESCRIPTION
-
- This manual page is for beginners. It assumes you know some perl,
- and have got perl+Tk running.
- Please run the 'widget' demo before reading this text; it will teach you
- the various widget types supported by Tk.
-
- =head1 Some background
-
- Tk GUI programming is event-driven. (This may already be familiar to you.)
- In event-driven programs, the main GUI loop is outside of the user program
- and inside the GUI library. This loop will watch all events of interest,
- and activate the correct handler procedures to handle these events.
- Some of these handler procedures may be user-supplied; others will be part
- of the library.
-
- For a programmer, this means that you're not watching what is happening;
- instead, you are requested by the toolkit to perform actions whenever
- necessary.
- So, you're not watching for 'raise window / close window / redraw window'
- requests, but you tell the toolkit which routine will handle such cases,
- and the toolkit will call the procedures when required.
-
- =head1 First requirements
-
- Any perl program that uses Tk needs to include C<use Tk>.
- A program should also use C<use strict> and the B<-w> switch to ensure
- the program is working without common errors.
-
- Any Tk application starts by creating the Tk main window. You then create
- items inside the main window, or create new windows, before starting the
- mainloop.
- (You can also create more items and windows while you're running.)
- The items will be shown on the display after you C<pack> them;
- more info on this later.
- Then you do a Tk mainloop; this will start the GUI and handle all events.
- That's your application.
- A trivial one-window example is show below:
-
- #! /usr/bin/perl5 -w
-
- use strict;
- use Tk;
-
- my $main = new MainWindow;
- $main->Label(-text => 'Hello, world!')->pack;
- $main->Button(-text => 'Quit',
- -command => sub{exit}
- )->pack;
- MainLoop;
-
- Please run this example. It shows you two items types also shown in the
- widget demo; it also shows you how items are created and packed.
- Finally, note the typical Tk style using C<-option> =E<gt> C<value> pairs.
-
- =head1 Item creation
-
- Tk windows and widgets are hierarchical, S<i.e. one> includes one or more
- others. You create the first Tk window using C<new MainWindow>.
- This returns a window handle, assigned to C<$main> in the example above.
- Keep track of the main handle.
-
- You can use any Tk handle to create sub-items within the window or widget.
- This is done by calling the Tk constructor method on the variable.
- In the example above, the C<Label> method called from C<$main> creates a
- label widget inside the main window. In the constructor call, you can specify
- various options; you can later add or change options for any widget
- using the C<configure> method, which takes the same parameters as the
- constructor.
- The one exception to the hierarchical structure is the C<Toplevel> constructor,
- which creates a new outermost window.
-
- After you create any widget, you must render it by calling C<pack>. (This
- is not entirely true; more info later). If you do not need to refer to
- the widget after construction and packing, call C<pack> off the constructor
- results, as shown for the label and button in the example above.
- Note that the result of the compound call is the result of C<pack>,
- which is not a valid Tk handle.
-
- Windows and widgets are deleted by calling C<destroy> on them;
- this will delete and un-draw the widget and all its children,
- with the exception of Toplevel windows.
-
- =head1 Standard Tk types
-
- =over 4
-
- =item Button
-
- =item Radiobutton
-
- =item Checkbutton
-
- =item Listbox
-
- =item Scrollbar
-
- =item Entry
-
- =item Text
-
- =item Canvas
-
- =item Frame
-
- =item Toplevel
-
- =item Scale
-
- =item Menu
-
- =item Menubutton
-
- =back
-
-
- =head1 Variables and callback routines
-
- Most graphical interfaces are used to set up a set of values and conditions,
- and then perform the appropriate action. The Tk toolkit is different
- from your average text-based prompting or menu driven system in that you do
- not collect settings yourself, and decide on an action based on an
- input code; instead, you leave these
- values to your toolkit and only get them when the action is performed.
-
- So, where a traditional text-based system would look like this:
- (yes, this is obviously dumb code)
-
- #! /usr/bin/perl5 -w
-
- use strict;
-
- print "Please type a font name\n";
- my $font = <>; chop $font;
- # Validate font
-
- print "Please type a file name\n";
- my $filename = <>; chop $filename;
- # Validate filename
-
- print "Type <1> to fax, <2> to print\n";
- my $option = <>; chop $option;
- if ($option eq 1) {
- print "Faxing $filename in font $font\n";
- } elsif ($option eq 2) {
- print "Now sending $filename to printer in font $font\n";
- }
-
- The (slightly larger) example below shows how to do this is Tk.
- Note the use of callbacks. Note, also, that Tk handles the values, and
- the subroutine uses C<get> to get at the values.
- If a user changes his mind and wants to change the font again,
- the application never notices; it's all handled by Tk.
-
- #! /usr/bin/perl5 -w
-
- use strict;
- use Tk;
-
- my $main = new MainWindow;
- $main->Label(-text => 'Print file')->pack;
- my $font = $main->Entry(-width => 10);
- $font->pack;
- my $filename = $main->Entry(-width => 10);
- $filename->pack;
- $main->Button(-text => 'Fax',
- -command => sub{do_fax($filename, $font)}
- )->pack;
- $main->Button(-text => 'Print',
- -command => sub{do_print($filename, $font)}
- )->pack;
- MainLoop;
-
- sub do_fax {
- my ($file, $font) = @_;
- my $file_val = $file->get;
- my $font_val = $font->get;
- print "Now faxing $file_val in $font_val\n";
- }
-
- sub do_print {
- my ($file, $font) = @_;
- $file = get $file;
- $font = get $font;
- print "Sending file $file to printer in $font\n";
- }
-
-
- =head1 The packer. Grouping and frames.
-
- In the examples above, you must have noticed the C<pack> calls.
- This is one of the more complicated parts of Tk. The basic idea
- is that any window or widget should be subject to a Tk widget placement manager;
- the I<packer> is the most useful placement manager.
-
- The actions of the packer are rather simple: when applied
- to a widget, the packer positions that widget on the indicated position
- within the remaining space in its parent. By default, the position is
- on top; this means the next items will be put below. You can also
- specify the left, right, or bottom positions. Specify position
- using B<-side =E<gt> 'right'>.
-
- Additional packing parameters specify the behavior of the widget when
- there is some space left in the frame or when the window size is
- increased. If widgets should maintain a fixed size, specify nothing;
- this is the default. For widgets that you want to fill up the current
- horizontal space, specify B<-fill =E<gt> 'x'>, B<y>, or B<both>; for
- widgets that should grow, specify B<-expand =E<gt> 'yes'>. These
- parameters are not shown in the example below; see the widget demo.
-
- If you want to group some items within a window that have a different
- packing order than others, you can include them in a Frame. This is a
- do-nothing window type that is meant for packing (and to play games
- with borders and colors).
-
- The example below shows the use of pack and frames:
-
- #! /usr/bin/perl5 -w
-
- use strict;
- use Tk;
-
- # Take top, the bottom -> now implicit top is in the middle
- my $main = new MainWindow;
- $main->Label(-text => 'At the top (default)')->pack;
- $main->Label(-text => 'At the bottom')->pack(-side => 'bottom');
- $main->Label(-text => 'The middle remains')->pack;
-
- # Since left and right are taken, bottom will not work...
- my $top1 = $main->Toplevel;
- $top1->Label(-text => 'Left')->pack(-side => 'left');
- $top1->Label(-text => 'Right')->pack(-side => 'right');
- $top1->Label(-text => '?Bottom?')->pack(-side => 'bottom');
-
- # But when you use frames, things work quite alright
- my $top2 = $main->Toplevel;
- my $frame = $top2->Frame;
- $frame->pack;
- $frame->Label(-text => 'Left2')->pack(-side => 'left');
- $frame->Label(-text => 'Right2')->pack(-side => 'right');
- $top2->Label(-text => 'Bottom2')->pack(-side => 'bottom');
-
- MainLoop;
-
- =head1 More than one window
-
- Most real applications require more than one window. As you read before,
- you can create more outermost windows by using Toplevel. Each window
- is independent; exiting a toplevel window does not affect the others.
- Exiting the main window will end the application.
- The example below shows a trivial three-window application:
-
- #! /usr/bin/perl5 -w
-
- use strict;
- use Tk;
-
- my $main = new MainWindow;
- fill_window($main, 'Main');
- my $top1 = $main->Toplevel;
- fill_window($top1, 'First top-level');
- my $top2 = $main->Toplevel;
- fill_window($top2, 'Second top-level');
- MainLoop;
-
- sub fill_window {
- my ($window, $header) = @_;
- $window->Label(-text => $header)->pack;
- $window->Button(-text => 'close',
- -command => sub{destroy $window}
- )->pack(-side => 'left');
- $window->Button(-text => 'exit',
- -command => sub{exit}
- )->pack(-side => 'right');
- }
-
-
-
- =head1 More callbacks
-
- So far, all callback routines shown called a user procedure.
- You can also have a callback routine call another Tk routine.
- This is the way that scroll bars are implemented: scroll-bars
- can call a Tk item or a user procedure, whenever their position
- has changed. The Tk item that has a scrollbar attached calls the
- scrollbar when its size or offset has changed. In this way,
- the items are linked. You can still ask a scrollbar's position,
- or set it by hand - but the defaults will be taken care of.
-
- The example below shows a listbox with a scroll bar. Moving
- the scrollbar moves the listbox. Scanning a listbox (dragging
- an item with the left mouse button) moves the scrollbar.
-
- #! /usr/bin/perl5 -w
-
- use strict;
- use Tk;
-
- my $main = new MainWindow;
- my $box = $main->Listbox(-relief => 'sunken',
- -width => -1, # Shrink to fit
- -height => 5,
- -setgrid => 'yes');
- my @items = qw(One Two Three Four Five Six Seven
- Eight Nine Ten Eleven Twelve);
- foreach (@items) {
- $box->insert('end', $_);
- }
- my $scroll = $main->Scrollbar(-command => ['yview', $box]);
- $box->configure(-yscrollcommand => ['set', $scroll]);
- $box->pack(-side => 'left', -fill => 'both', -expand => 'yes');
- $scroll->pack(-side => 'right', -fill => 'y');
-
- MainLoop;
-
-
- =head1 Canvases and tags
-
- One of the most powerful window types in Tk is the Canvas window.
- In a canvas window, you can draw simple graphics and include
- other widgets. The canvas area may be larger than the visible window,
- and may then be scrolled. Any item you draw on the canvas has its own id,
- and may optionally have one or more I<tags>. You may refer to any
- item by its id, and may refer to any group of items by a common tag;
- you can move, delete, or change groups of items using these tags,
- and you can I<bind> actions to tags. For a properly designed (often
- structured) canvas, you can specify powerful actions quite simply.
-
- In the example below, actions are bound to circles (single click)
- and blue items (double-click); obviously, this can be extended to any
- tag or group of tags.
-
- #! /usr/bin/perl5 -w
-
- use strict;
- use Tk;
-
- # Create main window and canvas
- my $main = new MainWindow;
- my $canvas = $main->Canvas;
- $canvas->pack(-expand => 'yes', -fill => 'both');
-
- # Create various items
- create_item($canvas, 1, 1, 'circle', 'blue', 'Jane');
- create_item($canvas, 4, 4, 'circle', 'red', 'Peter');
- create_item($canvas, 4, 1, 'square', 'blue', 'James');
- create_item($canvas, 1, 4, 'square', 'red', 'Patricia');
-
- # Single-clicking with left on a 'circle' item invokes a procedure
- $canvas->bind('circle', '<1>' => sub {handle_circle($canvas)});
- # Double-clicking with left on a 'blue' item invokes a procedure
- $canvas->bind('blue', '<Double-1>' => sub {handle_blue($canvas)});
- MainLoop;
-
- # Create an item; use parameters as tags (this is not a default!)
- sub create_item {
- my ($can, $x, $y, $form, $color, $name) = @_;
-
- my $x2 = $x + 1;
- my $y2 = $y + 1;
- my $kind;
- $kind = 'oval' if ($form eq 'circle');
- $kind = 'rectangle' if ($form eq 'square');
- $can->create(($kind, "$x" . 'c', "$y" . 'c',
- "$x2" . 'c', "$y2" . 'c'),
- -tags => [$form, $color, $name],
- -fill => $color);
- }
-
- # This gets the real name (not current, blue/red, square/circle)
- # Note: you'll want to return a list in realistic situations...
- sub get_name {
- my ($can) = @_;
- my $item = $can->find('withtag', 'current');
- my @taglist = $can->gettags($item);
- my $name;
- foreach (@taglist) {
- next if ($_ eq 'current');
- next if ($_ eq 'red' or $_ eq 'blue');
- next if ($_ eq 'square' or $_ eq 'circle');
- $name = $_;
- last;
- }
- return $name;
- }
-
- sub handle_circle {
- my ($can) = @_;
- my $name = get_name($can);
- print "Action on circle $name...\n";
- }
-
- sub handle_blue {
- my ($can) = @_;
- my $name = get_name($can);
- print "Action on blue item $name...\n";
- }
-
-