如何正确中断嵌入tkinter的matplotlib创建的动画?
解决Matplotlib动画嵌入Tkinter后无法正确中断的问题
问题根源
你用del fig, ani删除实例的方式无法彻底终止后台运行的动画。FuncAnimation依赖内部的定时器(event source)持续触发帧更新,即使实例引用被删除,这些定时器仍会在后台运行,多次点击按钮后,积累的动画进程会导致界面卡顿。
修复方案
要彻底中断旧动画,需要:
- 先停止旧动画的事件源,终止其定时更新
- 销毁旧的Tkinter画布控件,避免重复创建的控件占用资源
- 再清理旧实例并创建新动画
修改后的完整代码
import matplotlib import matplotlib.backends.backend_tkagg as tkagg import matplotlib.animation as animation import numpy as np import tkinter as tk fig = None ani = None old_figure_widget = None # 保存旧画布控件引用 def solve(): global fig, ani, old_figure_widget # 1. 停止并清理旧动画 if ani is not None: ani.event_source.stop() # 终止动画的定时更新 ani = None # 释放动画实例引用 # 2. 销毁旧画布控件 if old_figure_widget is not None: old_figure_widget.destroy() # 3. 清理旧figure if fig is not None: del fig # 创建新figure和画布 fig = matplotlib.figure.Figure() aCanvas = tkagg.FigureCanvasTkAgg(fig, master=win) old_figure_widget = aCanvas.get_tk_widget() old_figure_widget.grid(row=0, column=3, rowspan=10) # 动画数据与绘图设置 ti, tf, dt, delay = 0, 10, 0.01, 15 t = np.arange(ti, tf, dt) x1 = np.sin(t) N = len(t) ax2 = fig.add_subplot(xlim=(0, t[-1]), ylim=(min(x1), max(x1))) time_template = 'time = %.1fs' time_text = ax2.text(0.05, 0.95, '', transform=ax2.transAxes, bbox=dict(facecolor='white', edgecolor='black', boxstyle='round,pad=1')) massmotion, = ax2.plot([], [], '-') CumulativeX1, CumulativeT = [], [] def animate(i): CumulativeX1.append(x1[i]) CumulativeT.append(i*dt) time_text.set_text(time_template % (i*dt)) massmotion.set_data(CumulativeT, CumulativeX1) return time_text, massmotion ani = animation.FuncAnimation(fig, animate, np.arange(1, N), interval=delay, blit=True) fig.canvas.draw() # 创建GUI win = tk.Tk() aButton = tk.Button(win, text='Start Animation', command=solve) aButton.grid(column=0, row=10, columnspan=2) win.mainloop()
关键改动说明
- 添加
old_figure_widget变量保存旧画布控件,每次点击时销毁它,避免控件堆积 - 在删除实例前调用
ani.event_source.stop(),彻底终止旧动画的定时任务 - 调整实例初始化的默认值为
None,更方便判断是否存在旧实例
内容的提问来源于stack exchange,提问作者Francesco
相关产品推荐
相关产品推荐

