Почему метод обновления в Tkinter приводит к зависанию окна?

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

from Tkinter import *
root = Tk()
c = Canvas()
c.pack()
c.create_line(10,10, 30, 30)
root.update()

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


person Michael Chav    schedule 22.06.2015    source источник
comment
почему вы хотите заменить mainloop() на update()?   -  person fferri    schedule 22.06.2015
comment
Вы действительно имеете в виду, что программа вылетает или просто закрывается?   -  person Bryan Oakley    schedule 22.06.2015
comment
Он становится невосприимчивым.   -  person Michael Chav    schedule 22.06.2015
comment
точный код в вашем вопросе зависает?   -  person Bryan Oakley    schedule 22.06.2015
comment
Да. Попытайся. Он просто перестает отвечать, и вам приходится принудительно закрывать окно.   -  person Michael Chav    schedule 22.06.2015
comment
Какая платформа? Я не понимаю, как он может перестать отвечать на запросы, если он вызывается в основном потоке приложения без других потоков. Как только root.update() возвращается, программе ничего не остается, кроме как выйти, и ничто не мешает ей вернуться.   -  person Bryan Oakley    schedule 22.06.2015
comment
Учитывая, что точный код даже не запустится, я думаю, что должны быть какие-то детали, которые вы упустили.   -  person Bryan Oakley    schedule 22.06.2015
comment
Я запускал ваш код как в OSX, так и в Windows, и в обоих случаях он завершается, а не зависает, как и ожидалось. Вы работаете на линуксе?   -  person Bryan Oakley    schedule 22.06.2015


Ответы (2)


update() просто обрабатывает события один раз.

mainloop() (как следует из названия) — это цикл, непрерывно обрабатывающий события.

В вашем коде вы вызываете root.update() только один раз, поэтому ваша программа перестает отвечать на запросы или завершается.

Поместите вызов root.update() в цикл while, и он будет работать как положено:

while True:
    root.update()

Однако, если это решит вашу проблему, возможно, вы просто хотите позвонить root.mainloop().

person fferri    schedule 22.06.2015
comment
Почему вы рекомендуете помещать update в цикл, а не вызывать mainloop? Ваше решение немного менее эффективно, чем вызов mainloop. - person Bryan Oakley; 22.06.2015
comment
Предпосылка OP заключается в том, чтобы не использовать mainloop(). У меня нет предвзятости к тому или иному решению. - person fferri; 22.06.2015

Причина, по которой он завершает работу (не падает), заключается в том, что он сделал все, о чем вы его просили. Вы сказали ему обрабатывать любые ожидающие события, а затем, как и в любой другой программе на Python, когда в ней заканчиваются операторы, она завершается.

Графический интерфейс должен иметь возможность непрерывно обрабатывать события. В tkinter вы делаете это, вызывая метод mainloop корневого окна. Это не вернется (и, следовательно, ваша программа не завершится), пока корневое окно не будет уничтожено.

from Tkinter import *
root = Tk()
...
root.mainloop()

Если ваш реальный код выполняется в потоке, проблема, скорее всего, связана с потоками. Точный код в вашем вопросе при запуске в однопоточном интерпретаторе завершится почти сразу после отображения корневого окна.

person Bryan Oakley    schedule 22.06.2015
comment
Он не выходит. Он просто зависает и перестает реагировать на ввод. Я думаю, это авария, да? - person Michael Chav; 22.06.2015