如何理解POEM-使用破坏?

时间:2009-07-17 20:30:34

标签: perl tk poe

以下是一些测试代码来说明我的问题;


use Tk;
use POE qw( Loop::TkActiveState );
use Tk::Toplevel;

POE::Session->create(
    inline_states => {
        _start      => \&ui_start
        ,top1       => \&top1
        ,top2       => \&top2
#       ,kill_top1  => \&kill_top1
        ,kill_top1  =>  sub {
            $heap->{tl1}->destroy;
        }
        ,over       => sub { exit }
    }
);

$poe_kernel->run();
exit 0;

sub ui_start {
    my ($kernel, $session, $heap) = @_[KERNEL, SESSION, HEAP];
    $heap->{mw} = $poe_main_window;
    $but1 = $heap->{mw}->Button(
        -text => 'Exit',
        -width => 12,
        -command => $session->postback("over")
    )->pack( -padx => 7,
        -side => 'left',
        -expand => 0 );

    $but2 = $heap->{mw}->Button(
        -text => 'Top1',
        -width => 12,
        -command => $session->postback("top1")
    )->pack( -padx => 7,
        -side => 'left',
        -expand => 0 );
    $but2 = $heap->{mw}->Button(
        -text => 'Top2',
        -width => 12,
        -command => $session->postback("top2")
    )->pack( -padx => 7,
        -side => 'left',
        -expand => 0 );
    $but3 = $heap->{mw}->Button(
        -text => 'Kill TL',
        -width => 12,
        -command => $session->postback("kill_top1")
    )->pack( -padx => 7,
        -side => 'left',
        -expand => 0 );
}

sub top1 {
    my ($kernel, $session, $heap) = @_[KERNEL, SESSION, HEAP];
    unless(Tk::Exists($heap->{tl1})) {
        $heap->{tl1} = $heap->{mw}->Toplevel( title => "Top1");
    }
}   

sub top2 {
    my ($kernel, $session, $heap) = @_[KERNEL, SESSION, HEAP];
    $heap->{tl2} = $heap->{mw}->Toplevel( title => "Top2");
    $heap->{tl1}->destroy if Tk::Exists($heap->{tl1});
}   

sub kill_top1 {
    my ($kernel, $session, $heap) = @_[KERNEL, SESSION, HEAP];
    $heap->{tl1}->destroy if Tk::Exists($heap->{tl1});
}

如果我取消注释内联状态kill_top1的版本,一切都很好。如果我使用调用匿名子的版本(如图所示),我会得到;


C:\scripts\alias\resource>alias_poe_V-3_0_par.pl
 error:Can't call method "destroy" on an undefined value at C:\scripts\alias\res
ource\alias_poe_V-3_0_par.pl line 328,  line 365.

Tk::Error: Can't call method "destroy" on an undefined value at C:\scripts\alias
\resource\alias_poe_V-3_0_par.pl line 328,  line 365.
 Tk::After::once at C:/Perl/site/lib/Tk/After.pm line 89
 [once,[{},undef,100,once,[\&POE::Kernel::_poll_for_io]]]
 ("after" script)

在这篇帖子中[链接文字] [1] Rocco Caputo解释说;

“Tk未将事件信息传递给POE。

如您所知,回发是匿名子例程引用,它们在调用时发布POE事件。它们被用作POE和Tk之间的薄而灵活的界面,等等。

回发受到祝福,他们的DESTROY方法用于在Tk完成后通知POE。从Tk的角度来看,回调和回发之间的唯一区别就是祝福。

出于某种原因,Tk不会将参数传递给受祝福的回调。“

他给出了一个解决方法,但我不确定1)这是否是我发现的问题或者)2如果是,如何应用解决方法。

[1]:http://osdir.com/ml/lang.perl.poe/2004-01/msg00002.html:Tk与POE - 用于按键的bind()函数“

1 个答案:

答案 0 :(得分:3)

看起来你确实遇到了Rocco所描述的问题。基本上,你的闭包(sub {...})可以访问$ heap,因为在创建闭包时$ heap在范围内。另一方面,当你使用& kill_top1函数引用时,你似乎没有传入任何参数,这意味着@_ [HEAP]是未定义的。

使用闭包似乎有效,但如果你想“伪造”它,你可以用以下代码替换它:

kill_top1 => sub { 
    @args[KERNEL,SESSION,HEAP] = ($kernel,$session,$heap);
    kill_top1(@args);
}

这是我的首选,只是为了使kill_top1的接口和事件处理与其他所有接口相同。