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

9 投票
3 回答
16970 浏览
提问于 2025-04-16 03:17

我有一个用Python写的脚本,里面用到了Tkinter来做图形界面。我的小脚本应该每隔X秒创建一个新的Toplevel窗口。当我运行代码时,第一个Toplevel窗口能成功创建,但当它尝试创建第二个窗口时,程序就崩溃了。

我现在做的是使用after方法每5秒调用一次startCounting这个函数,同时运行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 个回答

0

你有没有想过为什么你想要每个顶层窗口都有一个事件循环?其实一个事件循环就能处理很多个顶层窗口,可能有几十个,甚至几百个、几千个都没问题。而且,正如其他回答提到的,你不能在单独的线程里运行这个事件循环。

所以,要解决你的代码问题,你只需要使用一个事件循环,并让它在主线程里运行就可以了。

8

Tkinter在处理来自多个线程的输入时会有一些问题,所以我使用mtTkinter。你不需要修改任何代码,一切都会正常工作。只需把mtTkinter导入替代Tkinter就可以了。

你可以在这里获取它:

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

24

Tkinter 是一个图形界面库,它只能在主线程中运行。你可以查看 相关文档

所有的用户界面代码都应该在主线程中运行,让其他线程把请求写入一个队列;例如:

接下来会有一个详细的例子,展示了其他线程如何把请求写入队列,而主循环则完全负责与 Tk 的所有直接交互。

很多对象和子系统不喜欢接收来自多个不同线程的请求,尤其是在图形界面工具包中,通常需要特别使用线程。

解决这个问题的正确 Python 结构是始终为这个挑剔的对象或子系统分配一个线程(如果必须的话,就是主线程);其他任何需要与这个子系统或对象交互的线程,都必须通过将请求放入队列来获取服务(如果需要结果,还可能需要在一个“返回队列”上等待结果)。这也是一种非常合理的 Python 线程架构,适用于一般的多线程编程(我在《Python 速查手册》中详细讲解过,但那是另一个话题;-)。

撰写回答