tkinter绑定右键事件时lambda传含event的两个参数报错的解决方法
报错根本原因
- Tkinter 的
bind机制在触发绑定的回调时,只会自动传递1个事件对象作为入参,不会额外向函数传你自己定义的循环下标i。 - 你写的 lambda 表达式定义了
e、i两个必传入参,实际触发时只有事件对象e被传入,缺少i的输入,直接触发参数缺失的TypeError。 - 就算解决了参数传递问题,直接在lambda内引用循环变量
i还会遇到闭包延迟绑定的经典坑:所有按钮的回调最后都会读取循环结束后的最终i值(也就是4),不管点哪个按钮,修改的都是最后创建的那个按钮的文本,完全不符合预期。
针对性修改方案
利用lambda的默认参数特性,在每次创建lambda的时候,把当前循环的下标值固定存储下来——默认参数会在lambda定义的瞬间完成求值,不会跟着循环推进改变绑定的值,刚好能解决上面两个问题。
把原来的绑定代码:
btn[i].bind('<Button-3>',lambda e, i: change_text(e,i))
替换为以下写法:
btn[i].bind('<Button-3>', lambda e, idx=i: change_text(e, idx))
这里的idx=i是lambda的默认参数,创建lambda时就把当前轮次的i值存到idx里。触发回调时,Tkinter自动传入事件对象e,idx直接用提前存好的固定值,既不会出现参数缺失的报错,也不会出现多个按钮修改同一个目标的串值问题。
修正后的完整可运行代码
from tkinter import * root = Tk() def change_text(e, i): btn[i].config(text='another') btn = [] files = [] for i in range(5): files.append("button " + str(i)) for i in range(len(files)): btn.append(Button(root, text=files[i], width=50)) btn[i].pack() # 移除了原代码中无实际作用的e_i=[]空列表 btn[i].bind('<Button-3>', lambda e, idx=i: change_text(e, idx)) root.mainloop()
运行后右键任意按钮,对应按钮的文本就会更新为
another,完全适配扫雷游戏右键标记、修改按钮展示文本的功能需求。
内容的提问来源于stack exchange,提问作者Dima Calmis
相关产品推荐
相关产品推荐

