Beefy Boxes and Bandwidth Generously Provided by pair Networks
Keep It Simple, Stupid
 
PerlMonks  

Re^2: Perl/Tk CanvasBind question

by rcseege (Pilgrim)
on Oct 20, 2006 at 18:19 UTC ( [id://579665]=note: print w/replies, xml ) Need Help??


in reply to Re: Perl/Tk CanvasBind question
in thread Perl/Tk CanvasBind question

Updated: Minor content edit for grammar - thanks, liverpole

Is there really ever a situation where you don't want to invoke the subroutine unless the Canvas is selected?

This is really the key question that you have to answer when doing something like this, and it is important to answer it in terms of the application you are working on. because the answer will vary. Binding to MainWindow can be a great timesaver and make the code less verbose, but it can also have unintended consequences that will bite you if you aren't careful.

For small applications such as all of the examples in this thread so far, there is no danger. The potential for problems grows with the number of widgets that make up the application. You have to be sure that the binding won't be disruptive if you apply it globally to all the widgets in your MainWindow. Take the following example:

use strict; use Tk; my $mw = MainWindow->new; my $frame = $mw->Frame->pack; $frame->Entry->pack(-side => 'left'); $frame->Button(-text => "Button")->pack(-side => 'left'); my $cv = $mw->Canvas()->pack(); $mw->bind( '<KeyPress-a>', sub { my $widget = shift; print "$widget: ouch!\n"; }); MainLoop;

When you apply a binding to a widget, the first argument that the bound sub receives is the widget being bound. If your sub depends on this, it can be a problem. Try using the tab key to traverse from one widget to the next using my example. Each widget, including the MainWindow should all trigger the binding. If the binding is global in nature (perhaps a sequence to exit the application) then maybe it's something you want

Consider another case, where your Canvas represents a game board of some kind, and you have other widgets outside that board that can accept inputs, such as Entry or Text widgets. You probably want to ensure that a key press in one of these input widgets doesn't inadvertently trigger an action within the game board.

Another common use is to create a form and then allow for the form to be submitted by pressing the Return key. Something like this, perhaps:

use strict; use Tk; use Tk::LabFrame; my $mw = MainWindow->new; my $lf = $mw->LabFrame( -labelside => 'acrosstop', -label => "My Form" )->pack(qw/-padx 10 -pady 5/); my $inFrame = $lf->Frame-> pack(qw/-padx 10 -pady 5/); $inFrame->Label(-text => "Field A: ")->grid( $inFrame->Entry(-width => 20), -pady => 2); $inFrame->Label(-text => "Field B: ")->grid( $inFrame->Entry(-width => 20), -pady => 2); $mw->Button( -text => "Submit", -command => \&Submit )->pack(-pady => 4); $mw->bind('<Key-Return>', \&Submit); MainLoop; sub Submit { print "form submitted\n"; }

This form will now trigger a Submit if someone presses the <Return> key or presses the Submit button, except in cases where the Button has focus. In those cases, Submit will be triggered twice. What about if your form has a Text widget in it. A widget in which users could conceivably type the Return key as part of the content. In this case, a submit could be triggered inadvertently.

use strict; use Tk; use Tk::LabFrame; my $mw = MainWindow->new; my $lf = $mw->LabFrame( -labelside => 'acrosstop', -label => "My Form" )->pack(qw/-padx 10 -pady 5/); my $inFrame = $lf->Frame-> pack(qw/-padx 10 -pady 5/); $inFrame->Label(-text => "Field A: ")->grid( $inFrame->Entry(-width => 20 ), -sticky => 'nw', -pady => 4); $inFrame->Label(-text => "Field B: ")->grid( $inFrame->Scrolled('Text', -scrollbars => 'osoe', -width => 15, -height => 10 ), -pady => 2, -sticky => 'nw'); $mw->Button( -text => "Submit", -command => \&Submit )->pack(-pady => 4); $mw->bind('<Key-Return>', \&Submit); MainLoop; sub Submit { print "form submitted\n"; }

The main point in all of this so far, is make sure that binding all the widgets is really what you want to do. Be sure to test to make sure the behavior is what you expect. Any of the pitfalls can be avoided without much difficulty, so long as you are aware of them.

One case where you might not want global bindings is when Canvas is being used as another widget. A Tree, Listbox, Group of checkbuttons, Notebook, are all possibilities. If you are simulating one of the other widget types you'd probably want to ensure that all the various bindings applied only to the Canvas.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: note [id://579665]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others having an uproarious good time at the Monastery: (5)
As of 2024-04-18 18:31 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found