Python 创建第二个顶级小部件时线程化Tkinter脚本崩溃

Python 创建第二个顶级小部件时线程化Tkinter脚本崩溃,python,multithreading,tkinter,Python,Multithreading,Tkinter,我有一个Python脚本,它使用Tkinter作为GUI。我的小脚本应该每X秒创建一个顶级小部件。当我运行代码时,第一个顶级小部件被成功创建,但当它试图创建第二个时,程序崩溃 我正在做的是使用after方法调用函数startCounting,该函数与root的mainloop一起每5秒调用一次。每次调用这个函数时,我都会将一个顶级小部件对象附加到一个列表中,并启动一个新线程,希望它能运行新的mainloop 如果有人能解决这个问题,我将不胜感激。顺便说一下,这只是我目前用来解决问题的一个小脚本,

我有一个Python脚本,它使用Tkinter作为GUI。我的小脚本应该每X秒创建一个顶级小部件。当我运行代码时,第一个顶级小部件被成功创建,但当它试图创建第二个时,程序崩溃

我正在做的是使用after方法调用函数startCounting,该函数与root的mainloop一起每5秒调用一次。每次调用这个函数时,我都会将一个顶级小部件对象附加到一个列表中,并启动一个新线程,希望它能运行新的mainloop

如果有人能解决这个问题,我将不胜感激。顺便说一下,这只是我目前用来解决问题的一个小脚本,它阻止了我继续我真正的学校项目

守则:

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()

Tkinter设计为仅从主线程运行。见:

只需在主界面中运行所有UI代码 线程,并让编写者向 队列对象;e、 g

…下面是一个实质性的示例,显示了将请求写入队列的辅助线程,主循环专门负责与Tk的所有直接交互

许多对象和子系统不喜欢接收来自多个不同线程的请求,在GUI toolkit中,通常只需要使用main线程


对于这个问题,正确的Python体系结构总是使用一个线程(如果必须的话,是主线程)来为挑剔的对象或子系统提供服务;需要与所述子系统或对象交互的每个其他线程必须通过将请求排队到专用线程(如果某个请求需要结果,则可能在“返回队列”上等待结果)来获得该子系统或对象。这也是一个非常完善的用于通用线程的Python体系结构(我在“Python简而言之”中详细阐述了这一点,但这是另一个主题;-)。

是否有理由希望(或认为需要)每个顶级窗口有一个事件循环?单个事件循环能够处理数十个(如果不是数百或数千个)顶级窗口。而且,正如在另一个答案中指出的,您不能在单独的线程中运行此事件循环


因此,要修复代码,只需使用单个事件循环,并在主线程中运行该循环

Tkinter在处理来自多个线程的输入时遇到问题,我使用mtTkinter,您不需要更改任何代码,一切都会正常工作。只需导入mtTkinter而不是Tkinter

你可以在这里找到它:


我遇到了这个限制,这正是我使用的策略。我有一个检查所有队列的方法。然后,通过调用root.after(ms,my_方法),将该方法注册到Tkinter的主循环中。my_方法中的最后一个调用是对root.after的另一个调用,以便my_方法不断地在主循环中重新注册自己。重要的是,my_方法中的异常不会导致您错过注册mainloop。你可能想打电话给root。在try/finally的finally部分之后。非常感谢你的回答,我已经解决了这个问题。多亏了你们,我从来没有在这样的地方发布过帖子,我对这么多的帮助感到惊喜。