如何在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
相关产品推荐
相关产品推荐

