Home > Enterprise >  Changing one scale widget will change the secone one
Changing one scale widget will change the secone one

Time:01-28

I have two scale widgets in my code that are supposed to display values from a list. I want to be able to set individual values for both sliders. For example, for file 1 "2.4" and for file 2 "5.025". But currently I can only update the second (lower) slider without it triggering the first (upper) one. If I use the upper one, the value of the second one is also changed.

I'm stuck implementing the lambda function, so it would be create if some could give me a hint. Thanks!

import tkinter as tk


class File_Selection():
    def __init__(self, frame, text):

        self.frame = frame
        self.text = text

        self.label_file = tk.Label(self.frame, text=text)
        self.label_file.pack(side="left", anchor="s")

        self.label_test = tk.Label(self.frame, text="| Select value: ")
        self.label_test.pack(side="left", anchor="s")

        self.scale = tk.Scale(self.frame, orient=tk.HORIZONTAL, from_=0)
        self.scale.pack(side="left", anchor="s")

class View:

    def __init__(self, view):

        self.view = view

        self.frame = tk.Frame(self.view)
        self.frame.pack()
    
        self.frame_row1 = tk.Frame(self.frame)
        self.frame_row1.pack(side="top")

        self.frame_row2 = tk.Frame(self.frame)
        self.frame_row2.pack(side="top")

        self.file_one = File_Selection(self.frame_row1, "File 1")
        self.file_two = File_Selection(self.frame_row2, "File 2")


class Controller:

    def __init__(self):
        self.root = tk.Tk()
        self.view = View(self.root)

        self.values = [1.01,2.4,3.6,4.89,5.025,6.547]

        self.view.file_one.scale.bind('<Enter>', self.update_scale)
        self.view.file_two.scale.bind('<Enter>', self.update_scale)

    def run(self):
        self.root.mainloop()

    def update_scale(self, event):
        self.active_scales = [self.view.file_one.scale, self.view.file_two.scale]

        for scale in self.active_scales:
            scale.config(from_=min(self.values), to=max(self.values), resolution=0.001, command=lambda value=scale: self.set_scale(value, scale))
            
    def set_scale(self, value, scale):
        self.newvalue = min(self.values, key=lambda x: abs(x-float(value)))
        scale.set(self.newvalue)

if __name__ == "__main__":
    c = Controller()
    c.run()

CodePudding user response:

The problem is that you have both scales set to active_scales. You can take advantage of the event and do away with active_scales.

You can get the widget associated with an event with event.widget. So, you can change the update_scales function from

def update_scale(self, event):
    self.active_scales = [self.view.file_one.scale, self.view.file_two.scale]
        for scale in self.active_scales:
            scale.config(from_=min(self.values), to=max(self.values), resolution=0.001, command=lambda value=scale: self.set_scale(value, scale))

to

def update_scale(self, event):
    event.widget.config(from_=min(self.values), to=max(self.values), resolution=0.001, command=lambda value=event.widget: self.set_scale(value, event.widget))

Additionally, since self.values don't appear to change, it does not seem necessary to config each scale to change its bounds and resolution on each event. You can instead pull that out of the event and make you Controller class as follows.

class Controller:

    def __init__(self):
        self.root = tk.Tk()
        self.view = View(self.root)

        self.values = [1.01,2.4,3.6,4.89,5.025,6.547]

        self.view.file_one.scale.bind('<Enter>', self.update_scale)
        self.view.file_two.scale.bind('<Enter>', self.update_scale)
        self.view.file_one.scale.config(from_=min(self.values), to=max(self.values), resolution=0.001)
        self.view.file_two.scale.config(from_=min(self.values), to=max(self.values), resolution=0.001)

    def run(self):
        self.root.mainloop()

    def update_scale(self, event):
        event.widget.config(command=lambda value=event.widget: self.set_scale(value, event.widget))
       
    def set_scale(self, value, scale):
        self.newvalue = min(self.values, key=lambda x: abs(x-float(value)))
        scale.set(self.newvalue)
  •  Tags:  
  • Related