如何禁用Tkinter按钮且不改变其颜色与样式?
解决Tkinter按钮禁用时样式变化的问题
你遇到的核心问题是Tkinter按钮默认的DISABLED状态会自动修改外观,导致卡片图片显示效果变差。下面提供两种解决方案,优先推荐第一种,因为它不受系统主题影响,效果更稳定:
方法1:手动控制按钮可点击状态(推荐)
不用依赖state=tk.DISABLED来阻止重复点击,而是给每个按钮添加一个标记,记录它是否已经完成配对。当用户点击时先检查这个标记,已配对的按钮直接忽略点击操作,这样按钮始终保持正常状态,样式不会改变。
修改步骤:
- 给按钮添加配对状态标记:创建按钮时,给每个按钮添加
is_matched属性,初始值设为False - 点击前检查状态:在
flipCard方法开头,先判断当前按钮是否已配对,或是已经处于选中状态,直接返回 - 匹配成功后更新标记:当两张卡片匹配成功时,将对应的两个按钮的
is_matched设为True - 移除原禁用状态代码:删掉原来设置
state=tk.DISABLED的语句
修改后的完整代码:
import tkinter as tk import random from PIL import Image, ImageTk import pygame class FlipnMatchGame: # Flip and Match Game init method def __init__(self, root): self.root = root self.root.title("Flip and Match Memory Game") self.button_size = 100 self.images = [self.getImage(f'icon{i}.png') for i in range(1, 19)] self.cards = self.createCards() self.buttons = [] self.firstCard = None self.secondCard = None self.button1 = None self.button2 = None self.imagePairs = 0 self.numFlip = 0 self.createButtons() def getImage(self, filepath): img = Image.open(filepath) img = img.resize((100, 100)) return ImageTk.PhotoImage(img) def createCards(self): card_values = self.images * 2 random.shuffle(card_values) return card_values def createButtons(self): for i in range(6): row = [] for j in range(6): button = tk.Button(self.root, text='?', width=10, height=5, command=(lambda i=i, j=j: self.flipCard(i, j)), font=("Arial", 10), padx=0, pady=0) # 添加配对状态标记 button.is_matched = False button.grid(row=i, column=j, padx=1, pady=1) row.append(button) self.buttons.append(row) def flipCard(self, i, j): current_btn = self.buttons[i][j] # 先检查是否已配对,或者已经是选中状态,直接返回 if current_btn.is_matched or current_btn in (self.button1, self.button2): return if self.firstCard is None: self.firstCard = self.cards[i * 6 + j] self.button1 = current_btn self.button1.config(image=self.firstCard, height=80, width=80) self.button1.config(text='') elif self.secondCard is None: self.secondCard = self.cards[i * 6 + j] self.button2 = current_btn self.button2.config(image=self.secondCard, height=80, width=80) self.button2.config(text='') self.root.after(500, self.checkSame) def checkSame(self): if self.firstCard == self.secondCard: self.playSound("correct.mp3") self.numFlip += 1 self.imagePairs += 1 # 标记这两个按钮为已配对 self.button1.is_matched = True self.button2.is_matched = True if self.imagePairs == 18: self.gameDone() else: self.numFlip += 1 self.playSound("wrong.mp3") self.button1.config(image='', text='?', height=5, width=10) self.button2.config(image='', text='?', height=5, width=10) self.firstCard = None self.secondCard = None self.button1 = None self.button2 = None def playSound(self, sound_file): sound = pygame.mixer.Sound(sound_file) sound.play() def gameDone(self): winner_label = tk.Label(self.root, text=("Game Over !! \n number of fliping = "+ str(self.numFlip)), font=("Arial", 24)) winner_label.grid(row=6, column=0, columnspan=6) if __name__ == "__main__": pygame.mixer.init() pygame.mixer.music.load("bgm.mp3") pygame.mixer.music.play(-1) root = tk.Tk() game = FlipnMatchGame(root) root.mainloop()
方法2:自定义禁用状态的按钮样式
如果你坚持要使用state=tk.DISABLED,可以通过设置按钮的disabledbackground和disabledforeground属性,让禁用状态的样式和正常状态一致。不过注意,这种方法受系统Tkinter主题影响,部分平台可能不生效。
修改示例:
创建按钮时添加这两个属性,或者在翻牌时动态设置:
# 创建按钮时设置 button = tk.Button(self.root, text='?', width=10, height=5, command=(lambda i=i, j=j: self.flipCard(i, j)), font=("Arial", 10), padx=0, pady=0, disabledbackground=button.cget("background"), disabledforeground=button.cget("foreground")) # 或者在翻牌时设置 self.button1.config(image=self.firstCard, height=80, width=80, state=tk.DISABLED, disabledbackground=self.button1.cget("background"), disabledforeground=self.button1.cget("foreground"))
内容的提问来源于stack exchange,提问作者Alden Ling
相关产品推荐
相关产品推荐

