You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.25 03:29:43