1

I am trying to program a minesweeper game on python using tkinter. I started off by creating a grid of buttons using a two dimensional list, and the generation of the button and everything works. The only issue I have is that I don't know how to determine which button in my grid is clicked. My goal is to be able to click on a button and through that I know the coordinates of that in my grid [row][col].

This is the code I have so far.

from tkinter import *
from functools import partial
from itertools import product

# Here, we are creating our class, Window, and inheriting from the Frame
# class. Frame is a class from the tkinter module. (see Lib/tkinter/__init__)
class Window(Frame):


    # Define settings upon initialization. Here you can specify
    def __init__(self, master=None):

        # parameters that you want to send through the Frame class. 
        Frame.__init__(self, master)   

        #reference to the master widget, which is the tk window                 
        self.master = master

        #with that, we want to then run init_window, which doesn't yet exist
        numRows = int(input("# of Rows: "))
        numCols = int(input("# of Cols: "))

        self.init_window(numRows, numCols)

    #Creation of init_window
    def init_window(self, rowNum, colNum):
        # print(x, y)
        # changing the title of our master widget      
        self.master.title("GUI")

        # allowing the widget to take the full space of the root window
        self.pack(fill=BOTH, expand=1)

        # creating a button instance
        #quitButton = Button(self, text="Exit",command=self.client_exit)

        # placing the button on my window
        #quitButton.place(x=0, y=0)
        but = []
        for row in range(0, rowNum):
            curRow = []
            for col in range(0, colNum):
                curRow.append(Button(self, bg="gray", width=2,height=1, command=lambda: self.open_button(row, col)))
                curRow[col].grid(row=row,column=col)
            but.append(curRow)

        #but[1][1].config(state="disabled")
        #but[1][1]["text"] = "3"
        #but[1][1]["bg"] = "white"

    def open_button(self, r, c):
        print(r, " : ", c)

# root window created. Here, that would be the only window, but
# you can later have windows within windows.
root = Tk()

root.geometry("600x600")

#creation of an instance
app = Window(root)

#mainloop 
root.mainloop()

Whenever I click on the grid, it gives me the very last button... For example, a 9x9 grid always gives me "9 : 9" whenever I click any button.

Solutions welcomed! I want an easy way to get the coordinates without changing too much of the code (if possible).

Thanks!

Bryan Oakley
  • 370,779
  • 53
  • 539
  • 685

1 Answers1

2

The row and col variables are assigned each value in the ranges. At the end of the loop that generates the buttons, the values for those variables are left at the last values in the ranges, e.g. "9 : 9".

Try replacing the line

curRow.append(Button(self, bg="gray", width=2,height=1, command=lambda: self.open_button(row, col)))

with

curRow.append(Button(self, bg="gray", width=2,height=1, command=lambda rw=row, cl=col: self.open_button(rw, cl)))

This assigns the values of row and col at the time the button is created to the variables rw and cl, which remain the same for each button as the for-loop iterates.

See this link: Tkinter assign button command in loop with lambda

enivium
  • 150
  • 1
  • 10