NAME

Tcl::Tk - Extension module for Perl giving access to Tk via the Tcl extension

SYNOPSIS

    use Tcl::Tk;
    my $int = new Tcl::Tk;
    my $mw = $int->mainwindow;
    my $lab = $mw->Label(-text => "Hello world")->pack;
    my $btn = $mw->Button(-text => "test", -command => sub {
        $lab->configure(-text=>"[". $lab->cget('-text')."]");
    })->pack;
    $int->MainLoop;

Or

    use Tcl::Tk;
    my $int = new Tcl::Tk;
    $int->Eval(<<'EOS');
    # pure-tcl code to create widgets (e.g. generated by some GUI builder)
    entry .e
    button .inc -text {increment by Perl}
    pack .e .inc
    EOS
    my $btn = $int->widget('.inc'); # get .inc button into play
    my $e = $int->widget('.e');     # get .e entry into play
    $e->configure(-textvariable=>\(my $var='aaa'));
    $btn->configure(-command=>sub{$var++});
    $int->MainLoop;

DESCRIPTION

The Tcl::Tk module provides access to the Tk library within Tcl/Tk installation. By using this module an interpreter object created, which then gain access to entire variety of installed Tcl libraries (Tk, Tix, BWidgets, BLT, etc) and existing features (for example natively looking widgets using tile).

Prerequisites

For full functionality you need the Tcl packages "snit", which is part of the standard tcl library (see "tcllib" in core.tcl.tk), and the standard tk library (see https://core.tcl.tk/tklib/home).

Having correct installation of snit is much preferred. In case it isn't found - some predefined tcl/snit will be used.

Access to the Tcl and Tcl::Tk extensions

To get access to the Tcl and Tcl::Tk extensions, put the command near the top of your program.

    use Tcl::Tk;

Creating a Tcl interpreter for Tk

Before you start using widgets, an interpreter (at least one) should be created, which will manage all things in Tcl.

To create a Tcl interpreter initialised for Tk, use

    my $int = new Tcl::Tk;

Optionally DISPLAY argument could be specified: my $int = new Tcl::Tk(":5");. This creates a Tcl interpreter object $int, and creates a main toplevel window. The window is created on display DISPLAY (defaulting to the display named in the DISPLAY environment variable)

The Tcl/Tk interpreter is created automatically by the call to MainWindow and tkinit methods, and main window object is returned in this case:

  use Tcl::Tk;
  my $mw = Tcl::Tk::MainWindow;
  my $int = $mw->interp;

Entering the main event loop

The Perl method call

    $int->MainLoop;

on the Tcl::Tk interpreter object enters the Tk event loop. You can instead do Tcl::Tk::MainLoop or Tcl::Tk->MainLoop if you prefer. You can even do simply MainLoop if you import it from Tcl::Tk in the use statement.

Creating and using widgets

Two different approaches are used to manipulate widgets (or, more commonly, to manipulate any Tcl objects behaving similarly)

  • access with a special widget accessing syntax of kind $widget->method;

  • random access with Eval

First way to manipulate widgets is identical to perl/Tk calling conventions, second one deploys Tcl syntax. Both ways are very interchangeable in that sence, a widget created with one way could be used by another way.

Usually Perl programs operate with Tcl/Tk via perl/Tk syntax, so user have no need to deal with Tcl language directly, only some basic understanding of widget is needed.

A possibility to use both approaches interchangeably gives an opportunity to use Tcl code created elsewhere (some WYSIWIG IDE or such).

In order to get better understanding on usage of Tcl/Tk widgets from within Perl, a bit of Tcl/Tk knowledge is needed, so we'll start from 2nd approach, with Tcl's Eval ($int->Eval('...')) and then smoothly move to 1st, approach with perl/Tk syntax.

Tcl/Tk syntax

  • interpreter

    Tcl interpreter is used to process Tcl/Tk widgets; within Tcl::Tk you create it with new, and, given any widget object, you can retreive it by $widget->interp method. Within pure Tcl/Tk it is already exist.

  • widget path

    Widget path is a string starting with a dot and consisting of several names separated by dots. These names are widget names that comprise widget's hierarchy. As an example, if there exists a frame with a path .fram and you want to create a button on it and name it butt then you should specify name .fram.butt. Widget paths are refered in miscellaneous widget operations, and geometry management is one of them.

    At any time widget's path could be retreived with $widget->path; within Tcl::Tk.

  • widget as Tcl/Tk command

    when widget is created, a special command is created within Tk, the name of this command is widget's path. That said, .fr.b is Tk's command and this command has subcommands, those will help manipulating widget. That is why $int->Eval('.fr.b configure -text {new text}'); makes sence. Note that $button->configure(-text=>'new text'); does exactly that, provided a fact $button corresponds to .fr.b widget.

use Tcl::Tk; not only creates Tcl::Tk package, but also it creates Tcl::Tk::Widget package, responsible for widgets. Each widget (object blessed to Tcl::Tk::Widget, or other widgets in ISA-relationship) behaves in such a way that its method will result in calling it's path on interpreter.

Perl/Tk syntax

Tcl::Tk::Widget package within Tcl::Tk module fully aware of perl/Tk widget syntax, which has long usage. This means that any Tcl::Tk widget has a number of methods like Button, Frame, Text, Canvas and so on, and invoking those methods will create appropriate child widget. Tcl::Tk module will generate an unique name of newly created widget.

To demonstrate this concept:

    my $label = $frame->Label(-text => "Hello world");

executes the command

    $int->call("label", ".l", "-text", "Hello world");

and this command similar to

    $int->Eval("label .l -text {Hello world}");

This way Tcl::Tk widget commands are translated to Tcl syntax and directed to Tcl interpreter; understanding this helps in idea, why two approaches with dealing with widgets are interchangeable.

Newly created widget $label will be blessed to package Tcl::Tk::Widget::Label which is isa-Tcl::Tk::Widget

OO explanations of Widget-s of Tcl::Tk

Tcl::Tk widgets use object-oriented approach, which means a quite concrete object hierarchy presents. Interesting point about this object system - it is very dynamic. Initially no widgets objects and no widget classes present, but they immediately appear at the time when they needed.

So they virtually exist, but come into actual existence dynamically. This dynamic approach allows same usage of widget library without any mention from within Tcl::Tk module at all.

Let us look into following few lines of code:

  my $text = $mw->Text->pack;
  $text->insert('end', -text=>'text');
  $text->windowCreate('end', -window=>$text->Label(-text=>'text of label'));

Internally, following mechanics comes into play. Text method creates Text widget (known as text in Tcl/Tk environment). When this creation method invoked first time, a package Tcl::Tk::Widget::Text is created, which will be OO presentation of all further Text-s widgets. All such widgets will be blessed to that package and will be in ISA-relationship with Tcl::Tk::Widget.

Second line calls method insert of $text object of type Tcl::Tk::Widget::Text. When invoked first time, a method insert is created in package Tcl::Tk::Widget::Text, with destiny to call invoke method of our widget in Tcl/Tk world.

At first time when insert is called, this method does not exist, so AUTOLOAD comes to play and creates such a method. Second time insert called already existing subroutine will be invoked, thus saving execution time.

As long as widgets of different type 'live' in different packages, they do not intermix, so insert method of Tcl::Tk::Widget::Listbox will mean completely different behaviour.

explanations how Widget-s of Tcl::Tk methods correspond to Tcl/Tk

Suppose $widget isa-Tcl::Tk::Widget, its path is .path and method method invoked on it with a list of parameters, @parameters:

  $widget->method(@parameters);

In this case as a first step all @parameters will be preprocessed, during this preprocessing following actions are performed:

  1. for each variable reference its Tcl variable will be created and tied to it

  2. for each code reference its Tcl command will be created and tied to it

  3. each array reference considered as callback, and proper actions will be taken

After adoptation of @parameters Tcl/Tk interpreter will be requested to perform following operation:

if $method is all lowercase, m/^[a-z]$/

.path method parameter1 parameter2 ....

if $method contains exactly one capital letter inside name, m/^[a-z]+[A-Z][a-z]+$/

.path method submethod parameter1 parameter2 ....

if $method contains several capital letter inside name, methodSubmethSubsubmeth

.path method submeth subsubmeth parameter1 parameter2 ....

faster way of invoking methods on widgets

In case it is guaranteed that preprocessing of @parameters are not required (in case no parameters are Perl references to scalar, subroutine or array), then preprocessing step described above could be skipped.

To achieve that, prepend method name with underscore, _. Mnemonically it means you are using some internal method that executes faster, but normally you use "public" method, which includes all preprocessing.

Example:

   # at following line faster method is incorrect, as \$var must be
   # preprocessed for Tcl/Tk:
   $button->configure(-textvariable=>\$var);

   # faster version of insert method of "Text" widget is perfectly possible
   $text->_insert('end','text to insert','tag');
   # following line does exactly same thing as previous line:
   $text->_insertEnd('text to insert','tag');

When doing many inserts to text widget, faster version will make execution faster.

using any Tcl/Tk feature with Tcl::Tk module

Tcl::Tk module allows using any widget from Tcl/Tk widget library with either Tcl syntax (via Eval), or with regular Perl syntax.

In order to provide perlTk syntax to any Tcl/Tk widget, only single call should be made, namely 'Declare' method. This is a method of any widget in Tcl::Tk::Widget package, and also exactly the same method of Tcl::Tk interpreter object

Syntax is

 $widget->Declare('perlTk_widget_method_name','tcl/tk-widget_method_name',
    @options);

or, exactly the same,

 $interp->Declare('perlTk_widget_method_name','tcl/tk-widget_method_name',
    @options);
 

Options are:

  -require => 'tcl-package-name'
  -prefix => 'some-prefix'

'-require' option specifies that said widget requires a Tcl package with a name of 'tcl-package-name'; '-prefix' option used to specify a part of autogenerated widget name, usually used when Tcl widget name contain non-alphabet characters (e.g. ':') so to keep autogenerated names syntaxically correct.

A typical example of such invocation is:

  $mw->Declare('BLTNoteBook','blt::tabnotebook',-require=>'BLT',-prefix=>'bltnbook');

After such a call Tcl::Tk module will take a knowledge about tabnotebook widget from within BLT package and create proper widget creation method for it with a name BLTNoteBook. This means following statement:

 my $tab = $mw->BLTNoteBook;

will create blt::tabnotebook widget. Effectively, this is similar to following Tcl/Tk code:

  package require BLT # but invoked only once
  blt::tabnotebook .bltnbook1

Also, Perl variable $tab will contain ordinary Tcl/Tk widget that behaves in usual way, for example:

  $tab->insert('end', -text=>'text');
  $tab->tabConfigure(0, -window=>$tab->Label(-text=>'text of label'));

These two lines are Tcl/Tk equivalent of:

  .bltnbook1 insert end -text {text}
  .bltnbook1 tab configure 0 -window [label .bltnbook1.lab1 -text {text of label}]

Given all previously said, you can also write intermixing both approaches:

  $interp->Eval('package require BLT;blt::tabnotebook .bltnbook1');
  $tab = $interp->widget('.bltnbook1');
  $tab->tabConfigure(0, -window=>$tab->Label(-text=>'text of label'));

using documentation of Tcl/Tk widgets for applying within Tcl::Tk module

As a general rule, you need to consult TCL man pages to realize how to use a widget, and after that invoke perl command that creates it properly. When reading Tcl/Tk documentation about widgets, quite simple transformation is needed to apply to Tcl::Tk module.

Suppose it says:

  pathName method-name optional-parameters
     (some description)
     

you should understand, that widget in question has method method-name and you could invoke it as

  $widget->method-name(optional-parameters);

$widget is that widget with pathName, created with perl/Tk syntax, or fetched by $int->widget method.

Sometimes in Tcl/Tk method-name consist of two words (verb1 verb2), in this case there are two ways to invoke it, $widget->verb1('verb2',...); or it $widget->verb1Verb2(...); - those are identical.

Widget options are same within Tcl::Tk and Tcl/Tk.

$int->widget( path, widget-type ) method

When widgets are created they are stored internally and could be retreived by widget(), which takes widget path as first parameter, and optionally widget type (such as Button, or Text etc.). Example:

    # this will retrieve widget, and then call configure on it
    widget(".fram.butt")->configure(-text=>"new text");

    # this will retrieve widget as Button (Tcl::Tk::Widget::Button object)
    my $button = widget(".fram.butt", 'Button');
    
    # same but retrieved widget considered as general widget, without
    # concrete specifying its type (Tcl::Tk::Widget object)
    my $button = widget(".fram.butt");

Please note that this method will return to you a widget object even if it was not created within this module, and check will not be performed whether a widget with given path exists, despite of fact that checking for existence of a widget is an easy task (invoking $interp->Eval("info commands $path"); will do this). Instead, you will receive perl object that will try to operate with widget that has given path even if such path do not exists. In case it do not actually exist, you will receive an error from Tcl/Tk.

To check if a widget with a given path exists use Tcl::Tk::Exists($widget) subroutine. It queries Tcl/Tk for existence of said widget.

widget_data method

If you need to associate any data with particular widget, you can do this with widget_data method of either interpreter or widget object itself. This method returns same anonymous hash and it should be used to hold any keys/values pairs.

Examples:

  $interp->widget_data('.fram1.label2')->{var} = 'value';
  $label->widget_data()->{var} = 'value';

Non-widget Tk commands

Many non-widget Tk commands are also available within Tcl::Tk module, such as focus, wm, winfo and so on. If some of them not present directly, you can always use $int->Eval('...') approach.

Miscellaneous methods

$widget->tooltip("text") method

Any widget accepts tooltip method, accepting any text as parameter, which will be used as floating help text explaining the widget. The widget itself is returned, so to provide convenient way of chaining:

  $mw->Button(-text=>"button 1")->tooltip("This is a button, m-kay")->pack;
  $mw->Entry(-textvariable=>\my $e)->tooltip("enter the text here, m-kay")->pack;

tooltip method uses tooltip package, which is a part of tklib within Tcl/Tk, so be sure you have it installed.

$int->create_rotext() method

This method creates "rotext" type of widget within Tcl/Tk, which then could be used for example as

  $int->Eval('rotext .ro1');

$int->create_scrolled_widget("widgetname") method

This method creates "scrolled" type of widget for a given widget type within Tcl/Tk. For example:

  $int->create_scrolled_widget("canvas");
  $int->Eval('scrolled_canvas .scanv');

This way you can even create a perl/Tk-style widget to be initially scrollable:

  $int->create_scrolled_widget("text"); # introduce scrolled_text in Tcl/Tk
  $int->Declare('SText','scrolled_text'); # bind scrolled_text to Tcl::Tk as SText
  # now use SText instead of Scrolled('Text',...) everywhere in program
  $int->mainwindow->SText->pack(-fill=>'both');

The scrolling is taken from snit (scrodgets), and the resulting widget have both scrolled options/methods and widget's options/methods.

Points of special care

list context and scalar context

When widget method returns some result, this result becomes transformed according to the context, either list or scalar context. Sometimes this transformation is right, but sometimes its not. Unfortunately there are many cases, when Tcl/Tk returns a string, and this string become broken into words, because the function call is placed in list context.

In such cases concatenate such call with empty string to force right behaviour:

  use Tcl::Tk;
  my $mw = Tcl::Tk::tkinit;
  my $int = $mw->interp;
  my $but = $mw->Button(-text=>'1 2  3')->pack;
  print "[", $but->cget('-text'), "] wrong - widget method returns 3 values!\n";
  print "[", "".$but->cget('-text'), "] CORRECT - 1 value in scalar context\n";
  $int->MainLoop;

Actually, the example above will work correctly, because currently list of function names having list results are maintained. But please contact developers if you find misbehaving widget method!

BUGS

Currently work is in progress, and some features could change in future versions.

AUTHORS

Malcolm Beattie.
Vadim Konovalov, vadim_tcltk@vkonovalov.ru 19 May 2003.
Jeff Hobbs, jeffh _a_ activestate com, February 2004.
Gisle Aas, gisle _a_ activestate . com, 14 Apr 2004.

COPYRIGHT

This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself.

See http://www.perl.com/perl/misc/Artistic.html