Home > Blockchain >  Bind right click to array of buttons tkinter
Bind right click to array of buttons tkinter

Time:04-08

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:

  1. Left-click followed by another left-click changes the text to L.
  2. 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.

  • Related