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
相关产品推荐
相关产品推荐

