以下是一些测试代码来说明我的问题;
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()函数“
答案 0 :(得分:3)
看起来你确实遇到了Rocco所描述的问题。基本上,你的闭包(sub {...})可以访问$ heap,因为在创建闭包时$ heap在范围内。另一方面,当你使用& kill_top1函数引用时,你似乎没有传入任何参数,这意味着@_ [HEAP]是未定义的。
使用闭包似乎有效,但如果你想“伪造”它,你可以用以下代码替换它:
kill_top1 => sub {
@args[KERNEL,SESSION,HEAP] = ($kernel,$session,$heap);
kill_top1(@args);
}
这是我的首选,只是为了使kill_top1的接口和事件处理与其他所有接口相同。