Updated 2012-09-29 04:57:29 by RLE

Tcl::Tk is an alternative binding to Tcl/Tk from Perl (as opposed to Perl/Tk). It uses Tcl in the bridge (which Perl/Tk does not). These are the Tcl [1] and Tcl::Tk [2] modules for Perl. Make sure you get the latest.

Mailing lists:

wiki:

Tcl::Tk has advantages over the traditional Perl/Tk in using less memory and being faster, as well as being more portable and flexible (for example, for use on Windows/CE). It gains this by linking directly against Tcl using a bridge that has deep understanding of Tcl_Objs and PerlSVs. It has a slightly varied interface, but there is a rough Perl/Tk compatability layer (about 80% compatability). It would be nice to see another module layered on top that provides near 100% Perl/Tk compability while maintaining the efficient lower layer that ties tightly to Tcl.

VK: Other advantages of Tcl, Tcl::Tk perl modules over Perl/Tk are briefly listed at perl's discussion site [3]:

  • Perl<->Tcl/Tk bridge is lightweight, any misbehaviour is hidden is 70Kb of pure-perl Tcl::Tk code and 30Kb of Tcl bridge code; perlTk is huge and really hard to maintain. It took really many efforts to switch to Unicode between versions Tk800.024 <->Tk804.027
  • Most up-to-date Tcl/Tk could easily be used. Tcl-8.5 is really soon to come, and I already tried it from Perl.
  • You can use Unicode GUI in Perl version 5.6.x, and perlTk lacks support for Unicode for 5.6.x.
  • You have a much richier set of widgets, plus pure-Tcl widgets, and the many widget extensions developed for Tcl/Tk.
  • It is the only way to have Perl+Tk GUI on WinCE devices. PerlTk is harder to port to another platform, and perlTk Unicode version is not ported to WinCE (only elder one).
  • True native OS X (Aqua) Tk is usable.
  • As a general rule, it is easier to maintain structured things. That said, Perl does its own evolving, and Tcl/Tk does its own. Contrary, perlTk contains "Tk" and "Tix" mixed in it, and you do not know how old they are, plus some pure-Perl widgets that do not have Tcl/Tk counterpart, and perlTk documentation contains a lot of documentation rudiments that fixed in Tcl/Tk
  • Perl motto "TIMTOWTDI" is wider: you can do
 $interpreter->Eval('pure-tcl-code-to-create-and-manipulate-widgets');

or use perlTk syntax
 my $btn=$frame->Button(-text=>'Ok',-command=>sub{print 'ok'})->pack;

Disadvantage and major compat issue over Perl/Tk is lack of documented way for creating of pure-perl widgets. This is currently work in progress. It is all technically possible, just needs to be done. Since Tcl::Tk is open to the world of Tcl/Tk widget sets (BLT, BWidget, Tix, tile, iwidgets, vu, Tktable, ...), developers of new (from scratch) apps may find it easier to use these, but compat for older apps should remain a consideration.

Following example shows how Perl program can use Tcl::Tk to access Tcl/Tk. It creates and then uses pure-perl widget LabEntry2 based on mkWidgets package:
 use Tcl::Tk;

 my $int = new Tcl::Tk;
 my $mw = $int->mainwindow;

 #
 # make pure-perl widget
 #
 # 1. bring mkWidgets package, it provides megawidgets (among others are snit, Tix, BWidget, IWidgets)
 $int->pkg_require('mkWidgets');
 # 2. create metawidget
 # our megawidget will have two labels and two edit boxes, aligned, with
 # a 'frustrate' button that swaps two Entry subwidgets
 # 2.1 metawidget itself
 $int->metawidgetCreate('LabEntry2', sub {
         #print STDERR "init proc: instantiation of a metawidget; create internal widgets\n";
         my $this = $int->widget($int->GetVar('this'));
         my $lab1 = $this->Label->grid(-column=>0,-row=>0,-sticky=>'e');
         my $ed1 = $this->Entry->grid(-column=>1,-row=>0,-sticky=>'w');
         my $lab2 = $this->Label->grid(-column=>0,-row=>1,-sticky=>'e');
         my $ed2 = $this->Entry->grid(-column=>1,-row=>1,-sticky=>'w');
         my $btn = $this->Button(-text=>'frustrate',-command=>sub{$this->frustrate})
             ->grid(-column=>0,-row=>2,-sticky=>'we',-columnspan=>2);
         $int->my('lab1',$lab1->path);
         $int->my('ed1',$ed1->path);
         $int->my('lab2',$lab2->path);
         $int->my('ed2',$ed2->path);
     }, sub {
         print STDERR "exit proc: destruction of a metawidget; delete internal widgets\n";
         my $this = $int->widget($int->GetVar('this'));
         # do I need deleting child widgets? those are deleted automatically
         for ($this->children) {
             print STDERR "\@\@";
             $_->destroy;
         }
     });
 # 2.2 some of its methods/options
 $int->metawidgetCommand('LabEntry2', frustrate=> sub {
         my $this = $int->widget($int->GetVar('this'));
         # frustrate method of our megawidget swaps two entry subwidgets, so user will be frustrated
         $int->_gridForget($int->my('ed1'),$int->my('ed2'));
         $int->_grid($int->my('ed1'),qw/-column 1 -row 1 -sticky w/);
         $int->_grid($int->my('ed2'),qw/-column 1 -row 0 -sticky w/);
     });
 # ... options
 $int->metawidgetOption('LabEntry2', '-lab1', sub {
         my (undef,$int,undef,$aa) = @_;
         $int->my('-lab1',$aa);
         $int->widget($int->my('lab1'))->configure(-text=>$aa);
     });
 $int->metawidgetOption('LabEntry2', '-lab2', sub {
         my (undef,$int,undef,$aa) = @_;
         $int->my('-lab2',$aa);
         $int->widget($int->my('lab2'))->configure(-text=>$aa);
     });
 $int->metawidgetOption('LabEntry2', '-textvariable1', sub {
         my (undef,$int,undef,$aa) = @_;
         $int->widget($int->my('ed1'))->configure(-textvariable=>$aa);
     });
 $int->metawidgetOption('LabEntry2', '-textvariable2', sub {
         my (undef,$int,undef,$aa) = @_;
         $int->widget($int->my('ed2'))->configure(-textvariable=>$aa);
     });

 # 3. now Tcl/Tk has our megawidget; bring it to Perl
 $mw->Declare('LabEntry2','labentry2');

 # megawidget creation completed. now use it
 my ($v1,$v2,$v3) = qw(one two three);
 my $mywid = $mw->LabEntry2(-lab1=>'l1',-lab2=>'l2',-textvariable1=>\$v1,-textvariable2=>\$v2)->pack;
 my $mywid1 = $mw->LabEntry2(-lab1=>'XXX',-lab2=>'O',-textvariable1=>\$v1,-textvariable2=>\$v3)->pack;

 # I wonder what is 2nd label of 2nd widget?
 print STDERR "2nd label of 2nd widget is ",$mywid1->cget('-lab2'),"\n";

 $mw->Scrolled('Text')->pack(-fill=>'both',-expand=>1)->_insertEnd("".$int->_infoBody('tclPkgUnknown'));
 $int->MainLoop;

Pure-perl widgets based on other Tcl approaches will be also added.

RLH - Since both are PM modules can I just drop them in my lib path (on Windows XP) and be off and running?

VK - Tcl::Tk is pure perl, but Tcl module is not (has XS). Perl module with a name Tcl is trivial to compile. Look /ask for/... in Tcl::Tk wiki for binaries.

Examples edit

by Xyem

Building Tcl for Tcl 8.5:

The Tcl module ( 0.97 ) tries to use stubs for Tcl 8.4 which results in a segmentation error when the Tcl module is used in Perl, despite passing all tests. To create the Makefile for building it for Tcl 8.5 on my Ubuntu ( 8.04 ) machine I used:
  perl Makefile.PL --nousestubs --library=-ltcl8.5  --include=-I/usr/include/tcl8.5/

JH: It should not be necessary to do that if you built properly with 8.4 stubs and not the regular library. Stubs ensures the upwards compatibility to 8.4+. The above line will create an 8.5-only version which won't work with 8.6.

Xyem 2008-10-08 09:28 UTC: When I try to build Tcl 0.97 downloaded from CPAN "normally", the following transpires:
  xyem@puppy:~$ tar zxvf Tcl-0.97.tar.gz
  ( ..snip.. )
  xyem@puppy:~$ cd Tcl-0.97/
  xyem@puppy:~/Tcl-0.97$ mkdir -p /tmp/perl/lib
  xyem@puppy:~/Tcl-0.97$ perl Makefile.PL PREFIX=~/tmp/perl LIB=~/tmp/perl/lib
  LIBS   = -Ltcl-core/linux-i686 -ltclstub8.4
  INC    = -Itcl-core/include
  DEFINE =  -DUSE_TCL_STUBS
  Checking if your kit is complete...
  Looks good
  Warning: -Ltcl-core/linux-i686 changed to -L/home/xyem/Tcl-0.97/tcl-core/linux-i686
  Writing Makefile for Tcl
  xyem@puppy:~/Tcl-0.97$ make
  ( ..snip.. compiles fine )
  xyem@puppy:~/Tcl-0.97$ make test
  PERL_DL_NONLAZY=1 /usr/bin/perl "-MExtUtils::Command::MM" "-e" "test_harness(0, 'blib/lib', 'blib/arch')" t/*.t
  ( ..snip.. all tests pass, none skipped )
  All tests successful.
  Files=10, Tests=53,  2 wallclock secs ( 0.78 cusr +  0.14 csys =  0.92 CPU)
  xyem@puppy:~/Tcl-0.97$ make install
  ( ..snip.. )
  xyem@puppy:~/Tcl-0.97$ export PERL5LIB=~/tmp/perl/lib
  xyem@puppy:~/Tcl-0.97$ perl -MTcl
  Segmentation fault
  xyem@puppy:~/Tcl-0.97$

JH: I find the above results odd ... the make test works correctly, but not the installed use case? Are you sure that the same Tcl and Perl and referenced in each case?

Xyem 2008-10-12 22:40 UTC: Freshly installed Ubuntu 8.04 gives this behaviour, so there is only one Tcl and Perl installed. Running Tcl alone ( tclsh ) works fine, as does building it specifically for 8.5. I would do more research into it but I don't know where to start. I do recall while Googling the issue that I was not alone.. I can put up a virtual machine and give you ssh access if you are interested in looking into it?

Xyem 2009-04-20 09:51 UTC: I tried to "do it properly" as root, seeing if my cpan configuration was causing issues. It does exactly the same thing.

Tcl lists returned as string instead of an array (workaround)

Tcl::Tk has a list of methods that returns lists as part of the module which, it seems, you cannot modify without editing the module source. The list is not exhaustive and fails to Do What You Expect when using certain widgets ( mainly non-core ones like BWidgets ).
  my @Nodes = $BWidget_Tree -> nodes ( 'root' );
  # @Nodes contains only a single element, a string of node indices, "1 2 3 4 5"

One workaround is to not use the Widgets method, but make the call more directly.
  my @Nodes = $Tcl -> call ( $BWidget_Tree, 'nodes', 'root' );
  # @Nodes contains node indices, ( 1, 2, 3, 4, 5 )

Doing it this way instead should prevent code that would normally split the ( erroneously? ) returned string from breaking if the method gets added to the returns-a-list list in Tcl::Tk in the future.

JH: The BWidget tree nodes call in Tcl is returning something of proper list type, so we would have to trace where the list type is lost in translation.

Xyem 2008-10-12 22:40 UTC: Don't know how but I am more than happy and willing to learn :)