2

これが私の問題を説明するためのいくつかのテストコードです。


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]RoccoCaputoが説明しています。

「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 with POE-キーを押すためのbind()関数 "

4

1 に答える 1

3

ロッコが説明している問題にぶつかったようです。基本的に、クロージャー(サブ{...})は$ heapにアクセスできます。これは、クロージャーを作成するときに$heapがスコープ内にあるためです。一方、&kill_top1関数参照を使用すると、パラメーターが渡されていないように見えます。つまり、@_[HEAP]は未定義です。

クロージャーの使用は機能しているようですが、「偽造」したい場合は、次のように置き換えることができます。

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

これは、kill_top1へのインターフェイスとイベント処理を他のすべてと同じに保つための私の好みです。

于 2009-07-18T10:36:32.590 に答える