Tkinter多线程场景下matplotlib的plt.show仅主线程生效问题求助
实现方案
该需求完全可实现,核心逻辑为工作线程仅负责计算输出数据,主线程仅负责绘图展示,依托你现有代码结构的修改实现如下:
核心修改点
- 修复原代码中matplotlib导入的拼写错误
- 工作线程仅完成数据计算逻辑,计算完成后将绘图所需参数写入队列
- 主线程轮询队列读取绘图参数,执行绘图展示操作,该操作耗时极短不会造成GUI冻结
修正后完整代码
# 修正导入错误,原peplos为拼写错误 import matplotlib.pyplot as plt from tkinter.constants import LEFT, RIGHT, S import tkinter as tk, time, threading, random, queue class GuiPart(object): def __init__(self, master, queue, client_instance): self.queue = queue self.button1 = tk.Button(master, text="生成图表", padx=10, pady=5, fg="white", bg="#263D42", command=client_instance.start_thread1) self.button1.pack() def processIncoming(self): # 从队列读取绘图数据,在主线程执行绘图 while self.queue.qsize(): try: plot_data = self.queue.get_nowait() x = plot_data['x'] y = plot_data['y'] plt.plot(x, y) plt.show() except queue.Empty: pass class ThreadedClient(object): def __init__(self, master): self.master = master self.queue = queue.Queue() self.running = True self.gui = GuiPart(master, self.queue, self) self.periodic_call() def start_thread1(self): thread1 = threading.Thread(target=self.worker_thread1, daemon=True) thread1.start() def periodic_call(self): self.master.after(200, self.periodic_call) self.gui.processIncoming() if not self.running: import sys sys.exit(1) def worker_thread1(self): if self.running: # 此处替换为你的CSV读取、数据计算等耗时逻辑 time.sleep(rand.random() * 1.5) x = [1, 2, 3, 4] y = [4, 3, 2, 1] # 仅将绘图需要的参数写入队列,不调用任何绘图相关接口 self.queue.put({'x':x, 'y':y}) def end_application(self): self.running = False rand = random.Random() root = tk.Tk() client = ThreadedClient(root) root.mainloop()
扩展说明
如果需要生成多组图表、自定义图表样式,可以将图表标题、图例、坐标轴名称等参数一并放入队列传递,主线程拿到参数后按需渲染即可。如果你最终需要的是直接生成PNG文件而不是弹出预览窗口,也可以将plt.show()替换为plt.savefig('输出路径.png'),操作逻辑完全一致。
内容的提问来源于stack exchange,提问作者tmg28
相关产品推荐
相关产品推荐

