基于Tkinter自定义switch_frame函数报错:'function'对象无destroy属性
解决Tkinter Toplevel销毁时切换Frame的AttributeError问题
嘿,咱先把问题拆明白:你遇到的AttributeError: 'function' object has no attribute 'destroy',说白了就是代码里的self.frame本来应该存的是Frame组件的实例,结果不知道咋回事变成了一个函数对象——函数哪来的destroy()方法嘛,这不就报错了。
大概率是你在绑定Toplevel销毁事件的时候写法出了问题,或者不小心把self.frame这个变量名和某个函数重名/赋值错了。咱一步步来解决:
先揪出错误根源
你是不是绑定Toplevel关闭事件的时候,写了类似这种代码?
# 错误示例:直接调用switch_frame,而不是传递回调函数 self.top.protocol("WM_DELETE_WINDOW", self.switch_frame(NewFrame))
这种写法会立刻执行switch_frame函数,而不是把它作为弹窗关闭时的回调。更糟的是,如果你的switch_frame逻辑有疏漏,可能会把self.frame意外覆盖成函数。
另外,你得检查自己的代码里有没有其他地方把self.frame赋值成了函数,比如手滑写了self.frame = self.switch_frame这种鬼代码——这直接把存Frame实例的变量变成了函数引用,调用destroy()能不报错吗?
正确的实现方式
咱基于你参考的代码结构,给你改出一个能正常工作的版本,核心是用lambda包装回调,确保self.frame始终指向Frame实例:
import tkinter as tk class SampleApp(tk.Tk): def __init__(self, *args, **kwargs): tk.Tk.__init__(self, *args, **kwargs) # 初始化容器,确保self.frame一开始是None,而不是其他东西 self.frame = None self.switch_frame(StartPage) def switch_frame(self, frame_class): # 销毁当前Frame(如果存在) if self.frame is not None: self.frame.destroy() # 创建新Frame实例并赋值给self.frame——这里一定要是实例,不是函数/类 self.frame = frame_class(self) self.frame.pack() class StartPage(tk.Frame): def __init__(self, master): tk.Frame.__init__(self, master) tk.Label(self, text="这是起始页面").pack(pady=10) tk.Button(self, text="打开弹窗,关闭后切换页面", command=self.open_toplevel).pack(pady=5) def open_toplevel(self): top = tk.Toplevel(self.master) top.title("测试弹窗") tk.Label(top, text="关闭我就能切换到新页面啦").pack(pady=20) # 重点:用lambda包装switch_frame的调用,把它作为回调传递 top.protocol("WM_DELETE_WINDOW", lambda: self.master.switch_frame(NewPage)) class NewPage(tk.Frame): def __init__(self, master): tk.Frame.__init__(self, master) tk.Label(self, text="成功切换到新页面!").pack(pady=10) tk.Button(self, text="回到起始页", command=lambda: master.switch_frame(StartPage)).pack(pady=5) if __name__ == "__main__": app = SampleApp() app.mainloop()
关键注意点
- 绑定回调要用lambda:
lambda: self.master.switch_frame(NewPage)这种写法,是把lambda函数作为回调,只有当弹窗关闭时才会执行switch_frame,而不是创建弹窗时就立刻执行。 - 确保self.frame始终指向Frame实例:
switch_frame里的self.frame = frame_class(self)一定要是创建实例,不能写成self.frame = frame_class(这会把类赋值给frame,不是实例),更不能赋值成函数。 - 检查变量名冲突:别把
self.frame和其他函数/变量重名,比如别定义一个叫frame的函数,不然不小心就会覆盖掉存实例的self.frame。
按照这个思路改完,你再试试,应该就不会再出现那个AttributeError了。
内容的提问来源于stack exchange,提问作者Michael Sibille
相关产品推荐
相关产品推荐

