How to create a grid of buttons in Tk with functions that are called using their grid positions as arguments

Question:

I’m trying to make a simple gameboard using Tkinter with buttons that will change a single item in a 2D array, that corresponds to its position in the window – so I can check if the game’s over by checking the array. This is my code:

from tkinter import *
root = Tk()
board = []
for x in range(8):
    board.append([0,0,0,0,0,0,0,0])
def toggle(row,column):
    global board
    board[row][column] = (board[row][column]+1)%2
    print("-"*10)
    for x in board:
        for y in x:
            print(y, end="")
        print("")
    print("-"*10)
for x in range(8):
    for y in range(8):
        button = Button(master=root, text="--", command=lambda:toggle(y,x))
        button.grid(row=y,column=x)
root.mainloop()

However, this just ends up giving ALL the buttons the command toggle(7,7) and they all just toggle the final item of the final item in board. I tried an old question but I think it was python2, because the solution didn’t change anything for my code.

Asked By: Xerxes

||

Answers:

As the answer of Bryan Oakley of the “How to get grid information from pressed Button in tkinter?”, the provided source is missing something.

When declaring the command attached to each button, it is necessary for the lambda to have a link between parameters y,x and the grid parameter row=y,column=x:

    button = Button(master=root, text=xy_text,
        command=lambda row=x, column=y: toggle(row, column))
    button.grid(row=y,column=x)
Answered By: J. Piquard

The quick fix is:

def create_toggle_callback(y, x):
    return lambda: toggle(y, x)

and set the button command as:

button = Button(master=root, text="--", command=create_toggle_callback(y, x))

The reason for this is the way the variable scope works for closures in python. See this question for instance. Basically we need to capture the value when defining the lambda and not capture a reference to the variable.

Answered By: patthoyts
Categories: questions Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.