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

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参数,从而抛出错误。

修复步骤

  1. 在StartPage的__init__方法中,将传入的controller保存为实例变量:
class StartPage(tk.Frame):
    def __init__(self, parent, controller):
        tk.Frame.__init__(self,parent)
        self.controller = controller  # 保存controller实例
        # ... 其余原有代码保持不变 ...
  1. 修改SubmitPass方法中的调用逻辑:
def SubmitPass(self):
    Password = self.entry.get()
    if Password == "123":
        self.controller.show_frame(PageOne)  # 通过实例调用show_frame
  1. 额外优化:删除代码中重复的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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.23 06:09:50