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 [L1 ] and Tcl::Tk [L2 ] 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 [L3 ]:
$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, VUW Widgets, 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.
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 :)