I'm new to Tkinter and as my first project I wanted to create a Tic Tac Toe. I want to create 9 buttons, that will change their background image when I click on them, the problem is that I dont want to create a function for every single button but one function that will take the button in argument and will change its background image.
The code I wrote:
def play(bid):
if player == "X":
bid.config(image=cross)
if player == "O":
bid.config(image=circle)
b1 = tk.Button(app, text="", image=white, command=lambda id=b1: play(id))
b1.grid(column=0, row=0)
How can I pass b1 as an argument to play() function? Thanks
I tried to use b1 as an argument to play(), and use play() to change b1's image. When I try to run this code I get "name b1 is not defined".
CodePudding user response:
Define a single function to create, configure, and bind your button; then your callback can close over the necessary variable referring to your button. Something like
def play(bid):
if player == "X":
bid.config(image=cross)
if player == "O":
bid.config(image=circle)
def add_button(app, r, c):
b = tk.Button(app, text="", image=white)
b.config(command=lambda: play(b))
b.grid(column=c, row=r)
return b
for row in [0,1,2]:
for col in [0,1,2]:
# Save the return value somewhere if necessary
addButton(app, row, col)
The lambda expression contains a free variable b
, which refers to the variable b
in the closest enclosing scope, which is the call to add_button
where the lambda expression is evaluated.
CodePudding user response:
One way you can do it is to separate the creation of the button from the assignment using the .config
method.
b1 = tk.Button(app, text="", image=white)
b1.config(command=lambda btn_id=b1: play(btn_id))
This is not really the best way to go about it, it's better to instead pass something that defines the button like an Enum or text.
b1 = tk.Button(app, text="", image=white, command=lambda : play("b1"))
then check that "b1" is the input in your function, this way b1
can be redefined as what would happen in loops.