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

如何禁用Tkinter按钮且不改变其颜色与样式?

解决Tkinter按钮禁用时样式变化的问题

你遇到的核心问题是Tkinter按钮默认的DISABLED状态会自动修改外观,导致卡片图片显示效果变差。下面提供两种解决方案,优先推荐第一种,因为它不受系统主题影响,效果更稳定:

方法1:手动控制按钮可点击状态(推荐)

不用依赖state=tk.DISABLED来阻止重复点击,而是给每个按钮添加一个标记,记录它是否已经完成配对。当用户点击时先检查这个标记,已配对的按钮直接忽略点击操作,这样按钮始终保持正常状态,样式不会改变。

修改步骤:

  1. 给按钮添加配对状态标记:创建按钮时,给每个按钮添加is_matched属性,初始值设为False
  2. 点击前检查状态:在flipCard方法开头,先判断当前按钮是否已配对,或是已经处于选中状态,直接返回
  3. 匹配成功后更新标记:当两张卡片匹配成功时,将对应的两个按钮的is_matched设为True
  4. 移除原禁用状态代码:删掉原来设置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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.18 23:00:02