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

Calling all Tk experts, I have read the Tk tutorial here in the monastery and looked at the explanation of bind on cpan, but I can't work out why
$input->bind('<Return>', [\&mysub]); #$input is an Entry widget

Works; But
$input->bind('<Return>', [\&mysub($arg)]);

Does not. I get the message
Tk::Error: Not a CODE reference at c:\perl\site\lib\/tk.pm line 340
Is it possible to pass arguements in this way or am I missing the point?

Replies are listed 'Best First'.
Re: Binding Tk events
by davidj (Priest) on Jun 01, 2004 at 15:12 UTC
    The problem is in how you are passing the arguments to &mysub.
    The following is from "Mastering Perl/Tk":

    "When you want to pass arguments to a callbakc, specify an array reference, with the callback code reference as the first element and the callback arguments as the subsequent array elements"

    In other words: instead of
    $input->bind('<Return>', [\&mysub($arg)]);
    you need to have
    $input->bind('<Return>', [\&mysub, $arg]);

    hope this helps,
    davidj

    UPDATE
    My solution is NOT correct for calling subs with bind.
    It is only correct for calling subs with arguments when using the -command widget option.
    Please refer to dave_the_m's post below for the correct solutin.
    Sorry for the post.

    davidj
      $input->bind('<Return>', [\&mysub, $arg]);
      ... UPDATE
      My solution is NOT correct for calling subs with bind...

      On the contrary, your solution, forming an anonymous array containing a subroutine ref followed by args to be passed to the sub, is entirely correct. It's the idiom that I normally use for bind calls of this sort.

      Thanks I think this is my problem in a nut shell. Mastering perl/Tk is this an actual book or a web resource?
        Mastering Perl/Tk is an O'Reilly book. You can find it on O'Reilly's web site.

        davidj
Re: Binding Tk events
by dave_the_m (Monsignor) on Jun 01, 2004 at 15:14 UTC
    \&mysub
    creates a reference to the sub mysub;
    \&mysub(...)
    calls mysub, then creates a reference to the returned value

    I'm not familiar with TK, so I don't know what bind is supposed to do, but you might be able to achieve what you want with a closure:

    $input->bind('<Return>', [ sub { mysub($arg) } ] );

    Dave.

Re: Binding Tk events
by davidj (Priest) on Jun 01, 2004 at 18:21 UTC
    Ok, I've been a bit whacky today regarding this node.
    Maybe its because I had to work all weekend and everyone else was on vacation :).

    I will post this on the "Tk Binding mouse down" node since it is the same issue.

    here is the clarification for Calling subs/functions from tk bound widgets:

    subs/functions can be called in 3 basic ways as the following code will demonstrate.
    1) directly
    2) using the sub function
    3) using an anonymous array

    If you want to pass arguments to the called sub you will need to use method 2 or 3.

    The code below demonstrates these 3 three methods.
    Notice closely the difference between what happens in the subs called by $button2 and $button4. Specifically, $button4 requires an initial shift; because an anonymous array is being used. Without this shift the print statement in the sub would attempt to print the tk::button information (which is stored in a hash).

    code
    use Tk; use strict; my $mw = MainWindow->new(); my $button1 = $mw->Button(-text => "on release 1")->pack(); $button1->bind('<ButtonRelease 1>' => \&doit1 ); my $msg = "pressed 2"; my $button2 = $mw->Button(-text => "on realease 2")->pack(); $button2->bind('<ButtonRelease 1>' => sub { \&doit2($msg) } ); my $button3 = $mw->Button(-text => "on release 3")->pack(); $button3->bind('<ButtonRelease 1>' => [\&doit3]); my $msg1 = "pressed 4"; my $button4 = $mw->Button(-text => "on release 4")->pack(); $button4->bind('<ButtonRelease 1>' => [\&doit4, $msg1]); MainLoop; sub doit1(){ print "pressed 1\n"; } sub doit2(){ my $msg = shift; print "$msg\n"; } sub doit3(){ print "pressed 3\n"; } sub doit4(){ shift; my $msg = shift; print "$msg\n"; }

    output from pressing each button in order:
    pressed 1 pressed 2 pressed 3 pressed 4

    Finally, any thoughts about putting this in the tutorials or Q&A section? Or is it not up to par?

    davidj