Ткинтер и нить. из пространства стека (бесконечный цикл?)

я экспериментирую с 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 не является потокобезопасным.

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

чтобы решить ваша проблема вы должны:

  1. не имеют бесконечного цикла, который навсегда добавляется к текстовому виджету
  2. не получить доступ к виджетам из более чем одного потока

Если вы хотите запускать функцию один раз в секунду, есть лучшие способы сделать это, чем с потоками. Короче:

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'цикл событий для продолжения.