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

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函数已被调用且能访问字典,但函数内字典显示为空。

解决方案

问题出在代码执行顺序上:

  1. send_input调用authenticate,authenticate在认证成功后立刻调用auth_success
  2. auth_success弹出对话框并打印字典时,authenticate还没返回结果给send_input,send_input里的valid_credentials赋值代码根本没执行
  3. 等你关闭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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.28 06:44:51