线程和 tkinter
- 2025-04-10 09:46:00
- admin 原创
- 19
问题描述:
我听说 Python 中的线程不易处理,而且与 tkinter 配合使用会变得更加复杂。
我有以下问题。我有两个类,一个用于 GUI,另一个用于无限进程。首先,我启动 GUI 类,然后启动无限进程的类。我希望当您关闭 GUI 时,它也会完成无限进程并且程序结束。
代码的简化版本如下:
import time, threading
from tkinter import *
from tkinter import messagebox
finish = False
class tkinterGUI(threading.Thread):
def __init__(self):
threading.Thread.__init__(self)
def run(self):
global finish
#Main Window
self.mainWindow = Tk()
self.mainWindow.geometry("200x200")
self.mainWindow.title("My GUI Title")
#Label
lbCommand = Label(self.mainWindow, text="Hello world", font=("Courier New", 16)).place(x=20, y=20)
#Start
self.mainWindow.mainloop()
#When the GUI is closed we set finish to "True"
finish = True
class InfiniteProcess(threading.Thread):
def __init__(self):
threading.Thread.__init__(self)
def run(self):
global finish
while not finish:
print("Infinite Loop")
time.sleep(3)
GUI = tkinterGUI()
GUI.start()
Process = InfiniteProcess()
Process.start()
当我单击关闭按钮(在右上角)时,控制台中出现以下错误:
Tcl_AsyncDelete: async handler deleted by the wrong thread
我不知道为什么会发生这种情况或这意味着什么。
解决方案 1:
所有 Tcl 命令都需要来自同一个线程。由于tkinter
依赖于 Tcl,通常需要让所有tkinter
gui 语句都来自同一个线程。问题出现是因为
在线程mainWindow
中实例化tkinterGui
,但是——因为mainWindow
是 的一个属性——直到在主线程中销毁tkinterGui
才会销毁。tkinterGui
可以通过不将 设为mainWindow
的属性来避免此问题tkinterGui
——即将 改为self.mainWindow
。mainWindow
这允许 在方法在线程中结束mainWindow
时销毁。但是,通常您可以通过使用调用来完全避免线程:run
tkinterGui
mainWindow.after
import time, threading
from tkinter import *
from tkinter import messagebox
def infinite_process():
print("Infinite Loop")
mainWindow.after(3000, infinite_process)
mainWindow = Tk()
mainWindow.geometry("200x200")
mainWindow.title("My GUI Title")
lbCommand = Label(mainWindow, text="Hello world", font=("Courier New", 16)).place(x=20, y=20)
mainWindow.after(3000, infinite_process)
mainWindow.mainloop()
如果您想在类中定义 GUI,您仍然可以这样做:
import time, threading
from tkinter import *
from tkinter import messagebox
class App(object):
def __init__(self, master):
master.geometry("200x200")
master.title("My GUI Title")
lbCommand = Label(master, text="Hello world",
font=("Courier New", 16)).place(x=20, y=20)
def tkinterGui():
global finish
mainWindow = Tk()
app = App(mainWindow)
mainWindow.mainloop()
#When the GUI is closed we set finish to "True"
finish = True
def InfiniteProcess():
while not finish:
print("Infinite Loop")
time.sleep(3)
finish = False
GUI = threading.Thread(target=tkinterGui)
GUI.start()
Process = threading.Thread(target=InfiniteProcess)
Process.start()
GUI.join()
Process.join()
或者更简单,只需使用主线程来运行 GUI 主循环:
import time, threading
from tkinter import *
from tkinter import messagebox
class App(object):
def __init__(self, master):
master.geometry("200x200")
master.title("My GUI Title")
lbCommand = Label(master, text="Hello world",
font=("Courier New", 16)).place(x=20, y=20)
def InfiniteProcess():
while not finish:
print("Infinite Loop")
time.sleep(3)
finish = False
Process = threading.Thread(target=InfiniteProcess)
Process.start()
mainWindow = Tk()
app = App(mainWindow)
mainWindow.mainloop()
#When the GUI is closed we set finish to "True"
finish = True
Process.join()
解决方案 2:
这里的修复很简单,但很难发现:
mainWindow.quit()
之后立即调用mainwindow.mainloop()
,以便清理发生在与创建 tk UI 相同的线程上,而不是在 python 退出时在主线程上进行。
相关推荐
热门文章
项目管理软件有哪些?
热门标签
曾咪二维码
扫码咨询,免费领取项目管理大礼包!
云禅道AD