有没有办法在单击时更改迭代创建的按钮的图像?

问题描述

按钮是在一个更大的循环中创建的,循环遍历 i 然后 j 使用以下代码

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')

具有更改按钮配置的功能

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"

但是,这并不像我单击任何按钮一样工作,它只会更改 btn[i][j] 的图像,其中 i 和 j 是在循环的最后一次迭代中达到的值。 这些按钮用于形成一个网格,在这种情况下,单击任何按钮都会更改最后一行中的最后一个元素。有什么方法可以使在创建按钮时声明命令时使用的 i 和 j 固定到该特定按钮?

解决方法

lambda 中的 loop 是常见问题。

您必须将 ij 赋值给 lambda 中的参数(即 xy),它会从 {{1} 复制值}},i 而不是使用对 j,i

的引用
j

顺便说一句:

在 Python 中,您可以在类中创建自己的属性,因此也许您应该将 command=lamda x=i,y=j:change_btn_img(btn[x][y]) 保留在 state

Button

然后你就不需要 btn[i][j].state = "unchecked" 并且每个按钮都有自己的 global


或者您应该创建自己的 state - 像这样:

Widget

然后你可以简单地使用

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"