2011-12-30 3 views
35

Каждый учебник tkinter Я видел утверждения, что tkinter.mainloop должен вызываться для окон, которые нужно нарисовать, и событий, которые нужно обработать, и они всегда называют эту функцию даже в приветственных программах мира. Однако, когда я пытаюсь выполнить их в интерактивной оболочке, окна рисуются правильно, без вызова mainloop. This example встраивания графики matplotlib в tkinter создает относительно сложное приложение с кнопками для панорамирования, масштабирования и изменения размера графика в окне tkinter, и снова это все работает, если вы удалите вызов mainloop и запустите код в интерактивной оболочке. Конечно, если я запустил скрипт (с удалением mainloop) вне интерактивной оболочки, программа закончится слишком быстро, чтобы узнать, что произойдет, но если я добавлю вызов input, чтобы держать программу открытой, все работает правильно (я запускаю python 3.2.2 на linux).Когда мне нужно вызвать mainloop в приложении Tkinter?

Так что же конкретно делает mainloop, и когда это необходимо назвать?

EDIT: Чтобы уточнить, если я открываю терминал GNOME и введите

$python3 
>>> import tkinter 
>>> root = tkinter.Tk() 

сразу появляется окно без вызова MainLoop, и более сложные функциональные Tkinter, кажется, работает, как хорошо (например, добавление кнопок в окно). В IDLE необходим вызов mainloop. Насколько я понимаю, ничто не должно быть нарисовано, и никакие события не должны обрабатываться до тех пор, пока не назовут mainloop.

ответ

38

Ответ на ваш основной вопрос: вы должны звонить mainloop один раз и только один раз, когда вы готовы для запуска своего приложения.

mainloop не намного больше, чем бесконечный цикл, который выглядит примерно так (это не те фактические имена методов, имена служат только для иллюстрации точки):

while True: 
    event=wait_for_event() 
    event.process() 
    if main_window_has_been_destroyed(): 
     break 

В этом контексте , «событие» означает как пользовательские взаимодействия (щелчки мыши, нажатия клавиш и т. д.), так и запросы от инструментария или диспетчера OS/window для рисования или перерисовки виджета. Если этот цикл не запущен, события не обрабатываются. Если события не обработаны, на экране ничего не появится, и ваша программа, скорее всего, выйдет, если у вас нет собственного бесконечного цикла.

Итак, почему бы вам не назвать это интерактивно? Это просто удобство, потому что иначе было бы невозможно вводить какие-либо команды, как только вы вызываете mainloop, так как mainloop работает до тех пор, пока основное окно не будет уничтожено.

7

Сравните программу с интерактивным графическим интерфейсом с программой, которая вычисляет сотый номер Фибоначчи. Вся последняя программа должна пройти последовательность шагов, сверху вниз. Набор шагов и их последовательность могут быть известны заранее, и он останется постоянным независимо от того, сколько раз вы запускаете программу.

Но программа графического интерфейса отличается: в любой момент он должен иметь возможность обрабатывать различные виды событий и взаимодействий. Это требование часто реализуется с использованием конструкции программирования, называемой циклом событий. Цикл событий является центральной структурой управления программой. Он ожидает события, а затем отправляет соответствующий обработчик.

Вы не указали, какую интерактивную оболочку вы используете, но я предполагаю, что это ИДЕТ. IDLE сам является программой Tkinter, и у нее уже есть цикл событий. Таким образом, возможно, код Tkinter, который вы вводите в оболочку, привязывается к циклу событий IDLE.

+0

К сожалению, я уже говорил: я только с помощью стандартной оболочки Python (не IDLE) в терминале GNOME (который, очевидно, написан в C). Итак, насколько я вижу, ничто, кроме моего собственного кода, не должно делать ничего, что влияет на tkinter. – James

+1

Я только что пробовал одно и то же в IDLE, и я не получаю такого же поведения - окна не появляются, пока я не позвоню mainloop. – James

-3

Я решил, что вместо того, чтобы прибегать к вызову непосредственно в mainloop в любом месте моего сценария, я просто добавлю его как часть atexit - то есть, когда интерпретатор Python решает, что пришло время начать закрытие, это собирается войти в главный замок Tk. Это то мешает ему закончить закрыть последовательность, пока пользователь на самом деле не говорит Tk, чтобы бросить курить (IE, с командой-Q на Mac, или нажав на красный крестик в Windows.)

from Tkinter import Tk 
root = Tk() 

import atexit 
atexit.register(root.mainloop) 

Там, кажется, не нужно вызывать mainloop из командной строки системы. Интерпретатор Python будет продолжать работать без него, потому что он ждет ввода от вас (пока вы не запустите exit()).

+1

_ «Мне кажется, что единственное, что позвонит mainloop, - это то, что ваше приложение автоматически закрывается» _: это неправильная оценка. Он управляет очередью событий, что значительно больше, чем просто отказ приложения от выхода. Кроме того, вы даже не делаете то, что думаете, что делаете: вы на самом деле вызываете 'mainloop()' сразу, а не во время выхода. –

+1

@BryanOakley - Упс, я исправил этот случайный вызов 'mainloop()' - теперь он зарегистрирован, как и должно быть. В любом случае, я считаю, что вы неверны. В вашем ответе вы говорите, что вам не нужно называть mainloop в интерактивном интерактивном режиме «просто удобство». Что, что? Если это удобная вещь, то что-то, либо интерактивный интерпретатор, либо модуль 'Tkinter' должен содержать специальный код, который позволяет это. Я не считаю, что код существует. Там нет документации, в которой говорится, что это так. Бремя лежит на вас, чтобы доказать, что mainloop - это волшебство, как вы говорите. – ArtOfWarfare

+0

Я никогда не слышал об atexit, и я рад, что нашел этот ответ, поскольку он позволяет мне называть приложение Tk() во время unittesting без необходимости вручную закрывать приложение. –

-3

Как следует:

from tkinter import * 

tk = Tk() 
canvas = Canvas(tk, width=500, height=500) 
canvas.pack() 
canvas.create_line(0, 0, 500, 500) 

mainloop() 
Смежные вопросы