I'm making a minesweeper game in python using tkinter and need to bind right click to my buttons so that I can flag the bombs.
Right now, when I left-click I can see the button being pressed but its function isn't performed, and I can't even see the button being pressed when right-clicking. I feel like maybe the click(ind) function is messing things up, but when I remove it, ind is underlined in red everywhere.
How can I properly bind right click to this array of buttons?
from tkinter import *
def play():
win = Tk()
main_frame = Frame(win)
main_frame.pack()
btn_grid = list()
i = 0
for row in range(8):
for col in range(8):
btn_grid.append(Button(main_frame, height=1, width=1, font="Verdana", relief='groove',
command=lambda c=i: click(c)))
btn_grid[i].grid(row=row, column=col, sticky="news", ipadx=20, ipady=15)
i = i 1
def click(ind):
def left(event):
btn_grid[ind].config(text='L')
def right(event):
btn_grid[ind].config(text='R')
btn_grid[ind].bind("<Button-1>", left)
btn_grid[ind].bind("<Button-3>", right)
win.mainloop()
play()
CodePudding user response:
When I executed your code, I observed the following:
- Left-click followed by another left-click changes the text to
L
. - Left-click followed by a right-click changes the text to
R
.
The reason for this is that the click
function is executed only after you left-click on a button. Once the click
function is executed for a specific button, it responds to left and right clicks as you expect.
So, the direct solution to your problem will be to execute click
at the time of defining a button itself so that it is ready for left and right clicks.
Working Code 1:
from tkinter import *
def play():
def click(ind):
def left(event):
btn_grid[ind].config(text='L')
def right(event):
btn_grid[ind].config(text='R')
btn_grid[ind].bind("<Button-1>", left)
btn_grid[ind].bind("<Button-3>", right)
win = Tk()
main_frame = Frame(win)
main_frame.pack()
btn_grid = list()
i = 0
for row in range(8):
for col in range(8):
btn_grid.append(Button(main_frame, height=1, width=1, font="Verdana", relief='groove',
command=lambda c=i: click(c)))
btn_grid[i].grid(row=row, column=col, sticky="news", ipadx=20, ipady=15)
click(i)
i = i 1
win.mainloop()
play()
But there is a better solution. Instead of executing click
in this manner, you can directly bind a button to left
and right
without going through click
.
Working Code 2 (Improved):
from tkinter import *
def play():
def left(ind):
btn_grid[ind].config(text='L')
def right(ind):
btn_grid[ind].config(text='R')
win = Tk()
main_frame = Frame(win)
main_frame.pack()
btn_grid = list()
i = 0
for row in range(8):
for col in range(8):
btn_grid.append(Button(main_frame, height=1, width=1, font="Verdana", relief='groove'))
btn_grid[i].grid(row=row, column=col, sticky="news", ipadx=20, ipady=15)
btn_grid[i].bind("<Button-1>", lambda e,c=i: left(c))
btn_grid[i].bind("<Button-3>", lambda e,c=i: right(c))
i = i 1
win.mainloop()
play()
CodePudding user response:
It is better to bind the two events inside the for loop instead:
def play():
def left(event):
event.widget.config(text='L')
def right(event):
event.widget.config(text='R')
win = Tk()
main_frame = Frame(win)
main_frame.pack()
btn_grid = list()
for row in range(8):
for col in range(8):
btn_grid.append(Button(main_frame, height=1, width=1, font="Verdana", relief='groove'))
btn_grid[-1].grid(row=row, column=col, sticky="news", ipadx=20, ipady=15)
btn_grid[-1].bind("<Button-1>", left)
btn_grid[-1].bind("<Button-3>", right)
win.mainloop()
I would prefer using Label
instead of Button
.