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

Tkinter子类调用show_frame触发KeyError问题求助

问题解决:Tkinter面向对象GUI切换Frame时触发KeyError

问题描述

采用面向对象方式基于Tkinter开发GUI,定义rootClass根类创建窗口、存储Frame子类实例,并通过show_frame方法切换显示指定Frame。但在Frame子类方法中调用show_frame时触发KeyError: <class '__main__.firstPage'>错误。

错误原因分析

  1. 按钮command参数错误绑定:Frame子类中按钮的command直接调用了方法(如command = self.newPageMethod(controller, secondPage)),这会在创建按钮时立即执行方法,而非点击按钮时触发。此时rootClass尚未完成所有Frame实例的创建和frames字典的填充,调用show_frame会因目标Frame未存入字典而引发KeyError。
  2. 类定义顺序/缺失问题:若rootClass定义在Frame子类之前,初始化时会引用未定义的子类;若thirdPage未定义,循环创建Frame时会中断,导致frames字典不完整。

修复后的代码示例

完整可运行代码

from tkinter import *
from tkinter import ttk

# 先定义所有Frame子类,确保rootClass初始化时能正常引用
class firstPage(Frame):
    def newPageMethod(self, controller, newPage):
        print("newPageMethod executed")
        controller.show_frame(newPage)
    
    def __init__(self, parent, controller): 
        super().__init__(parent)
        
        titleLabel = Label(self, text ="firstPage")
        titleLabel.grid(row = 0, column = 1, padx = 10, pady = 10) 

        # 使用lambda延迟方法调用,点击按钮时才执行
        loginButton = Button(self, text ="go to second page", 
                            command = lambda: self.newPageMethod(controller, secondPage))
        loginButton.grid(row = 1, column = 1, padx = 10, pady = 10)

class secondPage(Frame):
    def newPageMethod(self, controller, newPage):
        print("newPageMethod executed")
        controller.show_frame(newPage)
    
    def __init__(self, parent, controller): 
        super().__init__(parent)
        
        titleLabel = Label(self, text ="secondPage")
        titleLabel.grid(row = 0, column = 1, padx = 10, pady = 10) 

        # 使用lambda延迟方法调用
        loginButton = Button(self, text ="go to third page", 
                            command = lambda: self.newPageMethod(controller, thirdPage))
        loginButton.grid(row = 1, column = 1, padx = 10, pady = 10)

class thirdPage(Frame):
    def __init__(self, parent, controller): 
        super().__init__(parent)
        
        titleLabel = Label(self, text ="thirdPage")
        titleLabel.grid(row = 0, column = 1, padx = 10, pady = 10) 

        # 添加返回按钮示例
        backButton = Button(self, text ="go back to first page", 
                           command = lambda: controller.show_frame(firstPage))
        backButton.grid(row = 1, column = 1, padx = 10, pady = 10)

class rootClass(Tk):
    def __init__(self): 
        Tk.__init__(self)
        
        window = Frame(self) 
        self.title("Application")
        window.pack(side="top", fill="both", expand=True) 
        window.grid_rowconfigure(0, weight = 1)
        window.grid_columnconfigure(0, weight = 1)
        self.frames = {} 

        pagesTuple = (firstPage, secondPage, thirdPage)
        for F in pagesTuple:
            frame = F(window, self)
            self.frames[F] = frame 
            frame.grid(row = 0, column = 0, sticky="NSEW")

        self.show_frame(firstPage)

    def show_frame(self, cont):
        frame = self.frames[cont]
        frame.tkraise()

# 启动应用
if __name__ == "__main__":
    app = rootClass()
    app.mainloop()

关键修复点

  • 按钮command绑定修正:将直接调用方法的写法改为lambda: self.newPageMethod(controller, secondPage),利用lambda表达式延迟方法执行,确保只有点击按钮时才触发页面切换逻辑。
  • 类定义顺序调整:将所有Frame子类的定义放在rootClass之前,避免初始化时引用未定义的类。
  • 补充缺失类定义:添加完整的thirdPage类,确保循环创建Frame时不会中断,frames字典能完整存储所有页面实例。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.07 17:15:54