Anonymous Monk has asked for the wisdom of the Perl Monks concerning the following question:

Hello fellas,
This is a snippet from my app using Tk::Canvas. I've created several rectangles inside a larger rectangle, and then grouped them using
$c->createGroup([0, 0], -members => [$parent, @children]);
When I try to select any one of the child rectangles and get the id only the last id is returned using
my $id = $c->find( 'withtag', 'current' ); print "\t item id: $id\n";
The following is a snippet from my creatRec routine
my $x1 = 10; my $x2 = 20; $parent = $c->createRectangle(10, 20, 100, 60, -fill => 'red'); for (1..4) { push @children, $c->createRectangle($x1, 20, $x2, 30, -state =>'disabled', -activefill => 'green',-disabledfill => 'whi +te'); $x1 += 15; $x2 += 15; } my $group = $c->createGroup([0, 0], -members => [$parent, @childre +n]);
The active fill doens't seem to work either..Any ideas?

Replies are listed 'Best First'.
Re: Tk-Canvas Grouping
by kaif (Friar) on Jun 21, 2005 at 05:58 UTC

    To answer the first part of your question, according to the Tk::Canvas documentation, find() returns a list:

    This method returns a list consisting of all the items that meet the constraints specified by ...

    However, you are storing the result of the find in a scalar, and as such are getting only the last ID (which is what you always get with a list --- not an array --- in scalar context). Try changing your code to

    my @id = $c->find( 'withtag', 'current' ); print "\t item id(s): @id\n";

    (assuming you're not already using the variable @id) and see if that works. Good luck. Sorry I haven't had a chance to look at the second part of your question yet.

      Unfortunatley that produces the same result...I think it has something to do with the grouping. Onnce I ungroup them I'm able to retrieve the individual id's but loose the ability to manipulate (drag) them as a group :(
Re: Tk-Canvas Grouping
by zentara (Cardinal) on Jun 21, 2005 at 11:55 UTC
    As far as the "active fill" not working is concerned, it's because you have "-state =>'disabled' in their setup. That makes them essentially 'inactive'. If you are looking for a way to change their colors on "enter and leave", you need to setup a binding on each small rect or tag them.

    That brings up a big point you are missing. Tags!! I'm not sure what you are trying to accomplish exactly, but you make no use of tags, and you need to. I like to use hashes instead of arrays, and with that in mind, here is a script which may help you understand things. You have to play around with it a bit, to get the hang of it. I took the group out, since it was just getting in the way. Show us a full working script which uses the group, if you want us to help you with it.

    #!/usr/bin/perl use warnings; use strict; use Tk; my $mw = MainWindow->new(); # first create a canvas widget my $c = $mw->Canvas(width => 300, height => 200)->pack(); my $x1 = 10; my $x2 = 20; my $parent = $c->createRectangle(10, 20, 100, 60, -fill => 'red', -tags => ['parent'], ); my %children; for my $i (1..4) { $children{$i} = $c->createRectangle($x1, 20, $x2, 30, #-state =>'disabled', -activefill => 'green', -disabledfill => 'white', -tags => ['children',$i], ); $x1 += 15; $x2 += 15; } my $ebutton = $mw->Button(-text => 'Exit', -command => 'Tk::exit')->pack(); $c->Tk::bind("<Motion>", \&get_info ); MainLoop(); sub get_info{ my $curr_object = $c->find('withtag','current'); if(defined $curr_object){ print "curr->",@$curr_object,"\n"; #array dereference my (@list) = $c->gettags($curr_object); print "list->@list\n"; } }

    I'm not really a human, but I play one on earth. flash japh
      I'm using CanvasBind to bind <B1-Motion> to allow me to drag the group around the screen similar to below:
      sub drag_group { my ($c) = @_; my $e = $c->XEvent; # get the screen position of the move... my ( $sx, $sy ) = ( $e->x, $e->y,,, ); print "\t screen: $sx, $sy\n"; # get the canvas position... my ( $cx, $cy ) = ( $c->canvasx($sx), $c->canvasy($sy) ); print "\t canvas: $cx, $cy\n"; # get the amount to move... my ( $dx, $dy ) = ( $cx - $draginfo{lastx}, $cy - $draginfo{lasty} + ); print "\t dx, dy = $dx, $dy\n"; # move it... $c->move( $draginfo{id}, $dx, $dy ); }
      The problem I'm having is that once grouped I can't seem to click or mouse over the child rectangles. I'm able to identify the id's by using:
      sub items_retrieve { my $id = shift; my @items = @{$group{$id}{items}}; return @items; }
Re: Tk-Canvas Grouping
by zentara (Cardinal) on Jun 22, 2005 at 11:49 UTC
    It gets kind of exasperating when someone wants answers to a relatively complex operation, and they don't give a working code example. The way you posted little snips of code, I've had to spend more time just trying to make it a running script, in order to test it. So, here is how I would have done it. It appears that the group in Tk::Canvas gets in the way. In Zinc, the group is very powerful and useful, but in the plain old Canvas, the group item is just not very useful. I switched to just using plain tags...like I said before "tags are the key to making complex interactions".
    #!/usr/bin/perl use warnings; use strict; use Tk; my $dx; my $dy; my $grouptag; my $mw = MainWindow->new; $mw->geometry("700x600"); my $x1 = 10; my $x2 = 20; my $c = $mw->Canvas(-width => 700, -height => 565, -bg => 'black', )->pack; my $closebutton = $mw->Button(-text => 'Exit', -command => sub{Tk::exi +t(0)}) ->pack; my $parent = $c->createRectangle(10, 20, 100, 60, -fill => 'red', -tags => ['mover','group1'], ); my @children; for (1..4) { push @children, $c->createRectangle($x1, 20, $x2, 30, # -state =>'disabled', -fill => 'white', -activefill => 'green', -disabledfill => 'white', -tags => ['mover','group1'], ); $x1 += 15; $x2 += 15; } # #my $group = $c->createGroup([0, 0], # -members => [$parent, @children]); # #$c->bind($group, '<1>', sub {&mobileStart();}); #$c->bind($group, '<B1-Motion>', sub {&mobileMove();}); #$c->bind($group, '<ButtonRelease>', sub {&mobileStop();}); $c->bind('mover', '<1>', sub {&mobileStart();}); $c->bind('mover', '<B1-Motion>', sub {&mobileMove();}); $c->bind('mover', '<ButtonRelease>', sub {&mobileStop();}); MainLoop; sub mobileStart { my $ev = $c->XEvent; ($dx, $dy) = (0 - $ev->x, 0 - $ev->y); my $curr_object = $c->find('withtag','current'); print "curr->",@$curr_object,"\n"; #array dereference my (@list) = $c->gettags($curr_object); print "movelist->@list\n"; ($grouptag) = grep /(group\d+)/, @list; print "grouptag-> $grouptag\n"; print "START MOVE-> $dx $dy\n"; } sub mobileMove { my $ev = $c->XEvent; $c->move($grouptag, $ev->x + $dx, $ev->y +$dy); ($dx, $dy) = (0 - $ev->x, 0 - $ev->y); print "MOVING-> $dx $dy\n"; } sub mobileStop{&mobileMove;}

    I'm not really a human, but I play one on earth. flash japh