2010-12-07 11 views
1

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

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

したがって、ユーザーがいずれかのボタンをクリックすると、ウィンドウが閉じprompt_user()(ユーザーがクリックによってどのボタンで)0または1を返し、実行が継続されます。私は再びユーザーにプロンプ​​トを表示しようとするまで。その後、私はエラーを取得:

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

私はちょうどたいユーザーがクリックされた1を参照するのを待つ、いずれかをクリックしてみましょう、ボタンの束を設置する方法を、多分後でもう一度それを行います。メインウィンドウを破壊することなくボタンクリックに対する応答を待つ方法はありますか?おそらくサブウィンドウを作りますか?

私はTkxを使い始めたばかりで、グーグルでは上記のコード(MainLoop/g_destroyを使用)のような簡単な例がたくさんありますが、ウィンドウを再作成する例は見つかりませんでした。私はダイアログボックスやメッセージボックスについての情報を見たことがありますが、それらは私のニーズに合っていません。私はボタンにテキストを置き、任意の数のボタンを使用したい(私はyes/no/cancelに制限されたくないので、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" ]); 
+0

より良い応答を得るためにtkタグが追加されました。 – slebetman

+1

時にはGUI要素をポップアップするコマンドラインプログラム(GUIなし)を作成しようとしていますか?それは可能だが、扱いにくい。 –

+0

@Michael - はい、まさに私がやろうとしていることです。はい、それはするのが厄介なようです。 – Tim

答えて

2

私はTKXと本当に慣れていないんだけどTkは本当によくそのように動作しません使用することができたものです。一般に、Tkアプリケーションは非同期です。コールバック(javascriptのようなもの)の期間にアプリケーションを書き直すべきです。

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

sub do_something { 

    perform_some_action(); 

    prompt_user(perform_some_other_action); 
} 

あなたのプログラムは基本的にメインループを持つべきではありません。

sub do_something { 

    perform_some_action(); 

    my $result = prompt_user(); 

    perform_some_other_action($result); 
} 

のようなものに再記述する必要があります。代わりに、プログラムの最後にTkx::MainLoopへの呼び出しがメインループになり、イベントを処理することによってすべての処理を行う必要があります。

これまでに、ブロックをエミュレートするいくつかのメカニズムがあります。文書番号vwaitを読んでください。しかし、それでも実行するにはTkx::MainLoopが必要だと思うので、必ずしもすべてのプログラムをリファクタリングする必要はありません。

  1. は、メインウィンドウ(.)を使用しますが、最後にそれを破壊していない2つの解決策があるウィンドウを作成し、破壊する方法の質問に

    。代わりにそれを隠し、すべての子供を破壊してください。その後、.を再表示して再表示することができます。

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

+0

私はオプション2が好きですが、他のウィンドウを作成して '。'を隠す方法は?私はこれを行うために必要な実際の関数呼び出しを見つけることができませんでした。 – Tim

+1

Tkxドキュメントを見て、非常に短いと判断しました。すべての情報はそこにありますが、TclやTkに関する事前知識があることを前提としています。ドキュメントから 'my $ window = $ mw-> new_toplevel'を実行することでウィンドウを作成できるようです。作成できるウィジェットを知るには、Tkのマニュアルを読む必要があります:http://www.tcl.tk/man/tcl8.5/TkCmd/contents.htm – slebetman

+1

OK、メインウィンドウを隠して、さらにドキュメントを読んでいる: '$ mw-> g_wm_withdraw()' Tkxはtcl/tkの周りの薄いラッパーにはあまりにも悪くはありません。ほとんどのものはAUTOLOADによって処理され、直接Tclインタプリタに転送されます。これは、Tkが行うことができるすべてのもの(Tkの将来のバージョンでさえも)をサポートする素敵な一般的な方法です。唯一のことは、ドキュメントを改善して、tclに精通していない人にも使えるようにすることだと思います。しかし、Tk自体は十分に文書化されているので、それほど悪くはありません。 – slebetman