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

如何在Python Tkinter的函数内无需按钮切换框架

问题:Tkinter登录验证完成后自动切换到主页框架

我正在使用Python和Tkinter开发一个包含用户认证、注册功能及主页框架的GUI。提交函数会验证数据库中的凭证,完成用户认证后,需要自动切换到主页框架。请问如何在函数内而非通过按钮实现框架切换?

附上相关代码:

from tkinter import Tk, Frame, Label, Entry, Button
from tkinter.messagebox import showinfo as MessageBox
import mysql.connector

class Application(Tk):
    
    def __init__(self, *args, **kwargs):
        
        Tk.__init__(self, *args, **kwargs)
        container = 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 (UserLogin, HomePage, RegisterUser): 
            frame = F(container, self)
            self.frames[F] = frame
            frame.grid(row=0, column=0, sticky = "nsew")
        
        self.show_frame(UserLogin)
        
    def show_frame(self, controller):
        
        frame = self.frames[controller]
        frame.tkraise()

# 假设HomePage和RegisterUser类已定义
class HomePage(Frame):
    def __init__(self, parent, controller):
        Frame.__init__(self, parent)
        Label(self, text="主页").pack()

class RegisterUser(Frame):
    def __init__(self, parent, controller):
        Frame.__init__(self, parent)
        Label(self, text="注册页").pack()

class UserLogin(Frame):
    
    db = mysql.connector.connect(
            host="localhost",
            port="XXXX",
            user="XXXX",
            passwd="XXXX",
            database="XXXXX"
        )
        
    cursorObject = db.cursor()
    

    def __init__(self, parent, controller):
        
        Frame.__init__(self, parent)
        controller = self.controller  # 此处存在错误
        
        self.title = Label(self, text="Welcome!", font=("Arial", 15, 'bold'))
        self.title.grid(row=1, column=1)
        
        self.description = Label(self, text="Please login to get started:", font=("Arial", 10))
        self.description.grid(row=2, column=1, pady=25, sticky=W)
    
        self.usernametitle = Label(self, text="Username")
        self.usernametitle.grid(row=3, column=1, sticky=W)

        self.passwordtitle = Label(self, text="Password")
        self.passwordtitle.grid(row=4, column=1, sticky=W)

        self.username_input = Entry(self, width=30)
        self.username_input.grid(row=3, column=1, sticky=E)

        self.password_input = Entry(self, show="*", width=30)
        self.password_input.grid(row=4, column=1, sticky=E)

        self.submit_button = Button(self, text="Submit", command=self.submit)
        self.submit_button.grid(row=5, column=1, pady=10, sticky=W)

        self.register_button = Button(self, text="New user? Register here", command=lambda: controller.show_frame(RegisterUser))
        self.register_button.grid(row=6, column=1, sticky=W)
    
    
    def submit(self):
        username = self.username_input.get()
        password = self.password_input.get()
        
        if(username == ""):
            MessageBox(title="Error", message="Username cannot be blank")
        if(password == ""):
            MessageBox(title="Error", message="Password cannot be blank")
        else:
            self.loginto(username, password)
            # 尝试切换主页框架(此处存在错误)
            UserLogin.controller.show_frame(HomePage)

    def loginto(self, username, password):
        query = "SELECT username, password FROM USER WHERE username ='" + username + "' AND password='" + password + "';"
        self.cursorObject.execute(query)
        myresult = self.cursorObject.fetchall()
        
        if myresult:
            print("success login")
            return True
        else:
            MessageBox(title="Error", message="Incorrect username and/or password")
            print("Incorrect")
            return False

我尝试在函数内调用show_frame但未成功,参考相关问题后尝试传递实例变量,却出现以下回溯信息:

Exception in Tkinter callback
Traceback (most recent call last):
  File "C:\Users\c\AppData\Local\Programs\Python\Python310\lib\tkinter\__init__.py", line 1921, in __call__
    return self.func(*args)
  File "C:\Users\c\eclipse-workspace\Medix.py", line 88, in submit
    controller = UserLogin.self.controller
AttributeError: type object 'UserLogin' has no attribute 'self'

解决方案

你的问题核心是controller实例变量的保存与调用逻辑错误,同时存在SQL注入风险和数据库连接的潜在问题,以下是分步修复方案:

1. 修复Controller的实例变量绑定

在UserLogin的__init__方法中,你把赋值逻辑写反了,应该将传入的controller绑定为实例变量:

def __init__(self, parent, controller):
    Frame.__init__(self, parent)
    self.controller = controller  # 正确:将外部传入的controller保存到实例属性
    # 后续UI元素初始化代码保持不变...

2. 正确实现登录成功后的框架切换

在submit函数中,不能通过类UserLogin访问controller,必须通过实例的self.controller,且要仅在登录验证成功时切换框架:

def submit(self):
    username = self.username_input.get()
    password = self.password_input.get()
    
    # 空值校验优化:提前退出避免无效执行
    if not username:
        MessageBox(title="Error", message="Username cannot be blank")
        return
    if not password:
        MessageBox(title="Error", message="Password cannot be blank")
        return
    
    # 登录成功才切换到主页
    if self.loginto(username, password):
        self.controller.show_frame(HomePage)

3. 修复SQL注入漏洞

当前的SQL查询通过字符串拼接实现,存在严重的SQL注入风险,必须改用参数化查询:

def loginto(self, username, password):
    # 使用%s作为占位符,由mysql-connector自动处理参数转义
    query = "SELECT username, password FROM USER WHERE username = %s AND password = %s;"
    self.cursorObject.execute(query, (username, password))  # 参数以元组形式传入
    myresult = self.cursorObject.fetchall()
    
    if myresult:
        print("success login")
        return True
    else:
        MessageBox(title="Error", message="Incorrect username and/or password")
        print("Incorrect")
        return False

4. 数据库连接优化建议

将数据库连接放在类属性中会导致所有UserLogin实例共享同一个连接,可能引发并发问题,建议将连接初始化移到__init__方法中:

class UserLogin(Frame):
    def __init__(self, parent, controller):
        Frame.__init__(self, parent)
        self.controller = controller
        
        # 实例化时创建独立的数据库连接和游标
        self.db = mysql.connector.connect(
            host="localhost",
            port="XXXX",
            user="XXXX",
            passwd="XXXX",
            database="XXXXX"
        )
        self.cursorObject = self.db.cursor()
        
        # 后续UI元素初始化代码...

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.14 22:16:30