CustomTkinter回调函数中全局字典更新后读取为空问题
问题描述
我开发了一个CustomTkinter应用,希望通过API对用户进行身份认证。认证成功后,我想将用户的用户名和token更新到名为valid_credentials的全局字典中。但当我尝试在auth_success()函数中打印该字典时,字典始终为空。令我困惑的是,在send_input()函数中却能正常打印出字典内容。
代码片段
import tkinter import CTkMessagebox as msgbox import customtkinter import requests from PIL import Image # from PlantReader import * # Constants for the GUI HEX_GREEN = "#009579" HEX_GREEN_HOVER = "#006e59" POPPINS = "/fonts/Poppins-Regular.otf" valid_credentials = {} def create_warning(title, message): return msgbox.CTkMessagebox(title=title, message=message, icon="warning", option_1="OK", bg_color="white", fg_color="white", text_color="black", button_hover_color=HEX_GREEN_HOVER, button_color=HEX_GREEN, font=("Poppins", 14), header=True) def input_warning(): return create_warning("Alert", "Error: No input.") def auth_warning(message): return create_warning("Alert", f"Authentication failed: {message}") def auth_success(message): popup = msgbox.CTkMessagebox(title="Success", message=message, icon="check", option_1="OK", bg_color="white", fg_color="white", text_color="black", button_hover_color=HEX_GREEN_HOVER, button_color=HEX_GREEN, font=("Poppins", 14), header=True) response = popup.get() if response: print(f"reponse: {valid_credentials}") # read_data() # send_data() def authenticate(username, token): # API endpoint for authentication auth_endpoint = "http://localhost/gardeneye/api/authentication/authenticateUser.php" # Parameters for the authentication request params = { "username": username, "token": token } try: response = requests.get(auth_endpoint, params) data = response.json() if data["success"]: print("authenticate():", data["message"]) auth_success(data["message"]) return username, token else: print("Authentication failed:", data["message"]) auth_warning(data["message"]) return False except requests.exceptions.RequestException as e: print("Error:", e) return False # Function for sending button input to authentication API def send_input(): token = token_entry.get() username = username_entry.get() token_entry.delete(0, "end") # Clears entry from text box username_entry.delete(0, "end") # Clears entry from text box if token and username: # Check if input_text is not empty print(f"send_input(): {username} + {token}") valid_user, valid_token = authenticate(username, token) print(f"if token and username: {valid_user},{valid_token}") if valid_user and valid_token: valid_credentials["username"] = valid_user valid_credentials["token"] = valid_token print(f'if valid_user and valid_token: {valid_credentials}') else: print("Please enter a non-blank input.") input_warning() # Selecting GUI theme - dark, light , system (for system default) customtkinter.set_appearance_mode("light") # GUI window setup. Contains all the elements you see in the window. app = customtkinter.CTk(fg_color=HEX_GREEN, ) app.geometry("300x400") app.title("GardenEye Setup") app.resizable(0, 0) app.eval('tk::PlaceWindow . center') app.attributes("-topmost", True) frame = customtkinter.CTkFrame(master=app, fg_color="white") frame.pack(fill="both", expand=True, padx=10, pady=10) element_frame = customtkinter.CTkFrame(master=frame, fg_color="transparent") element_frame.pack(fill="both", expand=True, padx=10, pady=10) element_frame.place(relx=0.5, rely=0.8, anchor=tkinter.S) label = customtkinter.CTkLabel(master=element_frame, text="Please enter your details below:", fg_color="transparent", font=("Poppins", 16), text_color="black", wraplength=200) label.place(relx=0.5, rely=0.25, anchor=tkinter.CENTER) token_entry = customtkinter.CTkEntry(master=element_frame, width=150, height=30, bg_color="white", corner_radius=10, font=("Poppins", 12), placeholder_text="Authentication Token", placeholder_text_color="grey") token_entry.place(relx=0.5, rely=0.7, anchor=tkinter.CENTER) username_entry = customtkinter.CTkEntry(master=element_frame, width=150, height=30, bg_color="white", corner_radius=10, font=("Poppins", 12), placeholder_text="Username", placeholder_text_color="grey") username_entry.place(relx=0.5, rely=0.5, anchor=tkinter.CENTER) # Send button button = customtkinter.CTkButton(master=element_frame, width=50, corner_radius=15, text="Send", font=("Poppins", 14), command=send_input, fg_color=HEX_GREEN, text_color="white", hover_color=HEX_GREEN_HOVER) button.place(relx=0.5, rely=0.9, anchor=tkinter.CENTER) # Logo image logo = customtkinter.CTkImage(light_image=Image.open( r"Logo.png"), dark_image=Image.open( r"Logo.png"), size=(60, 60)) # Label to display the logo logo_label = customtkinter.CTkLabel(master=frame, image=logo, text="", width=60, height=60, fg_color="transparent") logo_label.place(relx=0.5, rely=0.15, anchor=tkinter.CENTER) app.mainloop()
已尝试操作
- 确认
valid_credentials字典在authenticate函数中被正确更新。 - 添加打印语句确认
auth_success函数已被调用且能访问字典,但函数内字典显示为空。
解决方案
问题出在代码执行顺序上:
send_input调用authenticate,authenticate在认证成功后立刻调用auth_successauth_success弹出对话框并打印字典时,authenticate还没返回结果给send_input,send_input里的valid_credentials赋值代码根本没执行- 等你关闭
auth_success的弹窗,authenticate才返回,send_input才给字典赋值,这时候再打印当然有内容
修复方法(二选一)
方法1:在authenticate里直接更新字典(推荐)
把valid_credentials的赋值逻辑移到authenticate中,调用auth_success之前完成:
def authenticate(username, token): auth_endpoint = "http://localhost/gardeneye/api/authentication/authenticateUser.php" params = { "username": username, "token": token } try: response = requests.get(auth_endpoint, params) data = response.json() if data["success"]: print("authenticate():", data["message"]) # 先更新全局字典 valid_credentials["username"] = username valid_credentials["token"] = token # 再调用成功弹窗 auth_success(data["message"]) return username, token else: print("Authentication failed:", data["message"]) auth_warning(data["message"]) return False except requests.exceptions.RequestException as e: print("Error:", e) return False
同时可以删掉send_input里的赋值代码,避免重复操作。
方法2:把字典作为参数传给auth_success
修改auth_success接收字典参数,在send_input赋值后再调用它:
# 修改auth_success函数 def auth_success(message, credentials): popup = msgbox.CTkMessagebox(title="Success", message=message, icon="check", option_1="OK", bg_color="white", fg_color="white", text_color="black", button_hover_color=HEX_GREEN_HOVER, button_color=HEX_GREEN, font=("Poppins", 14), header=True) response = popup.get() if response: print(f"reponse: {credentials}") # 修改authenticate,不再直接调用auth_success,而是返回状态 def authenticate(username, token): auth_endpoint = "http://localhost/gardeneye/api/authentication/authenticateUser.php" params = { "username": username, "token": token } try: response = requests.get(auth_endpoint, params) data = response.json() if data["success"]: print("authenticate():", data["message"]) return True, data["message"] else: print("Authentication failed:", data["message"]) auth_warning(data["message"]) return False, "" except requests.exceptions.RequestException as e: print("Error:", e) return False, "" # 修改send_input,赋值后调用auth_success def send_input(): token = token_entry.get() username = username_entry.get() token_entry.delete(0, "end") username_entry.delete(0, "end") if token and username: print(f"send_input(): {username} + {token}") success, message = authenticate(username, token) print(f"if token and username: {success}") if success: valid_credentials["username"] = username valid_credentials["token"] = token print(f'if valid_user and valid_token: {valid_credentials}') auth_success(message, valid_credentials) else: print("Please enter a non-blank input.") input_warning()
两种方法都能解决问题,方法1更简洁,符合原有代码逻辑;方法2解耦性更强,适合后续扩展。
内容的提问来源于stack exchange,提问作者veryconfused
相关产品推荐
相关产品推荐

