0

So I have created 5 x 5 buttons using for-loop:

for i in range(5):
for j in range(5):
    gameButton = Button(boardFrame, bg="khaki1", width=10, height=5, command=colorTheButton)
    gameButton.grid(row=i, column=j, sticky=E)

and I have a function called changeColor():

def colorTheButton():
    global colorCounter, boardColor
    row = gameButton.grid_info()['row']
    column = gameButton.grid_info()['column']

    if colorCounter % 2 == 0:
        boardColor = "black"
    else:
        boardColor = "white"
    colorCounter += 1

    button = button(boardFrame, bg=boardColor, width=10, height=5)
    button.grid(row=row, column=column)

Now the problem is, every time I click any button it'll not change the color of the clicked button instead, it'll change the color of the last created button. What should I do to change the clicked button instead of the last one?

maxime
  • 35
  • 6

2 Answers2

1

First of all you're creating multiple buttons but they're overwritingly assigned to the very same variable, gameButton and thus you can only refer to the last button created, later on, which would be problematic.

You can instead create your buttons like:

gameButton = list()
for i in range(5)
    gameButton.append(list())
    for j in range(5)
        gameButton[i].append(Button(boardFrame, bg="khaki1", width=10, height=5, command=colorTheButton))
        gameButton[i][j].grid(row=i, column=j, sticky=E)

Secondly you should rather pass the node information to the colorTheButton method instead of trying to find which button is pressed later on:

gameButton[i].append(Button(boardFrame, bg="khaki1", width=10, height=5, command=lambda row=i, col=j : colorTheButton(row, col))

modify colorTheButton accordingly:

def colorTheButton(row, column):
    global colorCounter, boardColor
    if colorCounter % 2 == 0:
...

Note: Last 2 lines of that function keeps creating non-referable button objects widgets as well.

So better:

def colorTheButton(row, column):
    global colorCounter, boardColor
    if colorCounter % 2 == 0:
        boardColor = "black"
    else:
        boardColor = "white"
    colorCounter += 1

    gameButton[row][column]['bg'] = boardColor
Nae
  • 14,209
  • 7
  • 52
  • 79
0

In your for loop, you give each new button the same name, gameButton. This means that only the most recent button is saved to the variable, in this case the bottom right button.

When you say row = gameButton.grid_info()['row'] and column = gameButton.grid_info()['column'], this therefore gets only the last buttons position in the grid. This means that only the last button is updated as you have observed.

To fix this, you could implement a list containing the buttons, or implement another way. One such way is this:

for i in range(5):
    for j in range(5):
        gameButton = Button(boardFrame, bg="khaki1", width=10, height=5,
                            command=lambda i=i, j=j: colorTheButton(i, j))
        gameButton.grid(row=i, column=j, sticky=E)

I changed the command to lambda i=i, j=j: colorTheButton(i, j), which passes the actual grid location of the button to colorTheButton.

And then colorTheButton is as follows:

def colorTheButton(row, column):
    global colorCounter, boardColor
    if colorCounter % 2 == 0:
        boardColor = "black"
    else:
        boardColor = "white"
    colorCounter += 1

    button = Button(boardFrame, bg=boardColor, width=10, height=5)
    button.grid(row=row, column=column)

Note that I have tried to keep your code as similar as possible; this code stills produces a new button each time, overlaying the old one in place. This is not as efficient as modifying the original button, but that is a different question!

SneakyTurtle
  • 1,831
  • 1
  • 13
  • 23