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

如何在tkinter中禁用按钮同时保留其自定义样式?

解决Tkinter井字棋按钮禁用后背景色变化的问题

问题出在ttk组件的状态样式机制上:你只配置了按钮默认状态的背景色,但按钮进入disabled状态时,会自动应用该状态的默认样式(灰色背景),覆盖了你自定义的黑色背景。

解决步骤

  1. 自定义禁用状态的样式
    通过ttk.Style的map方法,给disabled状态绑定和默认状态一致的背景色与前景色,确保禁用后样式不变:
Drip = ttk.Style()
Drip.theme_use('classic')
# 设置默认状态样式
Drip.configure('TButton', background='Black', foreground='Gold')
# 绑定禁用状态的样式,保持和默认一致
Drip.map('TButton',
         background=[('disabled', 'Black')],
         foreground=[('disabled', 'Gold')])
  1. 优化按钮管理(可选)
    原代码中Set_Symbol函数用大量if-elif判断按钮索引,可通过按钮列表简化代码,让逻辑更清晰:
  • 先创建按钮列表并布局:
buttons = []
# 循环创建3x3按钮网格
for row in range(3):
    for col in range(3):
        btn = ttk.Button(root, text='')
        btn.grid(row=row, column=col, sticky='snew', ipadx=40, ipady=40)
        buttons.append(btn)

# 绑定按钮点击命令
for idx, btn in enumerate(buttons, start=1):
    btn.config(command=lambda idx=idx: Bu_Click(idx))
  • 修改Set_Symbol函数:
def Set_Symbol(Index, Symbol):
    # 列表索引从0开始,按钮Index从1开始,所以减1
    target_btn = buttons[Index - 1]
    target_btn.config(text=Symbol)
    target_btn.state(['disabled'])

修改后的完整代码

from tkinter import *
from tkinter import ttk

root = Tk()
root.title("Turn: P1")

# 配置样式,包含禁用状态
Drip = ttk.Style()
Drip.theme_use('classic')
Drip.configure('TButton', background='Black', foreground='Gold')
Drip.map('TButton',
         background=[('disabled', 'Black')],
         foreground=[('disabled', 'Gold')])

ActivePlayer = 1
Player1 = []
Player2 = []

# 创建按钮列表
buttons = []
for row in range(3):
    for col in range(3):
        btn = ttk.Button(root, text='')
        btn.grid(row=row, column=col, sticky='snew', ipadx=40, ipady=40)
        buttons.append(btn)

# 绑定点击事件
for idx, btn in enumerate(buttons, start=1):
    btn.config(command=lambda idx=idx: Bu_Click(idx))

def Bu_Click(Index):
    global ActivePlayer
    global Player1
    global Player2
    if ActivePlayer == 1:
        Set_Symbol(Index, "X")
        Player1.append(Index)
        root.title("Turn: P2")
        ActivePlayer = 2
        print(f'P1{Player1}')
    elif ActivePlayer == 2:
        Set_Symbol(Index, "O")
        Player2.append(Index)
        root.title("Turn: P1")
        ActivePlayer = 1
        print(f'P2{Player2}')
    Check_Win()

def Set_Symbol(Index, Symbol):
    target_btn = buttons[Index - 1]
    target_btn.config(text=Symbol)
    target_btn.state(['disabled'])

def Check_Win():
    Winner = -1
    # 检查玩家获胜条件
    win_combos = [(1,2,3), (4,5,6), (7,8,9),
                  (1,4,7), (2,5,8), (3,6,9),
                  (1,5,9), (3,5,7)]
    for combo in win_combos:
        if all(pos in Player1 for pos in combo):
            Winner = 1
            break
        if all(pos in Player2 for pos in combo):
            Winner = 2
            break
    
    if Winner == 1:
        win_message = Toplevel(root)
        ttk.Label(win_message, text="Player 1 Won", width=50).pack()
    elif Winner == 2:
        win_message = Toplevel(root)
        ttk.Label(win_message, text="Player 2 Won", width=50).pack()

root.mainloop()

注:原代码中获胜弹窗用Tk()会创建新的主窗口,改用Toplevel(root)作为子窗口更符合GUI规范。

内容的提问来源于stack exchange,提问作者Bradkik

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.07 09:00:41