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

如何获取CustomTkinter按钮的text或fg_color属性值?

问题:CustomTkinter按钮文本获取报错,无法切换状态发送消息

我有一个CustomTkinter(CTk)按钮组件,点击它时需根据按钮的text值向客户端发送编码消息;若按钮文本为"Off"则发送"On",反之则发送"Off"。

现有代码

import tkinter as tk
import traceback
import customtkinter as cust
import socket
from threading import Thread
from tkinter import messagebox

class GUI2(cust.CTk): #second window; not the root

    def __init__(self):

        super().__init__()

        self.PORT = 5000
        
        self.SERVER = socket.gethostbyname(socket.gethostname())
        
        self.ADDRESS = (self.SERVER, self.PORT)
       
        self.FORMAT = "utf-8"
        
        self.clients = [] #list to store all client connections
       
        self.server = socket.socket(socket.AF_INET,
                            socket.SOCK_STREAM)
        
        self.server.bind(self.ADDRESS)
        

        self.master2 = cust.CTkToplevel()
        
        self.ecdpower = cust.CTkButton(self.master2, text = "Off", fg_color = "Black", text_color = "White", hover_color = "Silver", command = lambda: Thread(target = self.startstream).start())
        self.ecdpower.grid(row = 0, column = 0) #button to send message to client connections
        
        self.thread = Thread(target = self.startChat)

        self.thread.start() #starts function to accept client connections
        
    def startChat(self): #function to accept client connections

        self.server.listen(30)

        try:

            while True:

                    self.conn, self.addr = self.server.accept()
                    
                    self.clients.append(self.conn) #stores all client connections

        except:

            pass 
            
    def startstream(self):

        
        try:

            if not self.clients: #checks if list is empty

                messagebox.showerror("No Connections!", "No clients connected to host!")

            else:

                for x in self.clients:

                    if self.ecdpower["text"] == "Off": #ecdpower button widget acts like a "power button"

                        self.ecdpower.configure(text = "On", fg_color = "Green")

                        x.send(("On").encode(self.FORMAT))

                    else:
                        
                        self.ecdpower.configure(text = "Off", fg_color = "Red")

                        x.send(("Off").encode(self.FORMAT))

        except:

            print (traceback.format_exc())    

报错信息

Traceback (most recent call last):
  File "f:\project\mainmenu.py", line 390, in startstream
  File "F:\Program Files (x86)\Python\lib\tkinter\__init__.py", line 1681, in cget
    return self.tk.call(self._w, 'cget', '-' + key)
_tkinter.TclError: unknown option "-text"

尝试过self.ecdpower.cget("text")或获取fg_color值,均出现相同错误。移除判断条件后消息发送功能正常,问题仅在于验证按钮text值。


修复方案

问题根源

Tkinter(包括基于它的CustomTkinter)的GUI组件操作必须在主线程中执行,子线程直接访问组件属性(如text、fg_color)会触发Tcl解释器报错,因为Tcl不是线程安全的。你的startstream方法在子线程中运行,直接操作按钮导致了错误。

方法1:用after将GUI操作委托给主线程

修改startstream方法,把按钮状态判断、配置更新等GUI相关逻辑通过self.after(0, ...)提交到主线程处理,socket发送操作可留在子线程:

def startstream(self):
    try:
        if not self.clients:
            # 弹窗操作也需放到主线程
            self.after(0, lambda: messagebox.showerror("No Connections!", "No clients connected to host!"))
        else:
            # 定义GUI操作逻辑,由主线程执行
            def update_button_and_send():
                current_text = self.ecdpower.cget("text")
                if current_text == "Off":
                    self.ecdpower.configure(text="On", fg_color="Green")
                    msg = "On"
                else:
                    self.ecdpower.configure(text="Off", fg_color="Red")
                    msg = "Off"
                # 发送消息(socket操作可在子线程执行)
                for x in self.clients:
                    x.send(msg.encode(self.FORMAT))
            
            # 委托主线程执行GUI操作
            self.after(0, update_button_and_send)
    except:
        print(traceback.format_exc())

方法2:维护独立状态变量,避免直接访问组件属性

在类实例中添加一个变量跟踪按钮状态,判断时直接使用该变量,仅将按钮配置更新委托给主线程:

def __init__(self):
    # ... 原有代码 ...
    # 添加状态变量跟踪按钮状态
    self.button_state = "Off"
    self.ecdpower = cust.CTkButton(
        self.master2, 
        text=self.button_state, 
        fg_color="Black", 
        text_color="White", 
        hover_color="Silver", 
        command=lambda: Thread(target=self.startstream).start()
    )
    # ... 原有代码 ...

def startstream(self):
    try:
        if not self.clients:
            self.after(0, lambda: messagebox.showerror("No Connections!", "No clients connected to host!"))
        else:
            # 根据状态变量判断,无需访问组件属性
            if self.button_state == "Off":
                new_state = "On"
                new_color = "Green"
            else:
                new_state = "Off"
                new_color = "Red"
            
            # 委托主线程更新按钮配置
            self.after(0, lambda: self.ecdpower.configure(text=new_state, fg_color=new_color))
            
            # 发送消息
            msg = new_state
            for x in self.clients:
                x.send(msg.encode(self.FORMAT))
            
            # 更新状态变量
            self.button_state = new_state
    except:
        print(traceback.format_exc())

内容的提问来源于stack exchange,提问作者N. Tanaka

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.13 13:50:26