我正在尝试设置一个tkinter窗口,我可以使用队列在主循环外部进行交互。当我在spyder中解释这个时,它运行正常。在启动()之后,我的Tk窗口出现了,我仍然有控制台访问权限,允许我改变窗口的标题来改变窗口的标题。
但是,关闭窗口是个问题。它关闭很好,检查mythread显示线程确实停止了。但是再次调用launch()不会做任何事情并阻止解释器。然后我被迫重启python :(
是否有需要清洁的东西阻止我创建新线程?从我在这里读到的内容来看,tkinter不喜欢不在main中运行,这就是我在这里所做的。但为什么第一个实例呢?
我希望能够编写一些低级函数,例如下面的change_titre(例如绘制基本内容),然后允许用户使用它们编写自己的函数。如果一切都失败了,还有另一种方法吗?
import tkinter as tk
from threading import Thread
#import threading
import queue
request_queue = None
master = None
mythread = None
def submit_to_tkinter(callable, *args, **kwargs):
request_queue.put((callable, args, kwargs))
return
def threadmain():
global master
master = tk.Tk()
master.title("stuff")
drawzone = tk.Canvas(master, width=300, height = 300, bg='white')
drawzone.pack()
def queueloop():
try:
callable, args, kwargs = request_queue.get_nowait()
except queue.Empty:
pass
else:
callable(*args, **kwargs)
master.after(500, queueloop)
queueloop()
master.mainloop()
def change_titre(text):
submit_to_tkinter(master.title,text)
return
def launch():
global mythread,request_queue
request_queue = queue.Queue()
mythread = Thread(target=threadmain, args=())
mythread.daemon=True
mythread.start()
答案 0 :(得分:-1)
我相信在这段代码中使用全局变量只是从Python REPL访问数据的一种简单方法(因为代码应该用于教学目的)。但是将Tk对象保存在全局变量中并从不同的线程访问它是这个问题的根源。
我认为在每次新发布时将master
(全局变量)设置为新的Tk对象可能有所帮助。因此,当launch()
完成并且它的线程被连接时,我们可以确保先前的Tk对象被垃圾收集。
以下是更改的功能(注释显示哪些部分已更改)。
# import garbage collection module
import gc
def threadmain():
global master
master = tk.Tk()
master.title("stuff")
drawzone = tk.Canvas(master, width=300, height = 300, bg='white')
drawzone.pack()
def queueloop():
try:
callable_, args, kwargs = request_queue.get_nowait()
except queue.Empty:
pass
else:
callable_(*args, **kwargs)
master.after(500, queueloop)
queueloop()
master.mainloop()
# added these 2 lines to remove previous Tk object when thread is finished
master = None
gc.collect()
def launch():
global mythread,request_queue
# added these 3 lines to end previous open thread if any
if mythread and mythread.isAlive():
submit_to_tkinter(master.destroy)
mythread.join()
request_queue = queue.Queue()
mythread = Thread(target=threadmain, args=())
# no need for daemon threads
# mythread.daemon=True
mythread.start()
现在,在每次调用launch()
时,它将关闭前一个Tk窗口并等待线程加入,然后在新线程中打开一个新的Tk。