Как я могу неоднократно предлагать пользователю Tkx?

Используя Perl 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

Я просто хочу как-то поднять кучу кнопок, позволить пользователю нажать одну, подождать, чтобы увидеть, какая из них нажата, и, возможно, сделать это позже. Можно ли как-то дождаться ответа на нажатие кнопки, не разрушая главное окно? Может быть, создать подокно?

Я новичок в использовании Tkx, и поиск в Google показывает множество простых примеров, таких как приведенный выше код (с использованием 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" ] );

1 ответ

Решение

Я не очень знаком с 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 поэтому не обязательно избегать рефакторинга всей вашей программы.

На вопрос о том, как создавать и уничтожать окна, существует два решения:

  1. Используйте главное окно (.) но не разрушайте это в конце. Вместо этого спрячь его и уничтожь всех его детей. Вы можете позже использовать . скрывая это.

  2. Спрятать . и не используйте его. Вместо этого создайте другие окна (toplevels) и используйте их. Так как на высшем уровне дети . они безопасны, чтобы уничтожить, не облажаясь Tk.

Другие вопросы по тегам