Search code examples
pythonpython-3.xtkinterlambda

Python TKinter button passing the same variable instead of updating with funciton


I'm learning TKinter and trying to make a GUI with multiple counters. The problem I'm running into is that the variable passed to the increment functions is just the declared root.counter number and it doesn't update after the function. So if it's set to 5, it'll add to 6 or subtract to 4, but that's it.

Not sure if I'm misunderstanding the lambda or how the variables themselves are stored.

from tkinter import *

def clicked_plus(val,lab):
    print(val)
    val += 1
    total(val,lab)
def clicked_minus(val,lab):
    print(val)
    if val > 0:
        val -= 1
    total(val,lab)
def total(val,lab):
    print(val)
    lab['text'] = str(val)

root = Tk()

root.counter = 5
root.counter2 = 100
root.geometry('350x200')


b = Button(root, text="+", command=lambda: clicked_plus(root.counter, L))
b.grid(row=0, column=2)
b2 = Button(root, text="-", command=lambda: clicked_minus(root.counter, L))
b2.grid(row=0, column=0)

L = Label(root, text="0")
L.grid(row=0, column=1)


b3 = Button(root, text="+", command=lambda: clicked_plus(root.counter2, L2))
b3.grid(row=1, column=2)
b4 = Button(root, text="-", command=lambda: clicked_minus(root.counter2, L2))
b4.grid(row=1, column=0)

L2 = Label(root, text="0")
L2.grid(row=1, column=1)

root.mainloop()

Solution

  • tkinter has special classes for widgets that contain variables. In your case the class tk.IntVar() should be assigned to the "textvariable" field of the Label element, and then you can reassign the value in your functions in a similar way to what you had.

    Here is an updated example:

    from tkinter import *
    
    def clicked_plus(label_variable):
        label_variable.set(label_variable.get() + 1)
    
    def clicked_minus(label_variable):
        if label_variable.get() > 0:
            label_variable.set(label_variable.get() - 1)
    
    root = Tk()
    
    label_var1 = IntVar()
    label_var2 = IntVar()
    label_var1.set(5)  # You need to use .set and .get to work with the value
    label_var2.set(100)
    root.geometry('350x200')
    
    
    b = Button(root, text="+", command=lambda: clicked_plus(label_var1))
    b.grid(row=0, column=2)
    b2 = Button(root, text="-", command=lambda: clicked_minus(label_var1))
    b2.grid(row=0, column=0)
    
    L = Label(root, textvariable=label_var1)  # Now using a textvariable
    L.grid(row=0, column=1)
    
    
    b3 = Button(root, text="+", command=lambda: clicked_plus(label_var2))
    b3.grid(row=1, column=2)
    b4 = Button(root, text="-", command=lambda: clicked_minus(label_var2))
    b4.grid(row=1, column=0)
    
    L2 = Label(root, textvariable=label_var2)  # Now using a textvariable
    L2.grid(row=1, column=1)
    
    root.mainloop()