2010-08-25 65 views
7

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

我正在做的是使用after方法每5秒调用一次函数startCounting以及root的主循环。每次调用该函数时,我都会将一个Toplevel Widget对象添加到列表中,并启动一个新线程,希望能够运行新的主循环。

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

代码:

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

回答

22

Tkinter的设计从主线程中运行,只是。见the docs

只要运行在主线程 所有UI代码,并让编剧写一个 队列对象;例如

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

许多对象和子系统不喜欢接收来自多个不同线程的请求,而对于GUI工具包,仅需要专门使用线程才是不常见的。

对于这个问题,正确的Python体系结构总是要投入一个线程(如果必须的话)来服务挑剔的对象或子系统;需要与所述子系统或对象交互的每个其他线程必须通过将请求排队到专用线程(并且如果由于某些请求而需要结果,可能等待“返回队列”中的结果)来获得它。这也是一个用于通用线程的非常健全的Python体系结构(我在“Python in a Nutshell”中详细阐述了它,但这是另一个主题;-)。

+0

感谢您的快速答复。我会检查文档。欢迎使用 – user430825 2010-08-25 15:07:05

+0

@user! – 2010-08-25 15:13:59

+9

我遇到过这个限制,这正是我使用的策略。我有一种方法可以检查所有队列。然后,我通过调用root.after(ms,my_method)将该方法注册到Tkinter的主循环中。my_method中的最后一次调用是对root.after的另一次调用,以便my_method不断向主循环重新注册自己。重要的是,my_method中的异常不会导致您错过向主循环注册。你可能想把你的调用root.after放到try/finally的finally部分。 – 2010-08-25 15:17:42

0

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

所以,要修复你的代码,你只需要使用一个事件循环,并让它在主线程中运行。

+0

非常感谢您的回答,我已经能够解决这个问题,这要归功于您们,我从未在这样的地方发布过任何内容,并且我对这么多的帮助感到惊喜。 – user430825 2010-08-25 15:51:47

6

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

你可以在这里得到它:

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

+0

它可以用python 3吗? – 2017-07-09 22:58:11