Search code examples
pythontkinterwidgettkinter-button

How to link an array of buttons to an array of variables with Python?


I'm trying to make rows of buttons and variables that when you click a button in a row it changes a variable in the same row. However I don't have a clue how to connect a button and a variable together.

I've tried using lambda, additional variables, and the closest thing I achieved was changing all variables by certain number with any button click, but that's not what I want.

Here is my code:

rows = 100
m = []
bt = list()

def popo():
    for i in range(rows):
        m.append(0)
        count = lambda x: x+1
        w = Button(master, text = "Act", command = count(m[i]))
        w.grid(row = i % 40, column = (i // 40) * 6, sticky = W, pady = 2)
        bt.append(w)
        print(m[i])

        l1 = Label(master, text = m[i])        
        l1.grid(row = i % 40, column = (i // 40) * 6 + 1, sticky = W, pady = 2)

b1 = Button(master, text = "Act", command = popo)
b1.grid(row = 0, column = 0, sticky = W, pady = 2)

Whenever I click any button in a list it doesn't change variables and of course doesn't do anything.


Solution

  • Note that command=count(m[i]) will execute count(m[i]) immediately and assign the result (which is 1) to command option.

    Also the associated label will not be updated automatically when m[i] is updated.

    Suggest to:

    • change m to list of IntVar() instead
    • use textvariable option when creating the associated label

    Below is the updated popo():

    def popo():
        for i in range(rows):
            # create an instance of IntVar() and append to list m
            m.append(IntVar())
            # lambda to increase the variable by 1
            count = lambda x=i: m[x].set(m[x].get()+1)
            w = Button(master, text = "Act", command = count) # assign the lambda to command
            w.grid(row = i % 40, column = (i // 40) * 6, sticky = W, pady = 2)
            bt.append(w)
            print(m[i].get())
    
            l1 = Label(master, textvariable = m[-1]) # used textvariable instead
            l1.grid(row = i % 40, column = (i // 40) * 6 + 1, sticky = W, pady = 2)
    

    Then the associated label will be updated automatically when the corresponding IntVar is updated.