0

I am having some trouble with the button widgets.

Here's my code. Basically, what I would like to do is to print "0,0" when I press the first button, print "0,1" when I press the second button and so on. But what happens is that it always prints "1,1", which are last values in my for loops. How could I fix that?

Thanks a lot for helping

from tkinter import *

def show(x,y):

    print(x,y)

root = Tk()

a = 0

for i in range(2):

    for j in range(2):
        Button(root, text=a, command=lambda:show(i,j)).grid(column=j, row=i)
        a += 1

root.mainloop()
Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
A.P.
  • 461
  • 2
  • 8
  • 17

1 Answers1

0

It is because of the closure property of Python. To fix this, change

Button(root, text=a, command=lambda:show(i,j)).grid(column=j, row=i)

to

def inner(i=i, j=j):
    Button(root, text=a, command=lambda:show(i,j)).grid(column=j, row=i)
inner()

We are just wrapping the values of i and j with a function. Since the function show is not executed immediately, it just accepts the values of the two variables i and j. So, all the buttons now, will have the same i and j and they will get the values which are at the end of the loop.

Now, by defining a new function, we are getting a default parameter of the same names i and j and we get the values of i and j at the particular moment. So, the current values will be retained.

thefourtheye
  • 233,700
  • 52
  • 457
  • 497
  • 1
    Your answer might be better if you give the other ways to solve the problem in the same manner. For example, instead of creating `inner`, you can bind the values at the time you create the lambda like so: `command = lambda i=i, j=j: show(i,j)` – Bryan Oakley Nov 24 '13 at 13:24