开发者

Perl Tk binding to canvas items

In my application if click once then circle will be drawed on canvas. If double click then recently added points will be connected to polygon.

I need to adjust new circle position to the center of clicked (and existing) point. That is if I click inside existing point then new point will match this existing point.

I tried to set separate callbacks for click on circle and on whole canvas but they called one-by-one. And callback for click on circle is also called after double-click...

Is there a way to stop event propagation?

 use strict;
use Tk;

my $countries = [];
push(@$countries, []);

my $mw = MainWindow->new;
$mw->title("Graph colorer");
$mw->minsize(600, 600);
$mw->resizable(0, 0);

my $canvas = $mw->Canvas(-background => 'white')->pack(-expand => 1,
                                                       -fill => 'both');
$canvas->bind('point', "<Button-1>", [ \&smart_point, Ev('x'), Ev('y') ]);
$canvas->Tk::bind("<Button-1>", [ \&append_point, Ev('x'), Ev('y') ]);
$canvas->Tk::bind("<Double-Button-1>", [ \&draw_last_country ]);

sub append_point {
    my ($canv, $x, $y) = @_;
    my $last_country = $countries->[-1];
    my ($canvx, $canvy) = ($canv->canvasx($x), $canv->canvasy($y));
    push(@$last_country, $canvx, $canvy);
    $canv->createOval($canvx-5, $canvy-5, $canvx+5, $canvy+5, -tags => 'point',
                      -fill => 'green');
    print "pushed (x,y) = ", $canvx, ", ", $canvy, "\n";
}

sub draw_last_country {
    my $canv = shift;
    $canv->createPolygon($开发者_如何学JAVAcountries->[-1]);
    push(@$countries, []);
}

sub smart_point {
    my $canv = shift;
    my $id = $canv->find('withtag', 'current');
    my ($x1, $y1, $x2, $y2) = $canv->coords($id);
    print "clicked (x,y) = ", ($x2-$x1)/2, ", ", ($y2-$y1)/2, "\n";
}

MainLoop;


The processing of events for canvas items is completely separate from the processing of events for windows (OK, there's a link, but it's not at a level that you can manipulate). You have to do the interlock yourself, e.g., by having a variable that's shared between the bindings.


Ok, I've just remove oval-click-callback and check if clicked inside or outside of an existing oval in canvas-click-callback.


# algorithm mado-williams

use strict;
use Tk;

my $RADIUS = 6;

my $countries = [];
push(@$countries, []);

my $mw = MainWindow->new;
$mw->title("Graph colorer");
$mw->minsize(600, 600);
$mw->resizable(0, 0);

my $canvas = $mw->Canvas(-background => 'white')->pack(-expand => 1,
                                                       -fill => 'both');

$canvas->Tk::bind("", [ \&append_point, Ev('x'), Ev('y') ]);
$canvas->Tk::bind("", [ \&draw_last_country ]);

sub append_point {
    # Append new point to the last country. If clicked into existing point then
    # adjust position of new point to this existing point.

    my ($canv, $x, $y) = @_;
    my ($canvx, $canvy) = ($canv->canvasx($x), $canv->canvasy($y));
    # find nearest existing point (find_nearest return undef when wi clicked
    # outside any existing point)
    my $nearest = find_nearest($canvx, $canvy);
    if (defined $nearest) {
        # if we clicked into existing point then adjust position to this point
        ($canvx, $canvy) = point_center($nearest);
    }
    # append new point to the last country
    my $last_country = $countries->[-1];
    push(@$last_country, $canvx, $canvy);
    # draw new point
    $canv->createOval($canvx-$RADIUS, $canvy-$RADIUS, $canvx+$RADIUS, $canvy+$RADIUS,
                      -tags => 'point', -fill => 'green');
    print "pushed (x,y) = ", $canvx, ", ", $canvy, "\n";
}

sub find_nearest {
    # Find nearest point to specified position.
    # Return its id or undef if clicked outside.
    my ($px, $py) = @_;
    my @points = $canvas->find('withtag', 'point');
    # sort existing points by ascending distance from specified position
    my @points = sort {distance($a, $px, $py)  distance($b, $px, $py)} @points;
    if (distance($points[0], $px, $py) coords($pid);
    my $cx = $px1 + ($px2 - $px1) / 2, my $cy = $py1 + ($py2 - $py1) / 2;
    return ($cx, $cy);
}

sub draw_last_country {
    # draws last country
    my $canv = shift;
    $canv->createPolygon($countries->[-1]);
    push(@$countries, []);
}

MainLoop;
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜