使用for循环创建Tkinter多组件时Scrollbar仅作用于最后一组的问题
Tkinter循环创建多组滚动组件仅最后一组生效的问题
我用for循环创建四组Frame、Canvas和Scrollbar,代码能正常运行,也能在循环外访问每个Frame插入Label,但只有最后一组的Scrollbar可以拖动。
原代码如下:
f_s = ['s_one', 's_two', 's_three', 's_four'] f_o = ['f_one', 'f_two', 'f_three', 'f_four'] f_c = ['c_one', 'c_two', 'c_three', 'c_four'] f_f = ['fs_one', 'fs_two', 'fs_three', 'fs_four'] for f in range(4): f_o[f] = Frame(self.f_bot, width=250, height=600, bg=self.bg) f_o[f].grid(row=1, column=f) f_o[f].grid_propagate(False) f_c[f] = Canvas(f_o[f], width=width_s, height=600, bg=self.bg) f_c[f].pack(side=LEFT, fill=BOTH, expand=1) f_s[f] = Scrollbar(f_o[f], orient=VERTICAL, command=f_c[f].yview, bg=self.bg) f_s[f].pack(side=RIGHT, fill=Y) f_c[f].configure(yscrollcommand=f_s[f].set) f_c[f].bind('<Configure>', lambda event: f_c[f].configure(scrollregion=f_c[f].bbox('all'))) f_f[f] = Frame(f_c[f], bg=self.bg) # 注:原代码里的`t`是笔误,应该为`f` f_c[f].create_window((0, 0), window=f_f[f], anchor='nw')
如果把bind行改成下面这样,滚动会作用于前一组组件:
f_c[f].bind('<Configure>', lambda event: f_c[f-1].configure(scrollregion=f_c[f].bbox('all')))
问题原因
这是循环中lambda表达式的变量延迟绑定导致的。循环里定义的lambda不会立刻捕获当前的f值,而是等到事件触发时才去读取f的当前值——循环结束后f的最终值是3(range(4)的最后一个元素),所以所有组件的<Configure>事件都绑定到了最后一个Canvas上,自然只有最后一组滚动生效。
解决方案
方法1:给lambda添加默认参数捕获当前值
修改bind语句,把当前的f作为默认参数传入lambda,这样每次循环都会固定捕获当前的f值,而不是等到事件触发才读取:
f_c[f].bind('<Configure>', lambda event, idx=f: f_c[idx].configure(scrollregion=f_c[idx].bbox('all')))
方法2:用工厂函数生成独立的回调函数
写一个专门的小函数来生成事件回调,确保每个回调对应正确的Canvas组件:
def get_scroll_callback(target_canvas): def callback(event): target_canvas.configure(scrollregion=target_canvas.bbox('all')) return callback # 循环中的bind语句替换为: f_c[f].bind('<Configure>', get_scroll_callback(f_c[f]))
内容的提问来源于stack exchange,提问作者Edmond Cepele
相关产品推荐
相关产品推荐

