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

Tkinter 如何禁用for循环中创建的点击事件触发的按钮

解决方案

核心修改点

  • 修复stored_functions.disable_btn的方法定义:添加静态方法装饰器,直接接收按钮实例作为入参,无需实例化工具类即可调用
  • 调整按钮command的lambda绑定逻辑:通过默认参数捕获当前循环生成的按钮实例,避免闭包延迟绑定问题,也不用额外存储按钮映射关系
  • 简化禁用逻辑,直接操作传入的按钮实例修改状态和样式

修改后完整代码

import tkinter as tk
from tkinter import font as tkfont

class SampleApp(tk.Tk):

    def __init__(self, *args, **kwargs):
        tk.Tk.__init__(self, *args, **kwargs)

        self.title_font = tkfont.Font(family='Helvetica', size=18, weight="bold", slant="italic")

        container = tk.Frame(self)
        container.pack(side="top", fill="both", expand=True)
        container.grid_rowconfigure(0, weight=1)
        container.grid_columnconfigure(0, weight=1)

        self.frames = {}

        self.frames["StartPage"] = StartPage(parent=container, controller=self)

        self.frames["StartPage"].grid(row=0, column=0, sticky="nsew")

        self.show_frame("StartPage")

    def show_frame(self, page_name):
        '''Show a frame for the given page name'''
        frame = self.frames[page_name]
        frame.tkraise()


class StartPage(tk.Frame):

    def __init__(self, parent, controller):
        tk.Frame.__init__(self, parent)
        self.controller = controller
        self.grid(columnspan=5, rowspan=5)

        self.populate = tk.Button(self, text='Populate Data', command=lambda : self.data())
        self.populate.pack(side='top')

        self.frame = tk.Frame(self)
        self.frame.pack()
        self.canvas = tk.Canvas(self.frame, borderwidth=0)
        self.canvas.pack(side='left', fill='both', expand=True)


    def data(self):
        row = 1
        for x in range(5):
            print(x)
            label = tk.Label(self.canvas, text='Line {}'.format(row))
            label.grid(row=row, column=1, padx=15, pady=15)

            text = tk.Text(self.canvas, width=5, height=1)
            text.grid(row=row, column=2, padx=15, pady=15)

            button = tk.Button(self.canvas, text='Click me', bg='white', 
                              # 用默认参数捕获当前循环的button实例
                              command=lambda btn=button: stored_functions.disable_btn(btn))
            button.grid(row=row, column=3, padx=15, pady=15)

            row+=1


class stored_functions():
    # 改为静态方法,不需要类实例即可调用
    @staticmethod
    def disable_btn(btn):
        print('Disabled the button')
        btn.configure(state='disabled', bg='grey')


if __name__ == "__main__":
    app = SampleApp()
    app.mainloop()

原理解释

你之前遇到UnboundLocalError是因为你试图在button变量完成赋值前就把它放到lambda的参数里,只要把lambda的定义放在button实例创建之后,通过默认参数捕获当前值,就可以避免闭包只拿到最后一次循环值的问题,也不用额外维护行号和按钮的映射关系。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.04 17:57:04