如何理解POE-Tk的destroy用法?

发布于 2024-07-27 18:37:19 字数 3184 浏览 5 评论 0原文

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


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 和 Tk 之间的薄而灵活的接口。

如您所知,回发是匿名子例程引用,在调用 POE 事件时发布 POE 事件。除其他外, 是受祝福的,并且它们的 DESTROY 方法用于在 Tk 处理完它们时通知 POE,从 Tk 的角度来看,回调和回发之间的唯一区别是这种祝福,

由于某种原因,Tk 不会将参数传递给受祝福的对象 。打回来。”

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

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

Here is some test code to illustrate my problem;


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});
}

If I uncomment the version of the inline state kill_top1, all is well. If I use the version (as shown) that calls the anonymous sub, I get;


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)

In this posting [link text][1] Rocco Caputo explains;

"Tk is not passing the event information to POE.

As you know, postbacks are anonymous subroutine references that post POE events when they're called. They're used as a thin, flexible interface between POE and Tk, among other things.

Postbacks are blessed, and their DESTROY methods are used to notify POE when Tk is done with them. From Tk's point of view, the only difference between a callback and a postback is this blessing.

For some reason, Tk does not pass parameters to a blessed callback."

He gives a workaround, but I am not sure 1) if this is the issue I have uncovered or )2 if it is, how to apply the workaround.

[1]: http://osdir.com/ml/lang.perl.poe/2004-01/msg00002.html :Tk With POE - bind() function for keypresses"

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

坐在坟头思考人生 2024-08-03 18:37:19

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

使用闭包似乎可行,但如果您想“伪造”它,您可以将其替换为:

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

这将是我的偏好,只是为了保持kill_top1 的接口和事件处理与所有其他相同。

It sure looks like you've hit the problem that Rocco is describing. Basically, your closure (the sub {...}) has access to $heap because $heap is in scope when you create the closure. On the other hand, when you use the &kill_top1 function reference it appears you're not getting any parameters passed in, which means @_[HEAP] is undefined.

Using the closure seems to work, but if you wanted to "fake" it, you could replace it with:

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

This would be my preference, just to keep the interface to, and event handling of, kill_top1 the same as all the others.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文