使用for循环创建Tkinter按钮时无法控制单个按钮的问题求助
解决Tkinter批量创建按钮时点击仅修改最后一个按钮的问题
问题根源
循环创建按钮时,lambda表达式里的i和btn_list[i]是对循环变量的引用,而非当前循环的数值副本。当循环结束后,i的最终值是15,所有按钮点击时都会传入btn_list[15]和15,导致所有操作都指向最后一个按钮。
修正方案
给lambda绑定当前循环的按钮实例和索引,确保每个按钮的command保存当前循环的具体值,而非引用循环变量。下面是两种可行的实现方式:
方式一:使用lambda默认参数
直接在lambda中添加默认参数,将当前循环的btn和i赋值给参数,这样每次循环都会生成独立的绑定:
import tkinter as tk root = tk.Tk() win_width = 355 win_height = 312 root.geometry("{}x{}+{}+{}".format(win_width,win_height, int(root.winfo_screenwidth()/2 - win_width/2), int(root.winfo_screenheight()/2 - win_height/2)-50)) beats = ['']*16 instrument = 'kick' def set_beat(x,num): global instrument,beats beats[num] = '' if beats[num]==instrument else instrument x['text'] = beats[num] btn_list = [] row,col = 0,0 for i in range(16): btn = tk.Button(root,text=' ',command=lambda btn=btn, num=i: set_beat(btn, num)) btn.grid(row=row,column=col,padx=5,pady=5) btn_list.append(btn) col+=1 if col==4: row+=1;col = 0 root.mainloop()
方式二:使用闭包函数封装
写一个辅助函数生成command,通过闭包保存当前循环的按钮和索引:
import tkinter as tk root = tk.Tk() win_width = 355 win_height = 312 root.geometry("{}x{}+{}+{}".format(win_width,win_height, int(root.winfo_screenwidth()/2 - win_width/2), int(root.winfo_screenheight()/2 - win_height/2)-50)) beats = ['']*16 instrument = 'kick' def set_beat(x,num): global instrument,beats beats[num] = '' if beats[num]==instrument else instrument x['text'] = beats[num] # 辅助函数生成绑定了当前按钮和索引的command def make_button_command(btn, num): return lambda: set_beat(btn, num) btn_list = [] row,col = 0,0 for i in range(16): btn = tk.Button(root,text=' ',command=make_button_command(btn, i)) btn.grid(row=row,column=col,padx=5,pady=5) btn_list.append(btn) col+=1 if col==4: row+=1;col = 0 root.mainloop()
说明
两种方式都能让每个按钮的command独立绑定自己对应的实例和索引,点击时就会正确修改自身的文本内容,避免了循环变量引用导致的问题。
内容的提问来源于stack exchange,提问作者GhostShadow
相关产品推荐
相关产品推荐

