How to make a responsive grid with tkinter?

Question:

I have a grid made in tkinter that looks like so –

Here, each column is a list inside which there are values ‘green’ or ‘yellow’ which correspond to the colour of each cell in the grid. As you can see it is a 9×9 grid. I wish to get the exact list index of where the user clicks upon which the colour of that cell is changed.

So, for example, if the user clicks on the 1 square of the 1st row and 1st column, then that square should change its colour to yellow and I want (0, 0) printed in the console.

enter image description here

Below is my code –

color_grid = [[random.choice(COLORS) for j in range(GRID_SIZE)] for i in range(GRID_SIZE)]


def on_click(event):  # event handler function
    item = canvas.find_closest(event.x, event.y)
    canvas.itemconfig(item, fill='green')  # set new fill color

def draw_board(canvas):
    for i in range(GRID_SIZE): # GRID_SIZE = 9
        for j in range(GRID_SIZE):
            x0, y0 = i * SQUARE_SIZE, j * SQUARE_SIZE # SQAURE_SIZE = 40
            x1, y1 = x0 + SQUARE_SIZE, y0 + SQUARE_SIZE
            rect = canvas.create_rectangle(x0, y0, x1, y1, fill=color_grid[i][j])
            canvas.tag_bind(rect, '<Button>', on_click)  # bind the event handler function

Asked By: Harsh Darji

||

Answers:

You can simply pass the coordinates and the item ID to on_click() as below:

def on_click(pos, item):
    print(pos)  # show coordinates in console
    # determine the new color
    color = "green" if canvas.itemcget(item, "fill")=="yellow" else "yellow"
    # change the color
    canvas.itemconfig(item, fill=color)


def draw_board(canvas):
    for i in range(GRID_SIZE): # GRID_SIZE = 9
        for j in range(GRID_SIZE):
            x0, y0 = i * SQUARE_SIZE, j * SQUARE_SIZE # SQAURE_SIZE = 40
            x1, y1 = x0 + SQUARE_SIZE, y0 + SQUARE_SIZE
            rect = canvas.create_rectangle(x0, y0, x1, y1, fill=color_grid[i][j])
            # pass coordinates and item ID to callback
            canvas.tag_bind(rect, '<Button>', lambda e, pos=(j,i), item=rect: on_click(pos, item))  # bind the event handler function
Answered By: acw1668