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

Hi all, I have a Perl/Tk question for which I haven't been able to find an answer in the excellent "Mastering Perl/Tk" book. I am creating a database interface for use on Windows, and so far Tk has been perfect for it. Here's my problem. I've created two items on a drop-down menu to control the sort method applied to the results of a db query. If the user selects option 1, she'll get a list of products sorted by item number. If she selects option 2, she'll get the same list, sorted by sales dollars. So I set it up by passing different parameters to the subroutine which does the query. Like so:
$action->command(-label=>"Sort by Number",-command=>\&queryDB("item_nu +mber")); $action->command(-label=>"Sort by Sales",-command=>\&queryDB("tot_sale +s"));
The query works perfectly, but the weird thing is that when I'm passing parameters like this, it runs automatically each time I start the application, whether or not I've selected either one of the menu choices! The product list comes back twice, sorted once by dollar sales, and once by product number. If anyone can see what I'm doing wrong, or if you know of a Tk-specific method of passing parameters to a subroutine, I would be most deeply indebted to you.

Thanks very much,
a Tk novice

Replies are listed 'Best First'.
Re: Perl/Tk parameters
by stephen (Priest) on Apr 15, 2002 at 17:06 UTC

    Actually, the problem has nothing to do with Tk per se. What you're trying to do is pass Tk a reference to a subroutine to call later on. Unfortunately, you're trying to pass arguments at the same time, which means that Perl thinks you're telling it to call the subroutine immediately at runtime and pass to Tk a reference to what the subroutine returns. So if I did this:

    use strict; sub vert { my ($arg) = @_; print "Arg is $arg\n"; return 'text'; } # Correct way of creating subroutine reference my $sub_ref = \| # Will print "Arg is foo" &$sub_ref('foo'); # Incorrect attempt at creating a subroutine reference # Will print "Arg is bar" as a side effect my $not_sub_ref = \&vert('bar'); # Will die horribly, since $not_sub_ref is a reference # to the string 'text' (the return value of &vert), # not a reference to a subroutine &$not_sub_ref();

    To get a reference to a subroutine that will call queryDB with the right parameters when you click the button, do this:

    #untested $action->command(-label=>"Sort by Number",-command=> sub { &queryDB("i +tem_number") }); $action->command(-label=>"Sort by Sales",-command=>sub { &queryDB("tot +_sales") });

    When you say sub { ... } without naming the subroutine, perl creates an anonymous subroutine and returns the reference. See perlman:perlref and perlman:perlsub for more information.

    stephen

    Update: Added additional explanaton.

      Absolutely brilliant! Thank you both very much for the kind explanations. I don't use references often, so this stuff never occurred to me. This problem was driving me nuts all last week. Thanks again!
Re: Perl/Tk parameters
by danboo (Beadle) on Apr 15, 2002 at 17:02 UTC
    You can't actually capture the subref with arguments in this manner. It's actually calling the sub immediately and your callback ends up being a reference to whatever is returned by your sub. To get around this, Tk callbacks accept the subref and arguments as an anonymous arrayref. See 'perldoc Tk::callbacks' for details but what you want is:
    $action->command(-label=>"Sort by Number", -command => [\&queryDB, 'it +em_number']);
    ... and likewise for the other.

    - danboo