如何在tkinter中禁用按钮同时保留其自定义样式?
解决Tkinter井字棋按钮禁用后背景色变化的问题
问题出在ttk组件的状态样式机制上:你只配置了按钮默认状态的背景色,但按钮进入disabled状态时,会自动应用该状态的默认样式(灰色背景),覆盖了你自定义的黑色背景。
解决步骤
- 自定义禁用状态的样式
通过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')])
- 优化按钮管理(可选)
原代码中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
相关产品推荐
相关产品推荐

