I had to do a little research to be able to answer your Tk Mystery 2. You see, I had noticed this behavior before, but I hadn't solved it myself, so I used your question as an excuse to go figure it out. (I also needed a few minutes to test and verify it).
The answer is that you have to assign a variable to the actual Canvas object which is a Subwidget of the Scrolled object, and bind to it. Then, when you pass the (x, y) coordinate pair, you need to use the Canvas methods canvasx() and canvasy() to convert them to the transformed (x, y) pair you will use.
Here is a rewrite of your code (well, originally mine :-)), which demonstrates this:
#!/usr/bin/perl -w use Tk; use strict; use warnings; # Globals my $scroll_x = 0; my $scroll_y = 0; my $b_button_1_down = 0; # Is the left mouse button currently down? my ($x0, $y0, $x1, $y1); # Starting and ending (x,y) coordinates my $rect_id = 0; # Last rectangle drawn # Main program / GUI setup my $mw = MainWindow->new; my $c = $mw->Scrolled('Canvas', -width => 200, -height => 200, -background =>'blue', -scrollregion => [ 0, 0, 1500, 1000 ] ); $c->pack(-expand => 1, -fill => 'both'); bind_left_mouse($c); MainLoop; # Subroutines sub bind_left_mouse { my ($c) = @_; # Create "callback"; subroutines which get called whenever the # corresponding event is triggered. Note that Ev('x') and Ev('y') # will tell us, at the time they're used, what the current (x,y) # coordinate pair was. Note, too, that we're now getting the actu +al # Canvas object $cv from the Scrolled object $c, using the Subwidg +et() # method, and using it for the binding, and as a parameter to each + of # the 3 callbacks. # my $cv = $c->Subwidget("canvas"); my $cb1 = [ \&left_mouse_down, $cv, Ev('x'), Ev('y')]; my $cb2 = [ \&left_mouse_release, $cv, Ev('x'), Ev('y')]; my $cb3 = [ \&left_mouse_moving, $cv, Ev('x'), Ev('y')]; # Bind the callbacks $cv->CanvasBind("<ButtonPress-1>", $cb1); $cv->CanvasBind("<ButtonRelease-1>", $cb2); $cv->CanvasBind("<Motion>", $cb3); } sub left_mouse_down { # This gets called whenever the left-mouse button is clicked my ($ev, $cv, $x, $y) = @_; # Figure out what adjustments have to be made for the scroll locat +ion $x = $cv->canvasx($x); $y = $cv->canvasy($y); $b_button_1_down = 1; ($x0, $y0) = ($x, $y); print "(debug) button1 down, (x,y) => ($x,$y)\n"; } sub left_mouse_moving { # This gets called whenever the mouse moves. It's true for ALL # mouse motion, but we're really just interested in when the mouse # is moving -and- the left mouse button is held down; hence the na +me. # my ($ev, $cv, $x, $y) = @_; return unless $b_button_1_down; # Figure out what adjustments have to be made for the scroll locat +ion $x = $cv->canvasx($x); $y = $cv->canvasy($y); print "(debug) button1 moving, (x,y) => ($x,$y)\n"; $rect_id and $cv->delete($rect_id); # Delete any old rectangle fir +st my @opts = (-outline => 'yellow', -dash => '. '); $rect_id = $cv->createRectangle($x0, $y0, $x, $y, @opts); } sub left_mouse_release { # This gets called whenever the left-mouse button is released my ($ev, $cv, $x, $y) = @_; $b_button_1_down = 0; # Figure out what adjustments have to be made for the scroll locat +ion $x = $cv->canvasx($x); $y = $cv->canvasy($y); ($x1, $y1) = ($x, $y); print "(debug) button1 release, (x,y) => ($x,$y)\n"; # Now do something with the triangle at (x0,y0,x1,y1)... $rect_id and $c->delete($rect_id); # Delete any old rectangle firs +t my @opts = (-fill => 'purple'); $rect_id = $c->createRectangle($x0, $y0, $x, $y, @opts); }
I changed the result to a solid purple rectangle (just to make it a little more interesting, as well as further visual confirmation of success). As you can see, the program finally does the right thing, even when you've scrolled the view.
In reply to Re: Tk mysteries.
by liverpole
in thread Tk mysteries.
by tamaguchi
| For: | Use: | ||
| & | & | ||
| < | < | ||
| > | > | ||
| [ | [ | ||
| ] | ] |