我有一个项目,其中一个被动 GUI 在它自己的线程中运行并由主线程操作。特别是,主线程使用 event_generate
:
from tkinter import Tk
import threading
import time
import queue
q = queue.Queue()
class Window:
def __init__(self):
self.root = Tk()
self.root.title("test")
self.root.bind("<<custom_close_event>>", self.close)
def close(self, event):
print("quit")
self.root.destroy()
def create_window():
window = Window()
q.put(window)
window.root.mainloop()
print("###########")
# Window creation executed in different thread
t1 = threading.Thread(target=create_window)
t1.start()
window = q.get()
time.sleep(2)
window.root.event_generate("<<custom_close_event>>")
print("end")
程序崩溃,输出如下:
quit
###########
Tcl_AsyncDelete: async handler deleted by the wrong thread
[1] 21572 IOT instruction (core dumped) python window_test.py
根据this discussion,看来多线程环境中对象清理的顺序有问题。取消对象(在我的例子中为 window
)和调用 gc.collect
的建议没有解决问题。
我该怎么办?
答案 0 :(得分:1)
不是使用单独的线程来创建对 Tk() 的第二个引用, 创建“Window”类时只需继承 tk.Toplevel 即可。 这将允许您拥有任意数量的窗口。 您可以使用 tk.after 来监视进程并执行伪多线程处理。这是如何做到这一点的示例
class Window(Toplevel):
def __init__(self, parent, *args, **kwargs):
super().__init__(*args, **kwargs)
self.parent = parent
...
self.parent.after(1000, self.do_something)
def do_something(self):
...
<code>
...
self.parent.after(1000, self.do_something)
root = Tk()
Window(root)
root.mainloop()
答案 1 :(得分:0)
使用@AndrewPye 的答案,但继承自 Tk
而不是 Toplevel
:
from tkinter import *
class Window(Tk):
def __init__(self, **kwargs):
super().__init__(**kwargs)
super().after(1000, self.do_something)
def do_something(self):
print("I am in a loop that runs every 1000ms = 1s")
super().after(1000, self.do_something)
root = Window()
root.mainloop()