-1

The buttons are being created in a larger loop iterating through i then j with the following code:

btn[i][j] = Button(lbl_frm, width=24, height=24, image=unchecked_img,
                                       command=lamda:change_btn_img(btn[i][j]),relief=SOLID)

                global state
                state = "unchecked"

                btn[i][j].place(relx=.5, rely=.5, anchor='c')

with the function to change the configuration of the button:

def change_btn_img(btn):
    global state
    if state == "checked":
        btn.configure(image=unchecked_img)
        state = "unchecked"

    elif state == "unchecked":
        btn.configure(image=checked_img)
        state = "checked"

However, this isn't working as if I click any button it only changes the image of btn[i][j] where i and j were values reached in the last iteration of the loop. The buttons are used to form a grid, and in this case clicking any changes the last element in the last row. Is there any way to make it so that the i and j used when declaring the command upon creation of the button are fixed to that specific button?

Dillon
  • 1
  • hi, interesting, perhaps this might be of interest https://stackoverflow.com/questions/44210557/changing-image-with-button-click-with-python-tkinter – IronMan Feb 10 '21 at 02:57
  • common problem with lambda in loop: `command=lamda x=i, y=j:change_btn_img(btn[x][y])` – furas Feb 10 '21 at 03:16

1 Answers1

0

It is common problem with lambda in loop.

You have to assing i, j to arguments in lambda (ie. x,y) and it will copy values from i, j instead of using references to i, j

 command=lamda x=i, y=j:change_btn_img(btn[x][y]) 

BTW:

In Python you can create own atributes in class so maybe you should keep state in Button

 btn[i][j].state = "unchecked"

and then you don't need global and every button has own state


Or maybe you should create own Widget - something like this:

class MyButton(tkinter.Button):

    def __init__(self, parent, *args, **kwars):
        super().__init__(parent, width=24, height=24, image=unchecked_img, command=self.change, relief=tkitner.SOLID)
        self.state = "unchecked"
        
    def change(self):
        if self.state == "checked":
            self.configure(image=unchecked_img)
            self.state = "unchecked"
        elif self.state == "unchecked":
            self.configure(image=checked_img)
            self.state = "checked"
            

and later you could simply use

btn[i][j] = MyButton(lbl_frm)

btn[i][j].place(relx=.5, rely=.5, anchor='c')
furas
  • 134,197
  • 12
  • 106
  • 148