4

I am trying to implement a game called "Five In a Row". And I create a 15×15 list to put the buttons. (I used range(16) because I also want a row and a column to display the row number and column number)

I hope my implementation will be like when a button is clicked, it becomes a label. But I don't know which button the user clicks.

How am I able to implement that? Thanks!

from tkinter import *
root=Tk()
root.wm_title("Five In a Row")
buttonlst=[ list(range(16)) for i in range(16)]

chess=Label(root,width=2,height=2,text='0')

def p(button):
    gi=button.grid_info()
    x=gi['row']
    y=gi['column']
    button.grid_forget()
    chess.grid(row=x,column=y)
    buttonlst[x][y]=chess

for i in range(16):
    for j in range(16):
        if i==0:
            obj=Label(root,width=2,text=hex(j)[-1].upper())
        elif j==0:
            obj=Label(root,width=2,text=hex(i)[-1].upper())
        else:
            obj=Button(root,relief=FLAT,width=2,command=p(obj))
        obj.grid(row=i,column=j)
        buttonlst[i][j]=obj

root.mainloop()

There is a similar question How to determine which button is pressed out of Button grid in Python TKinter?. But I don't quite get that.

3
  • This looks like an exact duplicate of the question you link to. What part of the answers don't you get? Can you be more specific? Commented Nov 14, 2017 at 22:04
  • @BryanOakley I don't know how he stores the info of the button. Commented Nov 14, 2017 at 22:27
  • You can have a function that takes button position info as argument at the very least if you want to determine which button is pressed. Commented Nov 14, 2017 at 22:31

2 Answers 2

10

To pass the button instance to the command, you must do it in two steps. First, create the button, and then in a second step you configure the command. Also, you must use a lambda to create what's called a closure.

For example:

obj=Button(root,relief=FLAT,width=2)
obj.configure(command=lambda button=obj: p(button))
Sign up to request clarification or add additional context in comments.

Comments

1

When you use command = p(obj) you are actually calling the function p. If you want to pass a function with parameters you should create a lambda function. Therefore, the command assignment should be something like:

command = lambda: p(obj)

That will pass the object properly into p function.

3 Comments

This won't work if this code is called in a loop and obj is different for each iteration.
Why not? obj is different in every iteration as it is assigned previously, so command takes the right variable reference for each new button.
obj is different during the loop, but the lambda doesn't run in the loop so it will pick up the last value that was stored in obj. See stackoverflow.com/q/13355233/7432 for one explanation.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.