Perl + Tk:将 (Scrolled/Listbox) 小部件引用传递给子例程

Perl + Tk: pass a (Scrolled/Listbox) widget reference to a subroutine

我在将列表框引用从一个子例程传递到另一个子例程时遇到问题。最后我想做的是:在 BoxA 中的 selection 中找出 selected 项目的值是什么,并根据该值在 boxB 中找到 select someting。

#!/usr/bin/perl -w
use Tk;
use strict;
use warnings;

my $mw = MainWindow -> new();
my @arr = qw(1 2 3 4 5);
my $button = $mw -> Button (-text=>"Push me", -command => \&buttonCall) -> pack;

sub callee{
        my $boxARef = $_[0];
        my $boxBRef = $_[1];
        my $index = $boxARef -> curselection();
        $boxBRef -> selectionSet($index);
}

sub buttonCall{
        my $boxA = $mw -> Listbox(-exportselection=>0, -selectmode => 'browse') -> pack;
        $boxA -> insert('end', @arr);
        my $boxB = $mw -> Listbox(-exportselection=>0, -selectmode => 'multiple') -> pack;
        $boxB -> insert('end', @arr);
        $boxA -> bind ('<<ListboxSelect>>' => [\&callee,$boxA,$boxB] );
}

MainLoop;

执行代码结果:

Tk::Error: Can't call method "selectionSet" on unblessed reference at ./stack-test.pl line 14.
 <<ListboxSelect>>
 (command bound to event)

我是 Perl 的新手,非常感谢任何参考资料方面的帮助。

buttonCall() 中创建的框的引用似乎有些奇怪。以下对我有用:

use strict;
use warnings;
use Tk;

my $mw = MainWindow -> new();
my @arr = qw(1 2 3 4 5);
my $boxA;
my $boxB;
my $button = $mw -> Button (
    -text=>"Push me",
    -command => sub { buttonCall( $boxA, $boxB ) }
) -> pack;

sub callee{
    my ( $boxARef, $boxBRef ) = @_;

    my $index = $$boxARef -> curselection();
    $$boxBRef -> selectionSet($index);
}

sub buttonCall{
    my ( $boxARef, $boxBRef ) = @_;
    if ( !defined $$boxARef ) {
        $$boxARef = $mw -> Listbox(-exportselection=>0, -selectmode => 'browse') -> pack;
        $$boxARef -> insert('end', @arr);
        $$boxBRef = $mw -> Listbox(
            -exportselection=>0, -selectmode => 'multiple'
        ) -> pack;
        $$boxBRef -> insert('end', @arr);
        $$boxARef -> bind ('<<ListboxSelect>>' => sub { callee( $boxARef, $boxBRef) });
    }
}

MainLoop;

有两个问题:

如果您使用 [coderef, arg, arg...] 形式指定 Tk 回调,将始终使用触发事件的小部件调用 coderef 作为第一个参数传递。那就是你的$_[0]。您要传递的两个参数将以 $_[1]$_[2].

结尾

您的变量 $boxA$boxB 已经是引用,但您使用额外的 \ 运算符传递它们。这意味着在尝试对它们调用 Tk 方法之前,您必须在回调子中取消引用它们。 - 或者在回调定义中删除 \

use Tk;
use strict;
use warnings;

my $mw = MainWindow -> new();
my @arr = qw(1 2 3 4 5);
my $button = $mw -> Button (-text=>"Push me", -command => \&buttonCall) -> pack;

sub callee{
        my $boxARef = $_[1];
        my $boxBRef = $_[2];
        my $index = $boxARef -> curselection();
        $boxBRef -> selectionSet($index);
}

sub buttonCall{
        my $boxA = $mw -> Listbox(-exportselection=>0, -selectmode => 'browse') -> pack;
        $boxA -> insert('end', @arr);
        my $boxB = $mw -> Listbox(-exportselection=>0, -selectmode => 'multiple') -> pack;
        $boxB -> insert('end', @arr);
        $boxA -> bind ('<<ListboxSelect>>' => [\&callee,$boxA,$boxB] );
}

MainLoop;