I can not fetch the values correctly for the different scalebars I created in an scrollable canvas. If I move the sliders it changes allways the last entry. Please advise if you have ideas to that code.
It prints out the changed number but is not placed in the correct position of u[x]
Print out example changed first slider to 1
1 correct (print(val)) {0: 0, 1: 0, 2: 0, 3: 0, 4: 0, 5: 0, 6: 0, 7: 0, 8: 0, 9: '1'} false should be (print(str(u)) {0: '1', 1: 0, 2: 0, 3: 0, 4: 0, 5: 0, 6: 0, 7: 0, 8: 0, 9: 0}
import tkinter as tk
from tkinter import ttk
global II
label={}
scale={}
u={}
class Scrollable(tk.Frame):
def __init__(self, frame, width=32):
scrollbar = tk.Scrollbar(frame, width=width)
scrollbar.pack(side=tk.RIGHT, fill=tk.Y, expand=False)
self.canvas = tk.Canvas(frame, yscrollcommand=scrollbar.set)
self.canvas.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
scrollbar.config(command=self.canvas.yview)
self.canvas.bind('<Configure>', self.__fill_canvas)
# base class initialization
tk.Frame.__init__(self, frame)
# assign this obj (the inner frame) to the windows item of the canvas
self.windows_item = self.canvas.create_window(0,0, window=self, anchor=tk.NW)
def __fill_canvas(self, event):
canvas_width = event.width
self.canvas.itemconfig(self.windows_item, width = canvas_width)
def update(self):
print(scale)
self.update_idletasks()
self.canvas.config(scrollregion=self.canvas.bbox(self.windows_item))
root = tk.Tk()
body = ttk.Frame(root)
body.pack()
def print_value(val):
print(val)
u[II]=val
print(str(u))
scrollable_body = Scrollable(body, width=32)
#scrollable_body2 = Scrollable(body, width=32)
print(scrollable_body)
for II in range(10):
x={II:0}
u.update(x)
label[II]=tk.Label(scrollable_body, text="Hello "+str(II)).grid(column=0)
scale[II]=tk.Scale(scrollable_body, from_=-10, to=20,sliderlength=60, length=300, orient=tk.HORIZONTAL, command=print_value).grid(column=2)
scrollable_body.update()
root.mainloop()
Note that variable II
will be 9 after the for loop, so u[II]
inside print_value()
will be the same as u[9]
when the function is executed.
One of the workaround is binding default value of lambda argument to the required value as below:
def print_value(idx, val):
print(idx, val)
u[idx] = int(val)
print(u)
for II in range(10):
x={II:0}
u.update(x)
#u[II] = 0 # the above two lines can be replaced by this line actually
label[II]=tk.Label(scrollable_body, text="Hello "+str(II))
label[II].grid(row=II, column=0)
scale[II]=tk.Scale(scrollable_body, from_=-10, to=20, sliderlength=60, length=300, orient=tk.HORIZONTAL,
# use default value of argument to bind the required value and pass it to print_value()
command=lambda val, idx=II: print_value(idx, val))
scale[II].grid(row=II, column=2)