我有一个Python脚本,它使用Tkinter作为GUI。我的小脚本应该每隔X秒创建一个Toplevel小部件。当我运行我的代码时,第一个Toplevel小部件成功创建,但当它尝试创建第二个时,程序崩溃。
我正在做的是使用after方法每隔5秒与root的mainloop一起调用函数startCounting。每次调用此函数时,我都会将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()
答案 0 :(得分:24)
Tkinter只能从主线程运行。见the docs:
只需在main中运行所有UI代码 线程,让作者写一个 队列对象; e.g。
...接下来是一个实例,显示了将请求写入队列的辅助线程,主循环专门负责与Tk的所有直接交互。
许多对象和子系统不喜欢接收来自多个不同线程的请求,而在GUI工具包的情况下,仅仅需要明确地使用主线程。
这个问题的正确Python架构总是用一个线程(主要的,如果必须的话)来为挑剔的对象或子系统提供服务;每个需要与所述子系统或对象交互的其他线程必须通过将请求排队到专用线程来获得它(并且如果某些请求需要结果,则可能在结果的“返回队列”上等待)。这也是用于通用线程的非常合理的Python体系结构(我在“果壳中的Python”中详细阐述了它,但这是另一个主题; - )。
答案 1 :(得分:6)
Tkinter处理来自多个线程的输入有问题,我使用mtTkinter代替,你不需要更改任何代码,一切都会正常工作。只需导入mtTkinter而不是Tkinter。
你可以在这里得到它:
答案 2 :(得分:0)
您是否有理由(或认为您需要)每个顶层窗口有一个事件循环?单个事件循环能够处理数十个(如果不是数百或数千个)顶层窗口。而且,正如另一个答案所指出的那样,你不能在一个单独的线程中运行这个事件循环。
因此,要修复代码,您只需要使用单个事件循环,并在主线程中运行。