如何在所有类外部访问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
相关产品推荐
相关产品推荐

