CustomTkinter登录GUI开发报错:NameError: name 'username_entry' is not defined
解决CustomTkinter登录GUI调用脚本时的NameError问题
问题场景
使用CustomTkinter开发登录GUI,主窗口包含Login和Exit按钮,点击Login按钮调用login.py打开登录界面。单独运行login.py一切正常,但从主脚本触发调用时出现如下错误:
Exception in Tkinter callback Traceback (most recent call last): File "C:\Users\denis\AppData\Local\Programs\Python\Python311\Lib\tkinter\__init__.py", line 1948, in __call__ return self.func(*args) ^^^^^^^^^^^^^^^^ File "D:\test\venv\Lib\site-packages\customtkinter\windows\widgets\ctk_button.py", line 527, in _clicked self._command() File "<string>", line 21, in login NameError: name 'username_entry' is not defined
主脚本代码
import tkinter import customtkinter customtkinter.set_appearance_mode("System") customtkinter.set_default_color_theme("dark-blue") app = customtkinter.CTk() # create CTk window like you do with the Tk window app.title("Menu") app.geometry("240x240") app.config(bg="#242320") def button_function(): exec(open('D:\\test\\login.py').read()) def Close(): app.destroy() font1=('Arial', 15, 'bold') button = customtkinter.CTkButton(master=app, text="Login", font=font1, command=button_function) button.place(relx=0.5, rely=0.4, anchor=tkinter.CENTER) button = customtkinter.CTkButton(master=app, text="Exit", font=font1, command=Close) button.place(relx=0.5, rely=0.6, anchor=tkinter.CENTER) app.mainloop()
登录脚本login.py代码
import customtkinter from tkinter import * from tkinter import messagebox app = customtkinter.CTk() app.title("Login") app.geometry("350x200") app.config(bg="#242320") font1=('Arial', 15, 'bold') username="hello" password="123" trials=0 def login(): global username global password global trials written_username = username_entry.get() written_password = password_entry.get() if(written_username == '' or written_password==''): messagebox.showwarning(title="Error", message="Enter your username and password.") elif(written_username==username and written_password==password): new_window=Toplevel(app) new_window.geometry("350x200") new_window.config(bg="#242320") welcome_label=customtkinter.CTkLabel(new_window, text="Welcome...", font=font1, text_color="#FFFFFF") welcome_label.place(x=100, y=100) elif((written_username != username or written_password != password) and trials<3): messagebox.showerror(title="Error", message="Your username or password are not correct.") trials=trials + 1 if (trials != 3): trials_label = customtkinter.CTkLabel(app, text=f"You have {3-trials} trials", font=font1, text_color="#FFFFFF") trials_label.place(x=100, y=160) if(trials==3): login_button.destroy() locked_label = customtkinter.CTkLabel(app, text="Your account is locked.", font=font1, text_color="#FFFFFF") locked_label.place(x=100, y=160) username_label=customtkinter.CTkLabel(app, text="Username: ",font=font1, text_color="#FFFFFF") username_label.place(x=10, y=25) password_label=customtkinter.CTkLabel(app, text="Password: ",font=font1, text_color="#FFFFFF") password_label.place(x=10, y=75) username_entry=customtkinter.CTkEntry(app,fg_color="#FFFFFF", font=font1, text_color="#000000", border_color="#FFFFFF", width= 200, height= 1) username_entry.place(x=100, y=25) password_entry=customtkinter.CTkEntry(app,fg_color="#FFFFFF", font=font1, text_color="#000000", border_color="#FFFFFF", show="*", width= 200, height= 1) password_entry.place(x=100, y=75) login_button=customtkinter.CTkButton(app, command=login, text="Login", font=font1, text_color="#FFFFFF", fg_color="#1f538d", hover_color="#14375e", width=50) login_button.place(x=165, y=120) app.mainloop()
问题原因与解决方法
原因
- 使用
exec(open('login.py').read())执行脚本时,login.py中的username_entry等变量处于局部作用域,login()函数无法直接访问这些未声明为全局的变量。 - 主脚本和
login.py都创建了名为app的CTk实例,导致上下文混乱,进一步加剧了作用域问题。
解决步骤
1. 重构login.py,封装登录窗口逻辑
将登录窗口的创建逻辑封装为函数,通过nonlocal声明函数需要访问的外层变量,确保作用域正确:
import customtkinter from tkinter import messagebox def show_login_window(): login_app = customtkinter.CTk() login_app.title("Login") login_app.geometry("350x200") login_app.config(bg="#242320") font1=('Arial', 15, 'bold') username="hello" password="123" trials=0 def login(): nonlocal username, password, trials, login_app, username_entry, password_entry, login_button written_username = username_entry.get() written_password = password_entry.get() if written_username == '' or written_password=='': messagebox.showwarning(title="Error", message="Enter your username and password.") elif written_username == username and written_password == password: new_window = customtkinter.CTkToplevel(login_app) new_window.geometry("350x200") new_window.config(bg="#242320") welcome_label = customtkinter.CTkLabel(new_window, text="Welcome...", font=font1, text_color="#FFFFFF") welcome_label.place(x=100, y=100) elif (written_username != username or written_password != password) and trials < 3: messagebox.showerror(title="Error", message="Your username or password are not correct.") trials += 1 if trials != 3: trials_label = customtkinter.CTkLabel(login_app, text=f"You have {3-trials} trials", font=font1, text_color="#FFFFFF") trials_label.place(x=100, y=160) if trials == 3: login_button.destroy() locked_label = customtkinter.CTkLabel(login_app, text="Your account is locked.", font=font1, text_color="#FFFFFF") locked_label.place(x=100, y=160) username_label = customtkinter.CTkLabel(login_app, text="Username: ",font=font1, text_color="#FFFFFF") username_label.place(x=10, y=25) password_label = customtkinter.CTkLabel(login_app, text="Password: ",font=font1, text_color="#FFFFFF") password_label.place(x=10, y=75) username_entry = customtkinter.CTkEntry(login_app,fg_color="#FFFFFF", font=font1, text_color="#000000", border_color="#FFFFFF", width=200, height=25) username_entry.place(x=100, y=25) password_entry = customtkinter.CTkEntry(login_app,fg_color="#FFFFFF", font=font1, text_color="#000000", border_color="#FFFFFF", show="*", width=200, height=25) password_entry.place(x=100, y=75) login_button = customtkinter.CTkButton(login_app, command=login, text="Login", font=font1, text_color="#FFFFFF", fg_color="#1f538d", hover_color="#14375e", width=50) login_button.place(x=165, y=120) login_app.mainloop() # 单独运行时启动窗口 if __name__ == "__main__": show_login_window()
2. 修改主脚本,通过导入模块调用函数
替换exec方式,改为导入login.py并调用封装好的函数:
import tkinter import customtkinter import login customtkinter.set_appearance_mode("System") customtkinter.set_default_color_theme("dark-blue") app = customtkinter.CTk() app.title("Menu") app.geometry("240x240") app.config(bg="#242320") def button_function(): login.show_login_window() def Close(): app.destroy() font1=('Arial', 15, 'bold') button = customtkinter.CTkButton(master=app, text="Login", font=font1, command=button_function) button.place(relx=0.5, rely=0.4, anchor=tkinter.CENTER) button = customtkinter.CTkButton(master=app, text="Exit", font=font1, command=Close) button.place(relx=0.5, rely=0.6, anchor=tkinter.CENTER) app.mainloop()
关键改动说明
- 用函数封装登录窗口逻辑,通过
nonlocal确保内部函数能访问外层变量,解决作用域问题。 - 使用模块导入替代
exec,避免脚本执行时的上下文混乱。 - 替换
Toplevel为customtkinter.CTkToplevel,保持CustomTkinter组件风格一致。 - 调整输入框
height参数为25,修复原代码中输入框显示异常的问题。
内容的提问来源于stack exchange,提问作者Alpha
相关产品推荐
相关产品推荐

