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

Hi All,
So I've been unsuccessfully trying to get text written to the canvas from a user input from the keyboard at a certain user selected coordinate.

In particular I'm having problems passing the @array to the subroutine.

I'd also like to avoid the second window for entering text if possible and be able to enter it directly onto the canvas.

Thanks in advance for the help-Mark.
Here's what I have so far:
#! /usr/bin/perl -w use strict; use Tk; use Win32::GUI; my @colors = qw(white yellow orange red magenta cyan blue green gray brown black ); # starting values my $drawItem = "rectangle"; my $thickness = 1; my $color = "blue"; my ($movx, $movy) = (-1, -1); my ($startx, $starty, $currentItem) = (-1,-1,""); my @items; my @allTags; my $mw = MainWindow->new(-title => "Genome Labeling Tools"); my ($f) = &CreateMenu($mw); my ($c, $canvas) = &CreateCanvas($f); my ($win); &BindStart(); MainLoop; # ------------------------------------------------------------ sub CreateCanvas { my ($f) = shift; my $c = $mw->Scrolled("Canvas", -cursor => 'crosshair', -scrollbars => 'se') ->pack( -side => 'left', -fill => 'both', -expand => 1); my $canvas = $c->Subwidget("canvas"); return ($c, $canvas); } # CreateCanvas # ------------------------------------------------------------ sub BindStart { # if there's a "Motion"-binding, we need to allow the user # to finish drawing the item before rebinding Button-1 # This fcn gets called when we finish drawing the item again my @bindings = $canvas->Tk::bind("<Motion>"); return if ($#bindings >= 0); if ($drawItem eq "rectangle" or $drawItem eq "oval" or $drawItem eq "line"){ $canvas->Tk::bind("<Button-1>", [\&StartDrawing, Ev('x'), Ev('y')] ); $canvas->Tk::bind("<Button-3>", [ \&StartMoving, Ev('x'), Ev('y') ]); $canvas->Tk::bind("<Button-2>", ""); } } # BindStart # ------------------------------------------------------------ sub StartMoving { our ($canv, $x, $y) = &GetCanvasCoords(@_); @allTags = $canvas->find("closest", $x, $y); print ("Moving: $x/$y: @allTags\n"); $movx = $x; $movy = $y; $canvas->Tk::bind("<Button-1>", ""); $canvas->Tk::bind("<Button-2>", ""); $canvas->Tk::bind("<Motion>", [ \&MoveItem, Ev('x'), Ev('y') ] ); $canvas->Tk::bind("<Button-3>", [ \&EndMoving, Ev('x'), Ev('y') ] ); } # StartMoving # ------------------------------------------------------------ sub MoveItem { our ($canv, $x, $y) = &GetCanvasCoords(@_); $canvas->move($allTags[0], $x - $movx, $y - $movy); $movx = $x; $movy = $y; } # MoveItem # ------------------------------------------------------------ sub EndMoving { our ($canv, $x, $y) = &GetCanvasCoords(@_); $canvas->Tk::bind("<Motion>", ""); $canvas->Tk::bind("<Button-3>", [ \&StartMoving, Ev('x'), Ev('y') ] ); $canvas->move($allTags[0], $x - $movx, $y - $movy); &BindStart; } # EndMoving # ------------------------------------------------------------ sub CancelDrawing { my ($canv) = @_; print ("Cancel drawing\n"); $canvas->delete("drawmenow"); $canvas->dtag("drawmenow"); $canvas->Tk::bind("<Motion>", ""); $canvas->Tk::bind("<Button-2>", ""); $startx = -1; $starty = -1; $currentItem = ""; &BindStart(); } # CancelDrawing # ------------------------------------------------------------ sub StartDrawing { our ($canv, $x, $y) = &GetCanvasCoords(@_); my ($sub); # Do some error-checking $thickness = 1 if $thickness !~ /^\d+$/; our @range = ($x, $y, $x, $y); my %options = ( -width => $thickness, -tags => "drawmenow", -fill => $color, ); my ($id); if ($drawItem eq "rectangle"){ $id = $canvas->createRectangle(@range, %options); } elsif ($drawItem eq "oval"){ $id = $canvas->createArc(@range, %options); } elsif ($drawItem eq "line"){ $id = $canvas->createLine(@range, %options); } elsif ($drawItem eq "text"){ my $main = MainWindow->new; $main->Label(-text => 'Annotation Entry')->pack; # create an annot +ation label and pack it my $say = $main->Entry(-width => 100); $say->pack; $main->Button(-text => 'Enter', -command => sub{do_say($say)} )->pack; } $currentItem = $id; $startx = $x; $starty = $y; # Map Button-1 binding to &EndDrawing instead of &StartDrawing $canvas->Tk::bind("<Motion>", [\&SizeItem, Ev('x'), Ev('y') ]); $canvas->Tk::bind("<Button-1>", [\&EndDrawing, Ev('x'), Ev('y') ]); $canvas->Tk::bind("<Button-2>", \&CancelDrawing); } # StartDrawing # ------------------------------------------------------------ sub EndDrawing { our ($canv, $x, $y) = &GetCanvasCoords(@_); # finish the size of the item, and remove tag $canvas->Tk::bind("drawmenow", "<Enter>", \&DeleteItem); $canvas->coords("drawmenow", $startx, $starty, $x, $y); $canvas->dtag("drawmenow"); # remove tag $canvas->Tk::bind("<Motion>", ""); # remove motion binding push (@items, { -id => $currentItem, -color => $color, -range => [$startx, $starty, $x, $y], } ); print ("$currentItem: $color: $startx, $starty, $x, $y\n"); $currentItem = ""; $startx = -1; $starty = -1; $canvas->Tk::bind("<Button-2>", ""); &BindStart(); } # EndDrawing # ------------------------------------------------------------ sub SizeItem { our ($canv, $x, $y) = &GetCanvasCoords(@_); $canvas->coords("drawmenow", $startx, $starty, $x, $y); } # SizeItem # ------------------------------------------------------------ sub GetCanvasCoords { return ($_[0], $_[0]->canvasx($_[1]), $_[0]->canvasy($_[2]) ); } # GetCanvasCoords # ------------------------------------------------------------ sub CreateMenu { my ($mw) = shift; my $f = $mw->Frame( -relief => 'groove', -bd => 2, -label => "Draw:"); $f->pack( -side => 'left', -fill => 'y'); $f->Radiobutton ( -variable => \$drawItem, -text => "Mark Region", -value => 'rectangle', -command => \&BindStart) ->pack( -anchor => 'w'); $f->Radiobutton ( -variable => \$drawItem, -text => "Add tRNA", -value => 'oval', -command => \&BindStart) ->pack( -anchor => 'w'); $f->Radiobutton ( -variable => \$drawItem, -text => "Add rRNA", -value => 'line', -command => \&BindStart) ->pack( -anchor => 'w'); $f->Radiobutton ( -variable => \$drawItem, -text => "Add annotatio +n", -value => 'text', -command => \&BindStart) ->pack( -anchor => 'w'); $f->Radiobutton ( -variable => \$drawItem, -text => "Add Line", -value => 'line', -command => \&BindStart) ->pack( -anchor => 'w'); $f->Label( -text => "Line width:")->pack( -anchor => 'w'); $f->Entry( -textvariable => \$thickness)->pack( -anchor => 'w'); $f->Label( -text => "Color:")->pack( -anchor => 'w'); foreach (@colors){ $f->Radiobutton( -variable => \$color, -text => $_, -value => $_, -command => \&BindStart) ->pack( -anchor => 'w'); } return ($f); } sub do_say { my ($what) = @_; my $what_val = $what->get; # use get to access contents + of entry # $canvas ->createText($range[0],$range[1], -text =>"$what_val\n"); $canvas ->createText(50,50, -text =>"$what_val\n"); } # CreateMenu # ------------------------------------------------------------

Edit by tye, add READMORE tags

Replies are listed 'Best First'.
Re: How to put text on the canvas for a keyboard STDIN
by Abigail-II (Bishop) on Sep 15, 2003 at 16:09 UTC
    In particular I'm having problems passing the @array to the subroutine.

    Considering that your 222 line blob of code contains 12 subroutines, but no mentioning of "@array", your question is very mysterious. I guess you have somewhere in your 222 lines something you have problems with. But while posting code is good, posting a complete 222 line program without any indication where your problem is, is not a good idea.

    You said you wanted to put text typed in my the user directly on the canvas, but how you want to do that is unclear to me. I've looked for the bindings, but all you seem to bind are mouse related events.

    Abigail

      Abigail-II,

      I didn't mean to waste your time. I actually have a problem passing @range not @array. Basically I'm a biologist who inhereted the code and needs to try and do something with it. I'm a really bad programmer (in Perl) and don't even know how to a bind keyboard event.

      The problem area in the code is here (line 212):
      my ($what) = @_; my $what_val = $what->get; # use get to access contents + of entry $canvas ->createText($range[0],$range[1], -text=>"$what_val\n");

      I'm using this to put some text on the canvas but can't pass the @range so I can't get $range[0] & $range 1.

      If I can skip the sub all together and bind the keyboard here (line 121)
      elsif ($drawItem eq "text"){ my $main = MainWindow->new; $main->Label(-text => 'Annotation Entry')->pack; # create an annot +ation label and pack it my $say = $main->Entry(-width => 100); $say->pack; $main->Button(-text => 'Enter', -command => sub{do_say($say)} )->pack;
      without needing to call the sub, that would be great!
      Thanks in advance for any help and sorry I wasn't clear the first time.
      -Mark