使用Tkinter滚动条搭配Pandas绘图时关闭窗口报错
Fixing the
_tkinter.TclError: invalid command name ".!toplevel.!scrollbar" on Toplevel Close 这个错误的核心原因是组件销毁顺序不匹配:当你关闭Toplevel窗口时,Tkinter的组件销毁顺序导致Scrollbar还在尝试引用已经被销毁的Canvas(或者反过来),同时Matplotlib的FigureCanvas和Tkinter窗口之间的残留引用也会触发无效的命令调用。
这里有一个直接有效的修复方案,我会结合代码详细说明:
修复步骤
- 给
Toplevel窗口绑定<Destroy>事件,在窗口销毁前手动清理Matplotlib资源,并解除Scrollbar与Canvas的绑定 - 确保Matplotlib的Figure被正确关闭,避免残留的Tkinter组件引用
修复后的完整代码
import pandas as pd import numpy as np import matplotlib.pyplot as plt from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg from tkinter import * from tkinter import ttk class TestClass(Frame): def __init__(self, parent=None): self.parent = parent Frame.__init__(self) self.main = self.master # Display graphs self.g_top = Toplevel(bg='white') self.g_top.title('Charts that create error :(') x = 5 y = 5 h = 800 w = 1100 self.g_top.geometry('%dx%d+%d+%d' % (w, h, x, y)) # 绑定窗口销毁事件,提前清理资源 self.g_top.bind('<Destroy>', self.on_toplevel_destroy) self.g_scroll = Scrollbar(self.g_top, orient='vertical') self.g_scroll.pack(side='right', fill='y') self.can=Canvas(self.g_top, yscrollcommand=self.g_scroll.set) self.can.pack(side='left', fill='both', expand=True) self.g_scroll.config(command=self.can.yview) self.frm = Frame(self.can) self.can.create_window((4,4), window=self.frm, anchor='nw') self.frm.bind('<Configure>', lambda event, canvas=self.can: self.onFrameConfigure(canvas)) fs = (12,30) dpi = 100 self.fig, axes = plt.subplots(nrows=3, ncols=1, figsize=fs, dpi=dpi) self.chart_type = FigureCanvasTkAgg(self.fig, self.frm) self.chart_type.get_tk_widget().grid(column=0, row=0) self.fig.tight_layout(pad=1.1) self.fig.subplots_adjust(bottom=0.2, hspace=0.2) df=pd.DataFrame(np.random.randn(5, 2), columns=['A','B']) df.plot(kind='bar', ax=axes[0], width=0.8) df.plot(kind='line', ax=axes[1]) df.plot(kind='scatter', x='A', y='B', ax=axes[2]) def onFrameConfigure(self, canvas): # Fixes scrollbar on tkinter canvas canvas.configure(scrollregion=canvas.bbox("all")) def on_toplevel_destroy(self, event): # 先解除滚动条与画布的命令绑定,避免互相引用 self.g_scroll.config(command=None) self.can.config(yscrollcommand=None) # 销毁Matplotlib的TK画布组件 self.chart_type.get_tk_widget().destroy() # 关闭Matplotlib的figure,彻底释放资源 plt.close(self.fig) if __name__ == '__main__': root=Tk() ui = TestClass(root) ui.pack() root.mainloop()
修复原理说明
- 绑定
<Destroy>事件:在窗口开始销毁流程时,我们主动介入清理资源,避免Tkinter自动销毁时的顺序混乱 - 解除组件绑定:让Scrollbar和Canvas不再互相引用命令,防止其中一个被销毁后另一个尝试调用无效的Tcl命令
- 清理Matplotlib资源:销毁关联的TK组件并关闭Figure,彻底切断Matplotlib与Tkinter之间的残留引用
这样修改后,你关闭Toplevel窗口时就不会再触发那个错误了,所有图表展示和滚动功能也能正常保留~
内容的提问来源于stack exchange,提问作者Tom
相关产品推荐
相关产品推荐

