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

如何在所有类外部访问Python内部类?Tkinter代码问题

解决Tkinter内部类外部访问问题

问题说明

我尝试用MainApplication类包裹所有Tkinter相关类来组织DnD角色创建界面的代码,但外部的if __name__ == "__main__"代码块无法访问MainApplication内部的Start类来启动程序。移除MainApplication后代码可正常运行,需要解决这个内部类的外部访问问题。

原问题代码:

import tkinter as tk

class MainApplication(tk.Frame):
    def __init__(self, parent, *args, **kwargs):
        tk.Frame.__init__(self, parent, *args, **kwargs)
        self.parent = parent
        class charName (object):
            def __init__ (self, master):
                Top = self.Top = tk.Toplevel(master)
                self.l= tk.Label(Top, text="Test")
                self.l.pack()
                self.e = tk.Entry(Top)
                self.e.pack()
                self.b = tk.Button(Top, text="Next", command=self.Cleanup,)
                self.b.pack()
                Top.mainloop
            
            def Cleanup (self):
                self.value = self.e.get()
                self.command = print("Works!")
                self.Top.destroy

        class Start (object):
            def __init__(self, master):
                self.master=master
                self.b = tk.Button(root, 
                            text="Get Started!", 
                            command=self.popup,)
                
                self.b.pack()
                    
            def popup (self):
                self.w = charName(self.master)
                self.b["state"] = "disabled" 
                self.master(self.w.Top)
                self.b["state"] = "normal"
                
if __name__ == "__main__":
    root=tk.Tk()
    m=Start(root)
    root.mainloop()

解决方案

方法1:将内部类定义在MainApplication的类级别(而非__init__方法内)

把charName和Start类移到MainApplication的类作用域下,而非__init__方法内部,这样外部可以通过MainApplication.Start的方式访问内部类。同时修正原代码中的几个小问题:

  • Top.mainloop需要加括号调用
  • self.Top.destroy需要加括号调用
  • self.master(self.w.Top)是错误写法,改用self.master.wait_window(self.w.Top)来等待弹窗关闭

修正后代码:

import tkinter as tk

class MainApplication(tk.Frame):
    def __init__(self, parent, *args, **kwargs):
        tk.Frame.__init__(self, parent, *args, **kwargs)
        self.parent = parent

    class charName(object):
        def __init__(self, master):
            self.Top = tk.Toplevel(master)
            self.l = tk.Label(self.Top, text="输入角色名称")
            self.l.pack()
            self.e = tk.Entry(self.Top)
            self.e.pack()
            self.b = tk.Button(self.Top, text="确认", command=self.Cleanup)
            self.b.pack()

        def Cleanup(self):
            self.value = self.e.get()
            print(f"角色名:{self.value}")
            self.Top.destroy()

    class Start(object):
        def __init__(self, master):
            self.master = master
            self.b = tk.Button(master, text="开始创建角色", command=self.popup)
            self.b.pack()

        def popup(self):
            self.b["state"] = "disabled"
            self.w = MainApplication.charName(self.master)
            self.master.wait_window(self.w.Top)
            self.b["state"] = "normal"

if __name__ == "__main__":
    root = tk.Tk()
    root.title("DnD角色创建工具")
    m = MainApplication.Start(root)
    root.mainloop()

方法2:在MainApplication中封装启动逻辑

保持内部类在__init__内的结构,通过MainApplication的实例方法来启动Start界面,外部只需要实例化MainApplication即可:

import tkinter as tk

class MainApplication(tk.Frame):
    def __init__(self, parent, *args, **kwargs):
        tk.Frame.__init__(self, parent, *args, **kwargs)
        self.parent = parent

        class charName(object):
            def __init__(self, master):
                self.Top = tk.Toplevel(master)
                self.l = tk.Label(self.Top, text="输入角色名称")
                self.l.pack()
                self.e = tk.Entry(self.Top)
                self.e.pack()
                self.b = tk.Button(self.Top, text="确认", command=self.Cleanup)
                self.b.pack()

            def Cleanup(self):
                self.value = self.e.get()
                print(f"角色名:{self.value}")
                self.Top.destroy()

        class Start(object):
            def __init__(self, master):
                self.master = master
                self.b = tk.Button(master, text="开始创建角色", command=self.popup)
                self.b.pack()

            def popup(self):
                self.b["state"] = "disabled"
                self.w = charName(self.master)
                self.master.wait_window(self.w.Top)
                self.b["state"] = "normal"

        # 启动初始界面
        self.start_ui = Start(parent)

if __name__ == "__main__":
    root = tk.Tk()
    root.title("DnD角色创建工具")
    # 实例化MainApplication即可启动界面
    app = MainApplication(root)
    root.mainloop()

说明

两种方法都能实现用MainApplication组织代码的需求:

  • 方法1更灵活,外部可以直接调用内部类;
  • 方法2封装性更好,外部无需关心内部类结构,只需实例化主类即可。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.20 09:32:12