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

如何定义Tkinter控制器?弹窗跨类调用函数报错求助

解决Tkinter弹窗调用主类函数的NameError及get_page函数疑问

Let's break down your problems step by step and fix them, along with clarifying how the get_page function works:

核心问题分析

1. NameError: name 'controller' is not defined

你在BoundingBox.popup()方法里调用popupWindow(self.master, controller)时,controller这个变量根本没定义。实际上你的BoundingBox类本身就是控制器,所以应该传递self(当前的BoundingBox实例)。另外,self.master在这里也是错误的——因为BoundingBox继承自tk.Tk,它自己就是主窗口,所以master参数应该传self。

2. 弹窗销毁代码错误

你的popupWindow.cleanup()方法里用了self.top.destroy(),但popupWindow继承自tk.Toplevel,不存在self.top这个属性,直接调用self.destroy()就能关闭弹窗。

3. get_page函数未完成

原代码里的get_page引用了self.frames,但你没有初始化这个字典。这个函数是Tkinter多页面应用的常用工具,用来管理不同页面的实例,需要先在BoundingBox的__init__里初始化self.frames = {},还可以完善逻辑让它自动创建页面实例(如果未创建的话)。

4. 补充:values方法变量缺失

你的values()方法用到了self.start_x、self.allcord等变量,这些需要在__init__里提前初始化,否则会触发新的报错。


修改后的完整代码

import tkinter as tk
from tkinter import Label, Entry, Button

class BoundingBox(tk.Tk):
    def __init__(self):
        super().__init__()  # 用super()替代直接调用父类构造,更简洁规范
        # 初始化values方法依赖的变量
        self.start_x = self.start_y = self.end_x = self.end_y = 0
        self.totwidth = self.totheight = 0
        self.value1 = self.value2 = ""
        self.allcord = []
        self.allrect = []
        # 初始化frames字典,用于get_page管理页面实例
        self.frames = {}

    def get_page(self, page_class):
        """获取或创建指定类的页面实例,用于多页面切换"""
        # 如果页面未创建,实例化并加入frames字典
        if page_class not in self.frames:
            frame = page_class(self, self)  # 传递主窗口和控制器
            self.frames[page_class] = frame
            frame.grid(row=0, column=0, sticky="nsew")
        # 返回页面实例
        return self.frames[page_class]

    def popup(self):
        # 正确传递主窗口和控制器(当前BoundingBox实例)
        self.w = popupWindow(self, self)

    def values(self):
        print(self.start_x, self.start_y, self.end_x, self.end_y, 
              self.totwidth, self.totheight, self.value1, self.value2)
        self.allcord.append([self.start_x, self.start_y, self.end_x, self.end_y, 
                             self.totwidth, self.totheight, self.value1, self.value2])
        # 注意:self.rect需要你在其他函数中定义,否则会报错
        self.allrect.append(self.rect)
        print(len(self.allcord))

class popupWindow(tk.Toplevel):
    def __init__(self, master, controller):
        super().__init__(master)
        self.controller = controller
        self.title("Input Breed & Color")
        # 布局控件并添加间距
        self.l1 = Label(self, text="Breed")
        self.l1.grid(row=0, column=0, padx=5, pady=5)
        self.e1 = Entry(self)
        self.e1.grid(row=0, column=1, padx=5, pady=5)
        self.l2 = Label(self, text="Color")
        self.l2.grid(row=1, column=0, padx=5, pady=5)
        self.e2 = Entry(self)
        self.e2.grid(row=1, column=1, padx=5, pady=5)
        self.b = Button(self, text='Save', command=self.cleanup)
        self.b.grid(row=2, column=1, padx=5, pady=5)

    def cleanup(self):
        # 将弹窗输入的值赋值给控制器的属性
        self.controller.value1 = self.e1.get()
        self.controller.value2 = self.e2.get()
        # 调用控制器的values方法
        self.controller.values()
        # 正确关闭弹窗
        self.destroy()

if __name__ == "__main__":
    draw = BoundingBox()
    # 添加测试按钮触发弹窗(你可以根据需求替换成自己的触发逻辑)
    test_btn = Button(draw, text="Open Input Popup", command=draw.popup)
    test_btn.pack(pady=20)
    draw.mainloop()

关于get_page函数的说明

这个函数是Tkinter多页面应用的标准工具,作用是:

  1. 避免重复创建相同页面的实例,节省资源
  2. 统一管理所有页面,方便在不同页面之间切换或调用方法

举个使用例子,如果你有一个设置页面:

class SettingsPage(tk.Frame):
    def __init__(self, parent, controller):
        super().__init__(parent)
        self.controller = controller
        Label(self, text="Settings Page").pack(pady=20)
        # 点击按钮切换回主页面
        Button(self, text="Go Back to Main", 
               command=lambda: controller.get_page(BoundingBox)).pack()

然后在主类中调用self.get_page(SettingsPage)就能获取这个页面的实例,直接切换到该页面。

内容的提问来源于stack exchange,提问作者AnalogDigital

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.06 21:17:42