Tkinter循环创建ScrolledText焦点事件仅最后一个生效如何解决
问题解决思路与修复代码
问题本质
Python循环中的lambda表达式存在迟绑定特性:绑定回调时不会立即保存当前迭代的控件变量,事件触发时读取的变量已经是循环结束后最后一个控件的实例,因此所有事件都只对最后一个ScrolledText生效,和你设置的name属性没有关系。
最优解决方法:直接使用事件对象的widget属性
Tkinter事件回调的第一个参数是触发事件的事件对象,其widget属性就对应当前触发事件的控件,不需要额外捕获循环变量,也不需要做name匹配,逻辑最简洁:
from tkinter.scrolledtext import ScrolledText from tkinter import Tk root = Tk() w, h = root.winfo_screenwidth(), root.winfo_screenheight() root.geometry("%dx%d+0+0" % (w, h)) for x in range(6): # 修复x为整型不能直接拼接字符串的问题 kiblogbn = ScrolledText(root, name="frm_"+str(x), width=25, height=30, border=2, relief="solid") kiblogbn.grid(column=x, row=0, padx=10, pady=10, ipady=25, sticky="W") kiblogbn.insert("1.0", 'Copy logs here.') # 用e.widget获取当前触发事件的控件 kiblogbn.bind("<FocusIn>", lambda e: e.widget.delete('1.0', 'end')) # get时用end-1c排除控件自带的末尾换行,判断更准确 kiblogbn.bind("<FocusOut>", lambda e: e.widget.insert("1.0", "Copy logs here.") if e.widget.get("1.0", "end-1c").strip() == "" else None) if __name__ == "__main__": root.mainloop()
可选替代方法:lambda默认参数捕获当前变量
如果你不想用事件对象的属性,也可以通过给lambda设置默认参数的方式,在每次迭代时就把当前控件实例保存下来,避免后续迭代覆盖变量:
# 绑定示例 kiblogbn.bind("<FocusIn>", lambda _, w=kiblogbn: w.delete('1.0', 'end')) kiblogbn.bind("<FocusOut>", lambda _, w=kiblogbn: w.insert("1.0", "Copy logs here.") if w.get("1.0", "end-1c").strip() == "" else None)
内容的提问来源于stack exchange,提问作者scll.raz
相关产品推荐
相关产品推荐

