1

Perl Tkxを使用して、ユーザーからいくつかの入力を取得し、ウィンドウを閉じて、後でもう一度やり直したいと思います。ユーザー入力については、いくつかのボタンを表示しているだけで、ユーザーはそのうちの1つをクリックすることができます。これが私が今持っているものです:

sub prompt_user {
  my $answer;
  my $mw = Tkx::widget->new(".");   ## the main window is unavailable the second time
  $mw->g_wm_title("Window Title");  ## line 40
  $mw->g_wm_minsize(300, 200);

  my $label = $mw->new_label( -text => "Question to the user?");
  $label->g_pack( -padx => 10, -pady => 10);

  my $button1 = $mw->new_button(
          -text => "Option One",
          -command => sub { $answer = 0; $mw->g_destroy; },
         );
  $button1->g_pack( -padx => 10, -pady => 10);
  my $button2 = $mw->new_button(
          -text => "Option Two",
          -command => sub { $answer = 1; $mw->g_destroy; },
         );
  $button2->g_pack( -padx => 10, -pady => 10);
  Tkx::MainLoop();     ## This blocks until the main window is killed

  return $answer;
}

したがって、ユーザーがボタンの1つをクリックすると、ウィンドウが閉じ、prompt_user()は0または1(ユーザーがクリックしたボタンに応じて)を返し、実行が続行されます。もう一度ユーザーにプロンプ​​トを表示しようとするまで。次に、エラーが発生します。

can't invoke "wm" command:  application has been destroyed at MyFile.pm line 40

たくさんのボタンを配置し、ユーザーに1つをクリックさせ、どのボタンがクリックされるかを確認して、後でもう一度実行する方法が必要です。メインウィンドウを破壊せずにボタンクリックへの応答を待つ方法はありますか?たぶんサブウィンドウを作成しますか?

私はTkxを初めて使用し、グーグルで上記のコード(MainLoop / g_destroyを使用)のような簡単な例をたくさん示していますが、ウィンドウを再作成する例は見つかりませんでした。ダイアログボックスやメッセージボックスについては見たことがありますが、それらは私のニーズに合いません。ボタンにテキストを入れて、任意の数のボタンを使用したい(したがって、はい/いいえ/キャンセルに制限されることはなく、3つのオプションしかありません)。

更新 これが私が使用できたものです

# hide the main window, since I'm not using it
my $mw = Tkx::widget->new(".");
$mw->g_wm_withdraw();

# function to prompt the user to answer a question
# displays an arbitrary number of answers, each on its own button
sub prompt {
  my $prompt = shift;
  my $list_of_answers = shift;

  # Note:  the window name doesn't matter, as long as it's './something'
  my $answer = Tkx::tk___dialog( "./mywindowpath", # window name
        "Prompt",            # window title
        $prompt,             # text to display
        undef,               # tk bmp library icon
        undef,               # default button
        @$list_of_answers);  # list of strings to use as buttons

  return $answer;
}

# use the button to ask a question
my $index = prompt("Who was the best captain?",
                   [ "Kirk", "Picard", "Cisco", "Janeway", "Archer" ] );
4

1 に答える 1

2

私はTkxにあまり詳しくありませんが、Tkはそのようにはうまく機能しません。一般に、Tkアプリケーションは非同期です。コールバック(javascriptのようなもの)の観点からアプリケーションを書き直す必要があります。

基本的に、この種のロジック:

sub do_something {

    perform_some_action();

    my $result = prompt_user();

    perform_some_other_action($result);
}

次のように書き直す必要があります。

sub do_something {

    perform_some_action();

    prompt_user(perform_some_other_action);
}

プログラムには基本的にメインループがないはずです。代わりに、プログラムの最後での呼び出しがTkx::MainLoopメインループになり、イベントを処理してすべての処理を実行する必要があります。

そうは言っても、ブロッキングをエミュレートするいくつかのメカニズムが利用可能です。のドキュメントをお読みくださいvwait。ただし、それでも実行が必要でTkx::MainLoopあるため、プログラム全体のリファクタリングを必ずしも回避できるとは限りません。

ウィンドウを作成および破棄する方法については、次の2つの解決策があります。

  1. メインウィンドウ(.)を使用しますが、最後に破棄しないでください。代わりにそれを隠し、そのすべての子供たちを破壊します。その後、非表示を解除して再利用できます.

  2. 非表示.にして使用しないでください。代わりに、他のウィンドウ(トップレベル)を作成して使用してください。トップレベルはその子である.ため、Tkを台無しにすることなく安全に破壊できます。

于 2010-12-07T04:13:03.940 に答える