Reputation: 31
I'm writing a program that displays a grid of buttons, when a button is pressed I want it to print the location of the button in the grid ("row column") out to the console. Here is what I have
import Tkinter as tk
class board(tk.Tk):
def __init__(self, parent=None):
tk.Tk.__init__(self,parent)
self.rows = 5
self.columns = 5
self.init_board()
def init_board(self):
for i in range(self.rows):
for j in range(self.columns):
cmd = lambda: self.button_callback(i,j)
b = tk.Button(self, text=str(" "), command=cmd)
b.grid(row=i, column=j)
def button_callback(self, row, col):
print(str(row) + " " + str(col))
if __name__ == '__main__':
board().mainloop()
the problem is that when I click on any of the buttons I get "4 4" printed out which is the location of the last button instantiated in the loop. I don't know why this is happening, please help!
Upvotes: 3
Views: 1166
Reputation: 515
As an addition to what @falsetru has said, You can also use functools.partial
.
from functools import partial
# ...
cmd = partial(self.button_callback, i, j)
# ...
Or you can "emulate" partial
's behavior like this: (use this snippet instead of the import statement)
def partial(fn, i, j):
def nested():
fn(i, j)
return nested
A better "emulation" can be found here.
Upvotes: 0
Reputation: 369074
In the function created using lambda
, i
, j
refers to the varaible in the init_board
function, which are set to 4, 4 after the for
loop ends.
You can workaround this using default argument.
Replace the following line:
cmd = lambda: self.button_callback(i,j)
with:
cmd = lambda i=i, j=j: self.button_callback(i,j)
Upvotes: 7