Tkinter调用show_frame报参数缺失错误及controller作用咨询
问题描述
使用取自sentdex的代码,尝试在首页输入正确密码“123”时唤起PageOne窗口,但出现错误:TypeError: show_frame() missing 1 required positional argument: 'cont'。疑惑PageOne是否就是对应的参数?为何无法正常运行?另外想了解controller变量的作用?
import tkinter as tk from PIL import Image,ImageTk LARGE_FONT= ("Verdana", 12) class Root(tk.Tk): def __init__(self, *args, **kwargs): tk.Tk.__init__(self, *args, **kwargs) container = tk.Frame(self) container.pack(side="top", fill="both", expand = True) container.grid_rowconfigure(0, weight=1) container.grid_columnconfigure(0, weight=1) self.frames = {} for F in (StartPage, PageOne, PageTwo): frame = F(container, self) self.frames[F] = frame frame.grid(row=0, column=0, sticky="nsew") self.show_frame(StartPage) def show_frame(self, cont): frame = self.frames[cont] frame.tkraise() class StartPage(tk.Frame): def __init__(self, parent, controller): tk.Frame.__init__(self,parent) self.entry=tk.Entry(self, width = 35) self.entry.insert(0, 'Enter password') self.entry.config(fg = "grey") self.entry.place(relx=.5, rely=.3,anchor = tk.CENTER) button=tk.Button( self,text="Show Password", width = 20,command = self.ShowPass).place(relx=.5, rely=.4,anchor = tk.CENTER) button=tk.Button(self,text="Submit",width = 20, command=self.SubmitPass).place(relx=.5, rely=.5,anchor = tk.CENTER) self.entry.config(fg = "grey") self.entry.bind('<FocusIn>', self.EntryFieldClicked) self.entry.bind("<Return>", (lambda event: self.SubmitPass )) label=tk.Label(self,text="Log in to continue") label.pack() button = tk.Button(self, text="Visit Page 1", command=lambda: controller.show_frame(PageOne)) button.pack() def EntryFieldClicked(self,event): if self.entry.get() == 'Enter password': self.entry.delete(0, tk.END) self.entry.insert(0, '') self.entry.config(fg = 'black', show = "*") def ShowPass(self): self.entry.config(fg = 'black', show = "") def SubmitPass(self): global Password Password = self.entry.get() if Password == "123": Root.show_frame(PageOne) class PageOne(tk.Frame): def __init__(self, parent, controller): tk.Frame.__init__(self, parent) label = tk.Label(self, text="Page One!!!", font=LARGE_FONT) label.pack(pady=10,padx=10) self.controller = controller button1 = tk.Button(self, text="Back to Home", command=lambda: self.controller.show_frame(StartPage)) button1.pack() button2 = tk.Button(self, text="Page Two", command=lambda: controller.show_frame(PageTwo)) button2.pack() class PageTwo(tk.Frame): def __init__(self, parent, controller): tk.Frame.__init__(self, parent) label = tk.Label(self, text="Page Two!!!", font=LARGE_FONT) label.pack(pady=10,padx=10) button1 = tk.Button(self, text="Back to Home", command=lambda: controller.show_frame(StartPage)) button1.pack() button2 = tk.Button(self, text="Page One", command=lambda: controller.show_frame(PageOne)) button2.pack() app = Root() app.mainloop()
错误原因与修复方案
核心错误原因
你触发错误的直接原因是调用show_frame的方式错误:
在SubmitPass方法中,你使用Root.show_frame(PageOne)直接调用类的方法,但show_frame是Root的实例方法,必须通过Root的实例(也就是你创建的app对象)来调用,而非类本身。这种调用方式会导致Python把PageOne当成实例参数self,而缺少了真正需要的cont参数,从而抛出错误。
修复步骤
- 在
StartPage的__init__方法中,将传入的controller保存为实例变量:
class StartPage(tk.Frame): def __init__(self, parent, controller): tk.Frame.__init__(self,parent) self.controller = controller # 保存controller实例 # ... 其余原有代码保持不变 ...
- 修改
SubmitPass方法中的调用逻辑:
def SubmitPass(self): Password = self.entry.get() if Password == "123": self.controller.show_frame(PageOne) # 通过实例调用show_frame
- 额外优化:删除代码中重复的
import tkinter as tk语句,同时去掉不必要的global Password声明(该变量仅在当前方法内使用,无需全局化)。
修复后,输入密码“123”点击提交就能正常切换到PageOne页面,PageOne确实是show_frame需要的cont参数——因为Root的self.frames字典是以页面类作为键来存储实例的。
controller变量的作用
在这个tkinter多页面框架中,controller就是Root类的实例(即代码最后创建的app对象),它的核心作用有两点:
- 统一管理所有页面:
Root类内部的self.frames字典存储了所有页面的实例,controller通过show_frame方法可以将指定页面提升到最上层显示,实现页面切换的逻辑。 - 页面间通信的桥梁:不同页面(比如
StartPage和PageOne)可以通过controller共享数据或调用全局方法,避免页面之间直接耦合,让代码结构更清晰、易于维护。
比如你代码里的Visit Page 1按钮,就是通过controller.show_frame(PageOne)来触发页面切换,和修复后的SubmitPass调用逻辑完全一致。
内容的提问来源于stack exchange,提问作者Aris K
相关产品推荐
相关产品推荐

