UserGuide(3pm)
πΈ NAME πΈ
Tk::UserGuide β writing Tk applications in Perl 5 π
β¨ bestie, you're reading UserGuide(3pm) β it lives in the User Contributed Perl Documentation, section 3pm, iykyk β¨
π DESCRIPTION π
Ok so this one's for beginners, no gatekeeping here. It assumes you know some Perl, and that you've got Perl and Tk up and running. π«Ά
If you're not currently reading this doc as a lil bonus from the widget demonstration program, pls pls pls go run widget β it'll show you all the different widget types Tk supports and how to actually use them. widget should be installed in your default path, so just type widget at a command prompt and go off. π
Here are links to other novice tutorials, if you want the extended lore:
And Mastering Perl/Tk is the definitive book on Perl/Tk, fr fr:
π«§ Some Background π«§
Tk GUI programming is event-driven. (Maybe you already knew that β if so, slay.) π
In event-driven programs, the main GUI loop is not chilling inside your user program β it lives outside, inside the GUI library itself. That loop gets kicked off when you call MainLoop, and it watches all the events it cares about and activates the correct handler procedures to deal with them. Some of those handler procedures are ones you supply; others are just part of the library. π§
So as a programmer, this means you're not sitting there watching what's happening. Instead, the toolkit comes to you and asks you to do stuff whenever it's needed. You're not out here watching for 'raise window / close window / redraw window' requests β nah. You just tell the toolkit which routine handles those cases, and the toolkit calls those procedures when it needs them. Those procedures are called callbacks, and some of them you write yourself. periodt. π
β¨ First Requirements β¨
Perl programs that use Tk need to include use Tk. A program should also use use strict and the -w switch, so you can make sure it's working without those common lil errors. π
Every Perl/Tk application starts by creating the Tk MainWindow. Then you create items inside that MainWindow, and/or create new windows called Toplevels that also contain child items β and then you start the MainLoop, which is the last logical statement in your program. You can also create more items and windows while you're running, using callbacks. π₯
Items only get shown on the display after they've been arranged by a geometry manager like pack β more on that later, bestie. MainLoop starts the GUI and handles all the events. That's literally all there is to it! π
A trivial one-window example, coming right up:
#!/usr/bin/perl -w
use Tk;
use strict;
my $mw = MainWindow->new;
$mw->Label(-text => 'Hello, world!')->pack;
$mw->Button(
-text => 'Quit',
-command => sub { exit },
)->pack;
MainLoop;
Please run this example, okay? It shows you two widget types β a Label and a Button β and how they're packed. When you click it, the Button widget invokes the callback specified by the -command option. And finally, notice the classic Tk style using -option => value pairs. β¨
π· Widget creation π·
Tk windows and widgets are hierarchical β i.e. one window includes one or more other windows. πͺ
You create the very first Tk window using MainWindow->new. This returns a window handle, assigned to $mw in the example above. Keep track of that main handle β it's commonly called a widget reference. π
You can use any Tk handle to create child widgets inside the window (or widget). You do this by calling the Tk constructor method on the variable. In the example above, the Label method called from $mw creates a Label widget inside the MainWindow. In that constructor call you can specify various options, and you can add or change options for any widget later using the configure method β which takes the same parameters as the constructor. π
The one exception to the hierarchical structure is the Toplevel constructor, which creates a brand-new outermost window. π
After you create any widget (other than the MainWindow or Toplevels), you must render it by calling pack. (This is not entirely true β more later.) If you don't need to refer to the widget after constructing and packing it, just call pack off the constructor results, like it's shown for the Label and Button in the example above. Note that the result of that compound call is the result of pack, which is a valid Tk handle. π
Windows and widgets get deleted by calling destroy on them β this deletes and un-draws the widget and all its children. π
π Standard Tk widgets π
Here's an itemize of the standard Tk widget set:
ButtonCanvasCheckbuttonEntryFrameLabelLabelframeListboxMenuMenubuttonMessagePanedwindowRadiobuttonScaleScrollbarSpinboxTextToplevel
And Perl/Tk provides an equal number of new widgets, above and beyond this core set:
AdjusterBalloonBrowseEntryColorEditorDialogDialogBoxDirTreeErrorDialogFBoxFileSelectHListLabEntryLabFrameNoteBookOptionmenuPaneProgressBarROTextTableTextUndoTilerTListTree
π¦ Variables and callback routines π¦
Most graphical interfaces get used to set up a bunch 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, because you do not collect the settings yourself and then decide on an action based on an input code. Instead, you leave those values to your toolkit, and you only get them when the action is performed. β¨
So where a traditional text-based system would look like this:
#!/usr/bin/perl -w
use strict;
print "Please type a font name\n";
my $font = <>; chomp $font;
# Validate font
print "Please type a file name\n";
my $filename = <>; chomp $filename;
# Validate filename
print "Type <1> to fax, <2> to print\n";
my $option = <>; chomp $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 in Tk. Note the use of callbacks. Also note that Tk handles the values, and the subroutine uses the method get to get at those values. And if a user changes their mind and wants to change the font again, the application never even notices β it's all handled by Tk. π
#!/usr/bin/perl -w
use Tk;
use strict;
my $mw = MainWindow->new;
$mw->Label(-text => 'File Name')->pack;
my $filename = $mw->Entry(-width => 20);
$filename->pack;
$mw->Label(-text => 'Font Name')->pack;
my $font = $mw->Entry(-width => 10);
$font->pack;
$mw->Button(
-text => 'Fax',
-command => sub{do_fax($filename, $font)}
)->pack;
$mw->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 $font_val\n";
}
sub do_print {
my ($file, $font) = @_;
my $file_val = $file->get;
my $font_val = $font->get;
print "Sending file $file_val to printer in font $font_val\n";
}
π The packer - grouping with Frame widgets π
In the examples above you must have noticed all the pack calls. This is one of the more complicated parts of Tk, ngl. π
The basic idea is that any window or widget should be subject to a Tk geometry manager. The packer is one of the placement managers, and grid is another one. π
The actions of the packer are pretty simple: when you apply it to a widget, the packer positions that widget at the indicated position within the remaining space in its parent. By default, the position is on top β which means the next items get put below. You can also specify the left, right, or bottom positions. You specify the position using -side => 'right'. π
Additional packing parameters specify how the widget behaves when there's some space left in the Frame, or when the window size gets increased:
- If widgets should keep a fixed size, specify nothing β that's the default.
- For widgets you want to fill up the current horizontal and/or vertical space, specify
-fill => 'x','y', or'both'. - For widgets that should grow, specify
-expand => 1.
These parameters are not shown in the example below; go check the widget demonstration for that. π
If you want to group some items within a window that have a different packing order than the others, you can put them inside a Frame. It's a do-nothing window type that's meant for packing or filling (and for playing games with borders and colors). π¨
The example below shows the use of pack and Frames:
#!/usr/bin/perl -w
use Tk;
use strict;
# Take top and the bottom - now implicit top is in the middle
my $mw = MainWindow->new;
$mw->title( 'The MainWindow' );
$mw->Label(-text => 'At the top (default)')->pack;
$mw->Label(-text => 'At the bottom')->pack(-side => 'bottom');
$mw->Label(-text => 'The middle remains')->pack;
# Since left and right are taken, bottom will not work...
my $top1 = $mw->Toplevel;
$top1->title( 'Toplevel 1' );
$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 = $mw->Toplevel;
$top2->title( 'Toplevel 2' );
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;
β¨ More than one window β¨
Okay so bestie, most real apps are NOT one-window wonders. You need more than one window, and you can create extra outermost windows with a Toplevel widget. Each window is independent; destroying a Toplevel window does not affect the others as long as they are not a child of the closed Toplevel. BUT β exiting the MainWindow will destroy all remaining Toplevel widgets and end the application. Periodt. The example below shows a trivial three-window application:
#!/usr/bin/perl -w
use Tk;
use strict;
my $mw = MainWindow->new;
fill_window($mw, 'Main');
my $top1 = $mw->Toplevel;
fill_window($top1, 'First top-level');
my $top2 = $mw->Toplevel;
fill_window($top2, 'Second top-level');
MainLoop;
sub fill_window {
my ($window, $header) = @_;
$window->Label(-text => $header)->pack;
$window->Button(
-text => 'close',
-command => [$window => 'destroy']
)->pack(-side => 'left');
$window->Button(
-text => 'exit',
-command => [$mw => 'destroy']
)->pack(-side => 'right');
}
π 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. No cap.
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/perl -w
use Tk;
use strict;
my $mw = MainWindow->new;
my $box = $mw->Listbox(
-relief => 'sunken',
-height => 5,
-setgrid => 1,
);
my @items = qw(One Two Three Four Five Six Seven
Eight Nine Ten Eleven Twelve);
foreach (@items) {
$box->insert('end', $_);
}
my $scroll = $mw->Scrollbar(-command => ['yview', $box]);
$box->configure(-yscrollcommand => ['set', $scroll]);
$box->pack(-side => 'left', -fill => 'both', -expand => 1);
$scroll->pack(-side => 'right', -fill => 'y');
MainLoop;
Note that there's a convenience method Scrolled which helps constructing widgets with automatically managed scrollbars. iykyk π
π¨ Canvases and tags π¨
One of the most powerful widgets 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 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 bind actions to tags. For a properly designed (often structured) Canvas, you can specify powerful actions quite simply. Main character energy tbh.
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/perl -w
use Tk;
use strict;
# Create B<MainWindow> and canvas
my $mw = MainWindow->new;
my $canvas = $mw->Canvas;
$canvas->pack(-expand => 1, -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";
}
π Perl/Tk and Unicode π
Perl/Tk follows Perl's model of handling Unicode. That is, if a string is correctly flagged as a "character" string in the sense like described in "TERMINOLOGY" in Encode, then Perl/Tk will very probably display and handle this string correctly. Slay.
Note that every variable which is passed somehow into a Perl/Tk method will be implicitely changed into an internally utf8-flagged variable. Semantically nothing changes, as the series of codepoints stays the same, but things will change when variables with high-bit iso-8859-1 characters will be passed to the "outer" world. In this case you have to explicitly mark the encoding of your output stream if using IO, or encode the variables using Encode for other style of communication. This is important, bestie.
This is the theory, now some examples.
If you use non-iso-8859-1 characters in the source code, then use either the "use utf8;" or "use encoding 'encodingname'" pragma:
use utf8;
use Tk;
my $x = "some characters using utf8 encoding";
tkinit->Label(-text => $x)->pack;
MainLoop;
For data that comes from a file you have to specify the encoding unless it's encoded as ascii or iso-8559-1:
use Tk;
open my $FH, "<:encoding(utf-8)", "filename" or die $!;
# or for utf-16 data: open my $FH, "<:encoding(utf-16)", "filename" or die $!;
my $data = <$FH>;
tkinit->Label(-text => $data)->pack;
MainLoop;
Likewise, the encoding must be specified for all data which is read from Tk widgets and that shall be output into a file. For the output, the encoding should be always specified, even if it is iso-8859-1:
use Tk;
$mw = tkinit;
$mw->Entry(-textvariable => \$input)->pack;
$mw->Button(
-text => "Write to file",
-command => sub {
open my $FH, ">:encoding(iso-8859-1)", "filename" or die $!;
print $FH $input;
},
)->pack;
MainLoop;
Note that Tk is Unicode-capable. So you need to be prepared that the user has the appropriate input methods activated to enter non-ascii characters. If an output encoding is used which does not cover the whole of Unicode codepoints then a warning will be issued when writing the file, like this:
"\x{20ac}" does not map to iso-8859-1 at /usr/local/lib/perl5/site_perl/5.8.8/mach/Tk.pm line 250.
Also, the same hexadecimal notation will be used as replacements for the unhandled characters.
Handling encoding in I/O is pretty simple using the "encoding" PerlIO layer, as described above. In other cases, such as when dealing with databases, encoding the data usually has to be done manually, unless the database driver has some means for automatically do this for you. So when working with a MySQL database, one could use:
use Tk;
use DBI;
use Encode qw(encode);
$mw = tkinit;
$mw->Entry(-textvariable => \$input)->pack;
$mw->Button(
-text => "Write to database",
-command => sub {
my $dbh = DBI->connect("dbi:mysql:test", "root", "") or die;
my $encoded_input = encode("iso-8859-1", $input);
$dbh->do("INSERT INTO testtable VALUES (?)", undef, $encoded_input) or die;
},
)->pack;
MainLoop;
Unfortunately, there are still places in Perl ignorant of Unicode. One of these places are filenames. Consequently, the file selectors in Perl/Tk do not handle encoding of filenames properly. Currently they suppose that filenames are in iso-8859-1 encoding, at least on Unix systems. As soon as Perl has a concept of filename encodings, then Perl/Tk will also implement such schemes. It's giving "we'll fix it when Perl does" energy. π
That's the whole vibe! This page was perl v5.40.1, dated 2025-04-13, and it's UserGuide(3pm). Bye bestie! πβ¨π¦
π¦ where this page comes from
- debian trixie: perl-tk 1:804.036+dfsg1-5
- ubuntu questing: perl-tk 1:804.036+dfsg1-5
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms