NAME

Tcl::pTk - Interface to Tcl/Tk with Perl/Tk compatible syntax

SYNOPSIS

Perl/Tk Compatible Syntax:

use Tcl::pTk;

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

Or Tcl::pTk Synax with direct access to Tcl:

use Tcl::pTk;
my $int = new Tcl::pTk;
$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

Tcl::pTk interfaces perl to an existing Tcl/Tk installation on your computer. It has fully perl/tk (See Tk) compatible syntax for running existing perl/tk scripts, as well as direct-tcl syntax for using any other Tcl/Tk features.

Using this module an interpreter object is created, which then provides access to all the installed Tcl libraries (Tk, Tix, BWidgets, BLT, etc) and existing features (for example native-looking widgets using the Tile package).

Features

  • Perl/Tk compatible syntax.

  • Pure perl megawidgets work just like in perl/tk. See the test case t/slideMegaWidget.t in the source distribution for a simple example.

  • All the perl/tk widget demos work with minimal changes. Typically the only changes needed are just changing the use Tk; to use Tcl::pTk; at the top of the file. See the widgetTclpTk demo script included in the source distribution to run the demos.

  • Built-in local drag-drop support, compatible with perl/tk drag-drop coding syntax.

  • Tcl::pTk::TkHijack package supplied which enables Tcl::pTk to be used with existing Tk Scripts.

  • Similar interface approach to Tcl/Tk that other dynamic languages use (e.g. ruby, python). Because of this approach, upgrades to Tcl/Tk shouldn't require much coding changes (if any) in Tcl::pTk.

  • Tcl::pTk::Facelift package supplied, which provides a quick way of using the new better-looking Tile/ttk widgets in existing code.

  • TableMatrix (spreadsheet/grid Tktable widget, built to emulate the perl/tk Tk::TableMatrix interface ) built into the package (as long as you have the Tktable Tcl/Tk extension installed).

  • Extensive test suite.

  • Compatible with Tcl/Tk 8.4+

Examples

There are many examples in the widgetTclpTk script (This is very simlar to the widget demo installed with perl/tk). After installing the Tcl::pTk package, type widgetTclpTk on the command line to run.

The test cases in the t directory of the source distribution also is a good source of code examples.

Relation to the Tcl::Tk Package

This package (Tcl::pTk) is similar (and much of the code is derived from) the Tcl::Tk package, maintained by Vadim Konovalov. However it differs from the Tcl::Tk package in some important ways:

  • Tcl::pTk

    Emphasis is on 100% compatibility with existing perl/tk syntax.

    For developers with a perl/Tk background and an existing perl/Tk codebase to support. For perl/Tk developers looking to take advantage of the look/feel updates in Tcl/Tk 8.5 and above.

  • Tcl::Tk

    Emphasis is on a lightweight interface to Tcl/Tk with syntax similar to (but not exactly like) perl/tk.

    For developers with some perl/Tk background, writing new code, but no existing perl/Tk codebase to support.

Basic Usage/Operation

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. Creating an interpreter is created automatically by the call to the MainWindow (or tkinit) methods, but can also be created explicitly.

Example showing perl/Tk compatible syntax: For perl/tk syntax, the interpreter is created for you when you create the mainwindow.

use Tcl::pTk;

my $mw = MainWindow->new(); # Create Tcl::pTk interpreter and returns mainwindow widget
my $int = $mw->interp;      # Get the intepreter that was created in the MainWindow call

Example showing explicit creation of an interpreter using Tcl::pTk:

use Tcl::pTk;

my $int = new Tcl::pTk;

Optionally a DISPLAY argument can be specified: my $int = new Tcl::pTk(":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)

Entering the main event loop

Perl/Tk compatible syntax:

MainLoop;  # Exact same syntax used as perl/Tk

Tcl::pTk Syntax:

$inst->MainLoop;

Creating and using widgets

Two different approaches are used to manipulate widgets (or to manipulate any Tcl objects that act similarly to widgets).

  • Perl/Tk compatible-syntax approach. i.e. $widget->method syntax.

  • Direct access using Eval-ed Tcl code. (e.g. using the Eval Tcl::pTk method)

The first way to manipulate widgets is identical to the perl/Tk calling conventions, the second one uses Tcl syntax. Both ways are interchangeable in that a widget created with one way can be used the another way. This interchangability enables use of Tcl-code created elsewhere (e.g. by some WYSIWYG IDE).

Usually Perl programs operate with Tcl::pTk via perl/Tk syntax, so users have no need to deal with the Tcl language directly. Only some basic understanding of Tcl/Tk widgets is needed.

Tcl/Tk syntax

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 first approach with perl/Tk syntax.

  • The Tcl Interpreter

    The Tcl interpreter is used to process Tcl/Tk widgets; within Tcl::pTk you create it with new, and given any widget object, you can retrieve it by the $widget->interp method. ( Within pure Tcl/Tk the interpreter already exists, you don't need to create it explicitly. )

  • The Widget Path

    The Widget path is a string starting with a dot and consisting of several names separated by dots. These names are individual widget-names that comprise a 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 also referred in other miscellaneous widget operations, like geometry management.

    At any time a widget's path can be retrieved with $widget->path; within Tcl::pTk.

  • The Widget Path as a Tcl/Tk command

    When a widget is created in Tcl/Tk, a special command is created that is the name of the widget's path. For example, a button created in a frame has a path and command-name .fr.b. This command also has subcommands which manipulate the widget. That is why $int->Eval('.fr.b configure -text {new text}'); makes sense. Note that using perl/tk syntax $button->configure(-text=>'new text'); does exactly the same thing, if $button corresponds to .fr.b widget.

The use Tcl::pTk; statement not only creates the Tcl::pTk package, but also creates the Tcl::pTk::Widget package, which is responsible for widgets. Each widget ( an object blessed to Tcl::pTk::Widget, or any of its subclasses ) behaves in such a way that its method will result in calling its path on the interpreter.

Perl/Tk syntax

Tcl::pTk fully supports perl/Tk widget syntax of the Tk package, which has been used for many years. This means that any Tcl::pTk widget has a number of methods like Button, Frame, Text, Canvas and so on, and invoking those methods will create an appropriate child widget. Tcl::pTk will generate an unique path-name for a newly created widget.

To demonstrate this concept, the perl/Tk syntax:

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::pTk widget commands are translated to Tcl syntax and directed to the Tcl interpreter. This translation that occurs from perl/Tk syntax to Tcl calls is why the two approaches for dealing with widgets are interchangeable.

The newly created widget $label will be blessed to package Tcl::pTk::Label which is isa-Tcl::pTk::Widget (i.e. Tcl::pTk::Label is a subclass of Tcl::pTk::Widget).

Categories of Tcl::pTk Widgets

Tcl::pTk Widgets fall into the following basic categories, based on how they are implemented in the Tcl::pTk package.

Direct auto-wrapped widgets

These types of widgets (for example the Entry, Button, Scrollbar, and Label widgets) have no special code written for them in Tcl::pTk. Their creation and method calls (e.g. $button->configure(-text => 'ButtonText')) are handled by the wrapping code in the base Tcl::pTk::Widget package.

Auto-wrapped widgets, with compatibility code

These types of widgets are similar to the Direct auto-wraped widgets, but have additional code written to be completely compatibile with the perl/Tk syntax. Examples of this type of widget are the Text, Frame, Menu, and Menubutton widgets.

Megawidgets

These are widgets that are composed of one-or-more other base widget types. Pure-perl megawidgets are supported in Tcl::pTk, just like they are in perl/Tk. Examples of these types of widgets are ProgressBar, LabEntry, BrowseEntry, and SlideSwitch (one of the test cases in the source distribution).

Derived Widgets

Derived widgets are sub-classes of existing widgets that provide some additional functions. Derived widgets are created in Tcl::pTk using very similar syntax to perl/Tk (i.e. using the Tcl::pTk::Derived package, similar to the Tk::Derived package). Examples of these types of widgets are Tree, TextEdit, TextUndo, ROText, and DirTree.

A behind-the-scenes look at auto-wrapped widgets

All widgets in Tcl::pTk are objects, and have an inheritance hierarchy that derives from the Tcl::pTk::Widget parent class. Megawidgets and derived widgets are handled very similar (if not exactly) the same as in perl/tk.

Auto-wrapped widgets (like the Entry, Button, Scrollbar, etc.) are handled differently. The object system for these types of widgets is dynamic. Classes and/or methods are created when they are first used or needed.

The following describes how methods are called for the two different categories of auto-wrapped widgets

Direct auto-wrapped widget example

Here is an example of a Entry widget, a direct auto-wrapped widget:

my $entry = $mw->Entry->pack;          # Create an entry widget and pack it
$entry->insert('end', -text=>'text');  # Insert some text into the Entry
my $entryText = $entry->get();         # Get the entry's text

Internally, the following mechanics come into play: The Entry method creates an Entry widget (known as entry in the Tcl/Tk environment). When this creation method is invoked the first time, a package Tcl::pTk::Entry is created, which sets up the class hierarchy for any further Entry widgets. The newly-created Tcl::pTk::Entry class is be a direct subclass of Tcl::pTk::Widget.

The second code line above calls the insert method of the $entry object. When invoked first time, a method (i.e. subref) insert is created in package Tcl::pTk::Entry, which will end-up calling calling the invoke method on the Tcl/Tk interpreter (i.e. $entry->interp()->invoke($entry, 'insert', -text, 'text')).

The first time insert is called, the insert method does not exist, so AUTOLOAD comes into play and creates the method. The second time insert is called, the already-created method is called directly (i.e. not created again), thus saving execution time.

Auto-wrapped widgets, with compatibility code

Here is an example of a Text widget, which is an auto-wrapped widget with extra code added for compatibility with the perl/tk Text widget.

my $text = $mw->Text->pack;            # Create an text widget and pack it
$text->insert('end', -text=>'text');   # Insert some text into the Text
@names = $text->markNames;             # Get a list of the marks set in the
                                       #  Text widget

Internally, following mechanics come into play: The Text method creates an Text widget (known as text in Tcl/Tk environment). Because a Tcl::pTk::Text package already exists, a new package is not created at runtime like the case above.

The second code line above calls the insert of the $text object of type Tcl::pTk::Text. This insert method is already defined in the Tcl::pTk::Text package, so it is called directly.

The third code line above calls the markNames method on the $text object. This method is not defined in the Tcl::pTk::Text package, so the first time when markNames is called, AUTOLOAD in the Tcl::pTk package comes into play and creates the method. The second time markNames is called, the already-created method is called directly (i.e. not created again), thus saving execution time.

Description of an auto-wrapped method call

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

$widget->method(@parameters);

In this case all @parameters will be preprocessed by performing the following actions:

  1. For each variable reference, a Tcl variable will be created and tied to it, so changes in the perl variable will be reflected in the Tcl variable, and changes in the Tcl variable will show up in the perl variable.

  2. For each perl code-reference, a Tcl command will be created that calls this perl code-ref.

  3. Each array reference will considered a callback, and proper actions will be taken.

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

if $method is all lowercase (e.g. insert), m/^[a-z]$/

.path method parameter1 parameter2 ....

if $method contains exactly one capital letter inside the method name (e.g. tagNames), m/^[a-z]+[A-Z][a-z]+$/

.path method submethod parameter1 parameter2 ....

if $method contains several capital letter inside the method name, methodSubmethSubsubmeth

.path method submeth subsubmeth parameter1 parameter2 ....

Fast method invocation for auto-wrapped widgets

If you are sure that preprocessing of @parameters in a method call aren't required (i.e. no parameters are Perl references to scalars, subroutines or arrays), then the preprocessing step described above can be skipped by calling the method with an underscore _ prepended to the name. (e.g call $text->_markNames(), instead of $text->markNames()). Calling the method this way means you are using an internal method that executes faster, but normally you should use a "public" (i.e. non-underscore) method, which includes all preprocessing.

Example:

# Can't use the faster method-call here, because \$var must be
# preprocessed for Tcl/Tk:
$button->configure(-textvariable=>\$var);

# Faster version of insert method for the "Text" widget
$text->_insert('end','text to insert','tag');

# This line does exactly same thing as previous line:
$text->_insertEnd('text to insert','tag');

When doing many inserts to a text widget, the faster version can help speed things up.

Using any Tcl/Tk feature from Tcl::pTk

In addition to the standard widgets (e.g. Entry, Button, Menu, etc), the Tcl::pTk module lets you use any other widget from the Tcl/Tk widget library. This can be done with either Tcl syntax (via the Eval method), or with regular perl/tk syntax.

To interface to a new Tcl/Tk widget using perl/tk syntax, a Declare method call is made on an already-created widget, or on the Tcl::pTk interpreter object itself.

Syntax is

# Calling Declare on a widget object:
$widget->Declare('perlTk_widget_method_name','tcl/tk-widget_method_name',
   @options);

or, exactly the same,

# Calling Declare on a the Tcl::pTk Interpreter object:
$interp->Declare('perlTk_widget_method_name','tcl/tk-widget_method_name',
   @options);

Options are:

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

The -require option specifies the new Tcl/Tk widget requires a Tcl package to be loaded with a name of 'tcl-package-name';

The -prefix option used to specify the prefix of the autogenerated widget path-name. This option is normally used when the Tcl/Tk widget name contains non-alphabetic characters (e.g. ':'). If not specified, the prefix will be generated from the package-name.

A typical example of using the Declare method:

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

After this call, Tcl::pTk will create a widget creation method for this new package to make it an auto-wrapped widget (See the definition of auto-wrapped widgets above).

This means

my $tab = $mw->BLTNoteBook;

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

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

After the above example code, the variable $tab is a Tcl::pTk::Widget that behaves in the usual way, for example:

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

These two lines are the Tcl/Tk equivalent of:

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

You can also intermix the perl/tk and Tcl/Tk syntax like this:

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

How to read Tcl/Tk widget docs when using in Tcl::pTk

For the documentation of standard perl/tk widgets (like Button, Entry, Menu, etc), you can refer to the the perl/tk docs Tk (We may move a copy of the perl/tk docs to Tcl::pTk in the future). For non-standard widgets (like the BLTNotebook widget example above) you have to use the Tcl docs on the widget for the widget documentation. (Most Tcl/Tk docs can be found at http://www.tcl.tk/ )

When reading Tcl/Tk widget documentation about widgets, you can apply the following guidelines to determine how to use the widget in Tcl::pTk using perl/tk syntax.

Suppose the Tcl/Tk docs say:

pathName method-name optional-parameters
   (some description)
   

This means the widget has a has method method-name and you can invoke it in Tcl::pTk like

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

The $widget variable in Tcl::pTk is like the pathName in the Tcl/Tk docs.

Sometimes the Tcl/Tk method-name consists of two words (verb1 verb2). In this case there are two equivalent ways to invoke it, $widget->verb1('verb2',...); or $widget->verb1Verb2(...);.

Widget options are used just like they are shown in the Tcl/Tk docs. There is no special translation needed for the widget options described in the Tcl/Tk docs for use in Tcl::pTk.

Miscellaneous methods

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

When widgets are created in Tcl::pTk they are stored internally and can be retrieved by the widget() method, which takes widget path as first parameter, and optionally the widget type (such as Button, or Text etc.). For 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::pTk::Button object)
my $button = widget(".fram.butt", 'Button');

# same but retrieved widget considered as general widget, without
# specifying its type. This will make it a generic Tcl::pTk::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 Tcl::pTk. A check is not performed to see if a widget with given path name exists. This enables the use of widgets created elsewhere in Tcl/Tk to be treated like Tcl::pTk widgets.

widget_data

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';

Note:

Use of this method has largely been superceded by the perl/tk-compatible privateData widget method.

$widget->tooltip("text")

Any widget accepts the 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;

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

Note: The perl/tk-compatible Balloon widget is also available for installing tool-tips on widgets and widget-elements.

Terminology

In the documentation and comments for this package, perl/Tk, Tcl/Tk, Tcl::pTk, Tcl.pm, and Tcl are used. These terms have the following meanings in the context of this package.

perl/Tk

The traditional perl interface to the Tk GUI libraries. i.e the perl package occupying the Tk namespace on CPAN.

Tcl/Tk

The Tcl/Tk package with tcl-code and associated libraries (e.g. Tcl.so or Tcl.dll and associated tcl-code). See http://www.tcl.tk/

Tcl::pTk

This package, which provides a perl interface into the Tcl/Tk GUI libraries.

Tcl.pm

The Tcl perl package, which provides a simple interface from perl to Tcl/Tk. Tcl::pTk interpreter objects are subclassed from the Tcl package.

Tcl

The Tcl programming language.

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.
John Cerney, john.cerney _a_ gmail . com, 29 Sep 2009.
Christopher A. Chavez, chrischavez _a_ gmx . us, May 2018.

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