Как я могу неоднократно предлагать пользователю 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
поэтому не обязательно избегать рефакторинга всей вашей программы.
На вопрос о том, как создавать и уничтожать окна, существует два решения:
Используйте главное окно (
.
) но не разрушайте это в конце. Вместо этого спрячь его и уничтожь всех его детей. Вы можете позже использовать.
скрывая это.Спрятать
.
и не используйте его. Вместо этого создайте другие окна (toplevels) и используйте их. Так как на высшем уровне дети.
они безопасны, чтобы уничтожить, не облажаясь Tk.