2
votes

I am creating a keyboard in TKinter. pressing a button should just print out the text for that button. For some reason every button prints out ctrl which is the last button created. How do I change it so that it actually prints out the respective text for each button?

 def press(key):
     print(key)

 def createWidgets(self):
    for tup in layout.layout:
        for key, value in tup:
            button = Button(self, text=key, command=lambda: self.press(key))
            self.kboard_buttons.append(button)
            button.pack(side="left")
1
I can't see anything wrong with the code you posted. Could you paste the entire code into a gist at gist.github.com and post the link here?twasbrillig
I can see wrong only in print(key) that is misindented, if such a word exists...gboffi
Could you please try lambda k=key: self.press(k) and let us know of your findings?gboffi
Well, iCodez flashed a similar answer while I was writing my comment so I'm now pretty sure my suggestion was correct!gboffi
@JayronHubbard The answer by iCodez below is both correct and helpful, really helpful with regard to your misunderstanding, the gist is not really necessary any longer. Go and approve... Ciao fromgboffi

1 Answers

2
votes

The expression inside a lambda function is evaluated when the function is called, not when it is defined. This means that the key in:

command=lambda: self.press(key)

will always refer to the last value held by key in the for-loop.

You can fix this problem by simply capturing the value of key as a default argument for the lambda:

command=lambda key=key: self.press(key)

Because default arguments are evaluated when a function is defined, this will ensure that the key inside the lambda refers to the current value of key inside the for-loop and not the last value.