Скрипт многопоточного Tkinter аварийно завершает работу при создании второго виджета Toplevel

У меня есть скрипт Python, который использует Tkinter для графического интерфейса. Мой маленький скрипт должен создавать виджет Toplevel каждые X секунд. Когда я запускаю свой код, первый виджет Toplevel создается успешно, но когда он пытается создать второй, происходит сбой программы.

Что я делаю, так это использую метод after для вызова функции startCounting каждые 5 секунд вместе с основной цепью root. Каждый раз, когда вызывается эта функция, я добавляю объект виджета Toplevel в список и запускаю новый поток, который, будем надеяться, будет выполнять новый основной цикл.

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

Код:

import threading,thread
from Tkinter import *


def startCounting():
    global root
    global topLevelList
    global classInstance

    topLevelList.append (Toplevel())
    topLevelList[len(topLevelList)-1].title("Child")
    classInstance.append(mainLoopThread(topLevelList[len(topLevelList)-1]))

    root.after(5000,startCounting)


class mainLoopThread(threading.Thread):
    def __init__(self,toplevelW):
        self.toplevelW = toplevelW
        threading.Thread.__init__(self)
        self.start()
    def run(self):
        self.toplevelW.mainloop()



global classInstance
classInstance = []
global topLevelList
topLevelList = []
global root

root = Tk() 
root.title("Main")
startCounting()
root.mainloop()

3 ответа

Tkinter предназначен для запуска только из основного потока. Смотрите документы:

Просто запустите весь код пользовательского интерфейса в главном потоке и позвольте авторам писать в объект Queue; например

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

Многие объекты и подсистемы не любят получать запросы от нескольких различных потоков, и в случае инструментария с графическим интерфейсом нередко требуется конкретное использование только основного потока.

Правильная архитектура Python для этой проблемы всегда состоит в том, чтобы посвятить поток (основной, если нужно) потоку для обслуживания привередливого объекта или подсистемы; каждый другой поток, требующий взаимодействия с упомянутой подсистемой или объектом, должен получить его, ставя запросы в очередь к выделенному потоку (и, возможно, ожидая в "очереди возврата" результатов, если результаты требуются вследствие какого-либо запроса). Это также очень надежная архитектура Python для многопоточности (и я подробно об этом расскажу в "Python in a Nutshell", но это уже другая тема;-).

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

Вы можете получить его здесь:

http://tkinter.unpythonic.net/wiki/mtTkinter

Есть ли причина, по которой вы хотите (или считаете, что вам нужно) один цикл обработки событий для каждого окна верхнего уровня? Один цикл обработки событий может обрабатывать десятки (если не сотни или тысячи) окон верхнего уровня. И, как было указано в другом ответе, вы не можете запустить этот цикл событий в отдельном потоке.

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

Другие вопросы по тегам