Buttons and Buttons: Using Lambda

I'm trying to make multiple checkboxes based on a list, however it looks like I'm pressing the command invocation and variable aspect of the button.

My code:

class Example(Frame):

def __init__(self, parent):
    Frame.__init__(self, parent)

    self.parent = parent
    self.initUI()

def initUI(self):

    self.courses = ["CSE 4444", "CSE 4343"]
    self.vars = []

    self.parent.title("Homework Helper")

    self.course_buttons()

    self.pack(fill=BOTH, expand=1)

def course_buttons(self):
    x = 0
    y = 0

    for i in range(0, len(self.courses)):
        self.vars.append(IntVar())
        cb = Checkbutton(self, text=self.courses[i],
                         variable=self.vars[i],
                         command=lambda: self.onClick(i))
        cb.select()
        cb.grid(column=x, row=y)
        y = y+1

def onClick(self, place):

    print place
    if self.vars[place].get() == 1:
        print self.courses[place]

      

The testing so far is that the course will be printed to the console when the checkbox is on, however it only works for the second button, the "CSE 4343" button. When I interact with the "CSE 4444" button, nothing is printed.

In addition, the "place" value is always 1 onClick, I click the "CSE 4343" button or the "CSE 4444" button.

+3


source to share


1 answer


When you create a function lambda

, its references are only resolved in values ​​when the function is called. So, if you create functions lambda

in a variable value loop ( i

in your code), each function gets the same i

- the last one that was available.

However, when you define a function with a default parameter, that reference is resolved as soon as the function is defined. By adding such a parameter to your functions lambda

, you can ensure that they get the value that you intended them to be.



lambda i=i: self.onClick(i)

      

This is called lexical scoping or closure if you want to do more research.

+6


source







All Articles