0

I'm writing a simple gui to change the brightness of the monitor, however I'm having a problem.

def start_ui(self):
    root = Tk()
    root.wm_title("Set brightness")

    col = 0
    for k, v in self.monitors.iteritems():
        print k
        Scale(root, variable = DoubleVar(), command = lambda(r): self.change_brightness(k, r)).grid(row=0, column=col)
        labelVar = StringVar()
        label = Label(root, textvariable=labelVar).grid(row=1, column=col)
        labelVar.set(k)
        col += 1

    root.mainloop()

This is where I start my UI, my self.monitors dictionary looks like this: {'LVDS1': '1.0', 'VGA1': '1.0'}.

The output of the loop is "LVDS1, VGA1" as expected, however, when I move the sliders and the callback is called, the last value of k is always passed, in this case "VGA1", no matter which slider I moved.

What could be causing this?

Leonardo Arroyo
  • 573
  • 6
  • 16
  • This has the same underlying problem as http://stackoverflow.com/questions/12423614/local-variables-in-python-nested-functions. – Rob Watts Jun 09 '14 at 20:08

1 Answers1

3

The problem is with your lambda function - it wants to call change_brightness with k and r, but k is not resolved until it is called. As such, it is using the value held by the global variable k at the time the function is called. If you had a line outside the for loop that said k = 'SomeNonsenseValue', then that is the value that would be passed in to the lambda function.

Try this instead:

for k, v in self.monitors.iteritems():
    def createLambda(k):
        return lambda(r): self.change_brightness(k, r)
    Scale(root, variable = DoubleVar(), command = createLambda(k)).grid(row=0, column=col)

This creates a closure that allows the lambda function to retain the value of k at the time of the creation of the function.

Rob Watts
  • 6,866
  • 3
  • 39
  • 58