Скрипт многопоточного Tkinter падает при создании второго виджета Toplevel - PullRequest
8 голосов
/ 25 августа 2010

У меня есть скрипт 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 ]

24 голосов
/ 25 августа 2010

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

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

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

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

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

6 голосов
/ 18 марта 2012

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

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

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

0 голосов
/ 25 августа 2010

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...