Ткинтер и нить. из пространства стека (бесконечный цикл?)
я экспериментирую с Tkinter и механизмом потоков. Может кто-нибудь объяснить, почему это вызывает исключение:
<class '_tkinter.TclError'> out of stack space (infinite loop?)
и как я могу решить это? Ниже приведен код. Кстати, я знаю, что некоторые люди предлагают использовать модуль threading вместо thread, но пока я хотел бы использовать модуль thread, который проще просто представить себе механизм.
from Tkinter import *
import thread
import time
def main_thread(master):
try:
frame = Frame(master)
frame.pack(side='bottom')
scrollbar = Scrollbar(master)
scrollbar.pack(side='right',fill='y')
t = "Title"
title = StringVar()
title.set(t)
ttl = Label(master, textvariable=title, font=("Helvetica", 18))
ttl.pack(side='top')
cont = Text(master, font=("Helvetica",14), yscrollcommand=scrollbar.set)
cont.pack(side='bottom')
button = Button(frame,text="Exit", command=root.destroy)
button.pack(side='bottom')
n = 0
while 1:
n += 1
cont.insert('end', str(n)+"n")
time.sleep(1)
except Exception as e:
print type(e), e
if __name__ == '__main__':
root = Tk()
root.title("My counting application")
thread.start_new_thread(main_thread, (root,)) # FIXME: out of stack space (infinite loop?)
root.mainloop()
спасибо, Лука!--7-->
редактировать
я решил подставляя
n = 0
while 1:
n += 1
cont.insert('end', str(n)+"n")
time.sleep(1)
С
n = 0
def do_every_second(n):
cont.insert("end", str(n) + "n")
n += 1
master.after(1000, do_every_second, n)
do_every_second(n)
, а вызов
main_thread(root)
вместо
thread.start_new_thread(main_thread, (root,))
2 ответов
у вас есть несколько роковых ошибок в коде. Во-первых, вы просто не можете написать код, который касается виджетов tkinter из нескольких потоков. Вы создаете корневое окно в главном потоке, поэтому вы можете напрямую обращаться к виджетам только из основного потока. Tkinter не является потокобезопасным.
вторая проблема заключается в том, что у вас есть бесконечный цикл, который постоянно добавляя в текст виджета. У него нет выбора, кроме как в конечном итоге исчерпать память.
чтобы решить ваша проблема вы должны:
- не имеют бесконечного цикла, который навсегда добавляется к текстовому виджету
- не получить доступ к виджетам из более чем одного потока
Если вы хотите запускать функцию один раз в секунду, есть лучшие способы сделать это, чем с потоками. Короче:
def do_every_second():
cont.insert("end", str(n) + "\n")
root.after(1000, do_every_second)
Это заставит do_every_second делать все, что он делает, а затем организует для себя вызов снова в одну секунду в будущем.
ошибка правильная - есть бесконечный цикл на одном из tkinter
элементы. The thread
модуль не имеет к этому никакого отношения. Конкретная строка, вызывающая ошибку:
cont.insert('end', str(n)+"\n")
С cont
является элементом tkinter, вы не можете запустить его в бесконечном цикле while. Чтобы сделать то, что вы хотите, вам нужно будет распечатать на консоли. Это можно продемонстрировать, если заменить оскорбительную строку простым:
print(str(n)+"\n")
Edit: если вы действительно хотите достичь тот же эффект, который вы первоначально намеревались,этот пост имеет дело с потенциальной альтернативой.
Edit2: я бы предположил, что исключение-это выбор дизайна tkinter
библиотека (хотя я не эксперт). Это имело бы смысл, так как tkinter
уже использует бесконечный цикл для своего цикла событий. Я бы предположил, что бесконечный цикл предотвратит tkinter
от когда-либо рисования изменений на экране, а вместо этого авторы библиотек решили бросить исключение вместо этого. А print
должно работать, так как нет ничего нового для рисования, плюс это в его собственном потоке, позволяющем tkinter
'цикл событий для продолжения.