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

Hi, I'm pretty new to Tk. In my Tk GUI application, I'd like to put some labels on a canvas, each label should be editable, and can be moved. But since it's on a canvas(with other graphics), I'd like the editable text to be displayed more like a label than a LabEntry box. To be more precise, I'd like to be able to: What's the best approach to do that? is there some code sample somewhere? I looked at the widget demo, doesn't seem to have something similar. Thanks.
  • Comment on Tk: how to have an editable/movable label?

Replies are listed 'Best First'.
Re: Tk: how to have an editable/movable label?
by kvale (Monsignor) on Oct 17, 2004 at 04:50 UTC
    To create a widget on a canvas, use the createWindow command:
    $button = $canvas->Button( -text => "Push me", -command => sub { print "Been pushed\n"; }); $id = $canvas->createWindow( 0, 0, -window => $button, -tags => "button1", -anchor => "center" );
    Note that I have associated the tag button1 with the widget. Then I can use this tag to move the widget around:
    $canvas->move( "button1", 100, 100);
    As to your type of widget, I would start out with a LabEntry box and try to configure the appearance to your liking. Note the inset box appearance is an inportant visual cue to editability and should not be lightly discarded. If you like, after the user has edited the text, your could destroy the LabEntry widget and replace it with a Label widget.

    Update: Forgot to mention that the single best source for programming the perl/Tk API is the book "Mastering Perl/Tk" by Steve Lidie and Nancy Walsh. I'd stay away from the Learing Perl/Tk book. It is pretty weak for an O'Reilly book.

    -Mark

Re: Tk: how to have an editable/movable label?
by mawe (Hermit) on Oct 17, 2004 at 08:12 UTC
    Hi!

    use Tk; my $top = new MainWindow; my $c = $top->Canvas()->pack(); my ($x,$y); # left mouse-button -> create text $top->bind('<1>' => [\&click_left, Ev('x'),Ev('y')]); # shift and left mouse-button -> edit text $top->bind('<Shift-Button-1>' => [\&edit, Ev('x'),Ev('y')]); # right mouse-button -> move the text $top->bind('<3>' => [\&move_it, Ev('x'),Ev('y')]); MainLoop; sub click_left { my $e = shift; ($x,$y) = @_; my $t = $top->Toplevel(); my $entry = $t->Entry()->pack(); $entry->focus(); $t->bind('<Return>' =>sub{ my $text = $entry->get(); $c->createText($x,$y,-text=>$text); $t->destroy(); }); } sub move_it { my $e = shift; ($x,$y) = @_; my $id = $c->find('closest',$x,$y); $top->bind('<Button3-Motion>' => [\&move, Ev('x'),Ev('y'),$id]); } sub move { my ($e,$xm,$ym,$id) = @_; my $dx = $xm - $x; my $dy = $ym - $y; ($x,$y) = ($x+$dx, $y+$dy); $c->move($id,$dx,$dy); } sub edit { my $e = shift; ($x,$y) = @_; my $id = $c->find('closest',$x,$y); my $text = $c->itemcget($id,'text'); my $t = $top->Toplevel(-title=>"edit"); my $entry = $t->Entry()->pack(); $entry->insert(0,$text); $entry->focus(); $t->bind('<Return>' => sub { my $text = $entry->get(); $c->delete($id); $c->createText($x,$y,-text=>$text); $t->destroy(); }); }
    I'm sure this is not the best way, but it should do what you want :-)

    mawe

      That's great, mawe. Thanks a lot, I tried it, works great.