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

Tkinter按钮文本修改异常:点击按钮仅更改最后一个按钮文本

问题:Tkinter井字棋按钮点击后仅最后一个按钮文本变化

我编写了一段实现井字棋按钮的Tkinter代码,代码能正常运行,但点击任意按钮时,只有最后创建的按钮文本会切换为X或O,而非被点击的目标按钮。

代码如下:

import tkinter as tk

class Btn_maker:
    def __init__(self,window):
        self.window = window
        self.num = 0
        self.matrix = [[],[],[]]
    def btn_maker(self,cmd,x=1,y=1,padx=5,pady=5):
        self.btn = tk.Button(self.window,command = cmd,width = 6,height = 2)
        Btn_maker.btn_grid(self,x,y,padx,pady)
    def btn_grid(self,x,y,padx,pady):
        self.btn.grid(row = x, column = y, padx = padx, pady = pady)
    def game_logic(self,x,y):
        self.num+=1
        if self.num%2==1:
            self.btn.config(text = 'X')
        else:
            self.btn.config(text = 'O')
        #self.matrix[x-1][y-1] 

window = tk.Tk()
frame1 = tk.Frame(window)
frame1.pack()
label = tk.Label(frame1,text='Game',fg='red',font = 30)
label.pack()
frame2 = tk.Frame(window)
frame2.pack()
btn_instant = Btn_maker(frame2)
btn1 = btn_instant.btn_maker(lambda: btn_instant.game_logic(1,1),x=1,y=1)
btn2 = btn_instant.btn_maker(lambda: btn_instant.game_logic(1,2),x=1,y=2)
btn3 = btn_instant.btn_maker(lambda: btn_instant.game_logic(1,3),x=1,y=3)
btn4 = btn_instant.btn_maker(lambda: btn_instant.game_logic(2,1),x=2,y=1)
btn5 = btn_instant.btn_maker(lambda: btn_instant.game_logic(2,2),x=2,y=2)
btn6 = btn_instant.btn_maker(lambda: btn_instant.game_logic(2,3),x=2,y=3)
btn7 = btn_instant.btn_maker(lambda: btn_instant.game_logic(3,1),x=3,y=1)
btn8 = btn_instant.btn_maker(lambda: btn_instant.game_logic(3,2),x=3,y=2)
btn9 = btn_instant.btn_maker(lambda: btn_instant.game_logic(3,3),x=3,y=3)
window.geometry('200x300')
window.mainloop()

问题原因

你的Btn_maker类里用self.btn这个实例变量存储每个新创建的按钮,每次调用btn_maker都会覆盖这个变量。最后self.btn指向的是最后一个创建的按钮,所以不管点击哪个按钮,game_logic里修改的都是这个最后创建的按钮的文本。

修复方案

需要让每个按钮的点击逻辑知道要修改自身的文本,而不是依赖会被覆盖的self.btn。下面是优化后的代码:

import tkinter as tk

class Btn_maker:
    def __init__(self,window):
        self.window = window
        self.num = 0
        # 初始化3x3矩阵存储按钮实例,方便后续管理(比如判断胜负)
        self.matrix = [[None for _ in range(3)] for _ in range(3)]
    
    def btn_maker(self,x=1,y=1,padx=5,pady=5):
        # 创建当前按钮
        btn = tk.Button(self.window, width=6, height=2)
        # 用lambda默认参数绑定当前按钮和坐标,避免延迟绑定问题
        btn.config(command=lambda b=btn, row=x, col=y: self.game_logic(b, row, col))
        # 直接布局按钮,简化代码
        btn.grid(row=x, column=y, padx=padx, pady=pady)
        # 将按钮存入矩阵
        self.matrix[x-1][y-1] = btn
    
    def game_logic(self, btn, x, y):
        # 防止重复点击同一个按钮
        if btn['text'] != '':
            return
        self.num += 1
        # 根据次数切换X/O
        btn.config(text='X' if self.num % 2 == 1 else 'O')

window = tk.Tk()
frame1 = tk.Frame(window)
frame1.pack()
label = tk.Label(frame1, text='Game', fg='red', font=30)
label.pack()
frame2 = tk.Frame(window)
frame2.pack()
btn_instant = Btn_maker(frame2)

# 用循环创建按钮,减少重复代码
for row in range(1,4):
    for col in range(1,4):
        btn_instant.btn_maker(x=row, y=col)

window.geometry('200x300')
window.mainloop()

关键改动说明

  1. 移除self.btn变量:不再用单个实例变量存储按钮,每个按钮创建后直接通过lambda绑定到自己的点击逻辑
  2. lambda默认参数绑定:用b=btn把当前按钮实例传给game_logic,确保每个按钮的command指向自身
  3. 优化按钮创建逻辑:用双层循环创建9个按钮,减少重复代码
  4. 增加重复点击防护:判断按钮已有文本时不执行修改,避免同一按钮被多次点击
  5. 初始化按钮矩阵:把每个按钮存入self.matrix,方便后续扩展胜负判断逻辑(比如检查行、列、对角线是否有相同符号)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.17 22:17:10