http://perlmonks.org?node_id=414803
Reputation: 0

Description: I constantly harp here about Tk::Zinc. Well I would just like to give a little demonstration of it's abilities. Just to keep Zinc in everyone's "list of options". :-) I am going to build a rudimentary "Newton's cradle", one in Canvas and one in Zinc. As a matter of fact, I'm going to use RotCanvas, instead of Canvas, otherwise it would be too complex too even mess with in Canvas. The first thing you will notice, is that RotCanvas is limited to only a few items types which can be rotated, and that it will lock up if you try to "push it too fast" with a timer. On my 800 Mhz system, RotCanvas will lock up if I set the repeat interval to less than 20. On Zinc, I can go down to 1. This results in greater resolution and smoother motion. Try setting the repeat interval to 1, in both scripts and see the difference. One other thing, I havn't even incorporated the scaling ability of Zinc , expecially on groups. With that, I could simulate 3D by zooming in and out as the pendulums rotate.

#!/usr/bin/perl
use warnings;
use strict;
use Tk;
use Tk::RotCanvas;

my $mw = tkinit;

my $heightmw = 260;
my $width = 600;
my $height = $heightmw - 60;

$mw->geometry($width.'x'.$heightmw .'+100+100');

my $canvas = $mw->RotCanvas(-width => $width, -height => $height,
                 -bg => 'black')->pack(-fill=>'both',-expand => 1);

my $angle = 0;
my $px0 = 240;
my $py0 = 0;
my $px_new = 240;
my $py_new = $height;

my %pend;

for(0..4){
  $pend{$_}{'line'} = $canvas->createLine(
                          $px0 ,$py0,
                         $px_new ,$py_new,
                          -smooth => 1,
                          -width => 3,
          -tags => ['line'.$_],
                          -fill => 'white');

  $pend{$_}{'ball'} = $canvas->createOval(
                        $px_new - 15 ,$py_new ,
                        $px_new + 15, $py_new + 30,
         -tags => ['ball'.$_],
         -fill => 'orange',
                );

  $canvas->move( $pend{$_}{'line'},$_ * 30,0);
  $canvas->move( $pend{$_}{'ball'},$_ * 30,0);
  $pend{$_}{'centerx'} = $px0 + $_ * 30;

}


my $motion = 0;

my $bframe = $mw->Frame()->pack(-fill =>'both');
my $startbut;
my $timer;
my $toggle = -1;
$startbut = $bframe->Button(-text=>'Start',
                 -command =>sub{
                       if($motion == 0){
                   $startbut->configure(-text=>'Stop');
                   $motion = 1;
               &start;
              }else{
                           $startbut->configure(-text=>'Start');
                   $motion = 0;
               $timer->cancel;
               }
            }
            )->pack(-side => 'left');

$bframe->Button(-text=>'Quit',
              -command =>sub{exit})->pack(-side => 'right');

MainLoop;

sub start{
#cannot set the timer too low or
#the rotate's below don't have enough
#time to complete, so lockups occur
#so set swing degree higher for more speed

 $timer = $canvas->repeat(50,sub{  
                 &swing(4);      
                 });            
 }
##########################################################

sub swing{
   my $degree = shift;
   $degree = $toggle*$degree;
   $angle = $angle + $degree;
    if( $angle > 90 ){$toggle *= -1}
    if( $angle < -90 ){$toggle *= -1}

for(0..4){
# can only specify one tag at a time in RotCanvas,
# and it will not do a group
 $canvas->rotate('line'.$_, $degree, $pend{$_}{'centerx'},$py0);
 $canvas->rotate('ball'.$_, $degree, $pend{$_}{'centerx'},$py0);
}

 }
           
__END__

###########################################################
##########################################################
#and now with Zinc
##########################################################
#########################################################

#!/usr/bin/perl
use warnings;
use strict;
use Tk;
use Tk::Zinc;

my $mw = tkinit;

my $heightmw = 260;
my $width = 600;
my $height = $heightmw - 60;

$mw->geometry($width.'x'.$heightmw .'+100+100');

my $canvas = $mw->Zinc(-width => $width,
               -height => $height,
               -backcolor => 'black')->pack(-fill=>'both',-expand => 1);

my $angle = 0;
my $px0 = 0;
my $py0 = 0;
my $px_new = 240;
my $py_new = $height;

my %pends;

#make a prototype pendulum easily at (0,0) coords
$pends{0}{'pendulum'} = $canvas->add('group',1,-visible=> 1);

# all lines are curves....of course!! it's relativity :-)
my $line = $canvas->add('curve',$pends{0}{'pendulum'},
                          [0 ,0, 0 ,$py_new],
                          -linewidth => 3,
                          -tags => ['line'],
                          -fillcolor => 'white',
           -linecolor => 'white',
              );

my $ball = $canvas->add('arc',$pends{0}{'pendulum'},
                             [-15,$py_new,15,$py_new+30],
                 -tags => ['ball'],
        -filled=> 1,
        -fillcolor => 'orange',
        );

$canvas->translate($pends{0}{'pendulum'},240,0);
$pends{0}{'center_rot'} = [240,0];
########end of first prototype

#now clone and position the other pendulums
for(1..4){
$pends{$_}{'pendulum'} = $canvas->clone( $pends{0}{'pendulum'} );
$canvas->translate($pends{$_}{'pendulum'}, $_*30, 0);
$pends{$_}{'center_rot'} = [240 + $_ * 30 ,0];
}

my $motion = 0;

my $bframe = $mw->Frame()->pack(-fill =>'both');
my $startbut;
my $timer;
my $toggle = -1;
$startbut = $bframe->Button(-text=>'Start',
                 -command =>sub{
                       if($motion == 0){
                   $startbut->configure(-text=>'Stop');
                   $motion = 1;
               &start;
              }else{
                           $startbut->configure(-text=>'Start');
                   $motion = 0;
               $timer->cancel;
               }
            }
            )->pack(-side => 'left');

$bframe->Button(-text=>'Quit',
             -command =>sub{exit})->pack(-side => 'right');

MainLoop;
######################################################
sub start{
 $timer = $canvas->repeat(10,sub{  
              &swing(.0175);    # 1 degree in radians      
                           });
 }
######################################################
sub swing{
   my $degree = shift;
   $degree = $toggle*$degree;
   $angle = $angle + $degree;
    if( $angle > 1.57 ){$toggle *= -1}
    if( $angle < -1.57 ){$toggle *= -1}
   
  for(0..5){ # rotate( item, rads, [center of rotation ])
    $canvas->rotate($pends{$_}{'pendulum'},
                       $degree,
        @{$pends{$_}{'center_rot'}});
  }
   
}
           
__END__


Edit your snippet here
comment on Advantages of Tk::Zinc over plain Canvas
Download Code

Back to Snippets Section