David
David

Reputation: 35

Tkinter Label referring to variable doesn't update when variable changed

I have a problem with tkinter when a label refers to a value and I update the value by pressing a button. The value is indeed updated but the label text referring to this value is not.

How can I change this code that the button updates the value and the label refering to this value is updated and shown in the root?

import tkinter

root = Tk()
root.title('Test Button')
root.geometry('600x450')


class Letter:
    def __init__(self, value):
        self.value = value


class Label:
    def __init__(self, master):
        self.a_label = tkinter.Label(root, text=current_letter.value)
        self.a_label.grid(row=2, column=1)

class Button:
    def __init__(self, master):

    self.Button1 = tkinter.Button(master, height = 12, width = 24,
                                  command= self.update_letter)
    self.Button1.grid(row=1, column=1)

    def update_letter(self):
        current_letter.value
        print("current_letter.value before: " + str(current_letter.value))
        current_letter.value += 1
        print("current_letter.value now: " + str(current_letter.value))
        root.update

#initialize a
a = Letter(0)
current_letter = a

b = Button(root)
l = Label(root)


root.mainloop()

Upvotes: 1

Views: 1160

Answers (3)

martineau
martineau

Reputation: 123413

My, what a big button you have.

If you use a tkinter Variable, then updating it will automatically change what's in any widgets that refers to one of them. Here's some documentation describing them, and here's some more describing how to use them.

Here's how that could be done to the code in your question:

import tkinter

root = tkinter.Tk()
root.title('Test Button')
root.geometry('600x450')


class Letter:
    def __init__(self, value):
        self.value = tkinter.IntVar(value=value)  # Store in a tkinter Variable.


class Label:
    def __init__(self, master, letter):
        self.a_label = tkinter.Label(master, textvariable=letter.value)
        self.a_label.grid(row=2, column=1)


class Button:
    def __init__(self, master, letter):
        self.letter = letter
        self.Button1 = tkinter.Button(master, height=12, width=24,
                                      command=self.update_letter)
        self.Button1.grid(row=1, column=1)

    def update_letter(self):
        current_value = self.letter.value.get()
        print("letter.value before: " + str(current_value))
        self.letter.value.set(self.letter.value.get() + 1)
        print("letter.value now: " + str(self.letter.value.get()))


# initialize a
a = Letter(0)

b = Button(root, a)
l = Label(root, a)

root.mainloop()

A comment: I found having your own classes named the same as those in tkinter a bit confusing because, while they superficially seem similar, they are actually very different—which could lead to difficult-to-understand programming errors.

Upvotes: 1

acw1668
acw1668

Reputation: 46669

It is because you did not update the label l after you have updated current_letter. The simple solution is to change current_letter to IntVar and update class Label and Button as below:

class MyLabel:
    def __init__(self, master):
        self.a_label = tkinter.Label(root, textvariable=current_letter)
        self.a_label.grid(row=2, column=1)

class MyButton:
    def __init__(self, master):
        self.Button1 = tkinter.Button(master, height = 12, width = 24,
                                      command= self.update_letter)
        self.Button1.grid(row=1, column=1)

    def update_letter(self):
        value = current_letter.get()
        print("current_letter.value before: ", value)
        value += 1
        print("current_letter.value now: ", value)
        current_letter.set(value)

current_letter = tkinter.IntVar(0)

b = MyButton(root)
l = MyLabel(root)

Note that I have removed class Letter as it is not necessary. I also rename class Label and Button to MyLabel and MyButton respectively as they are classes in tkinter.

Upvotes: 1

Aybars
Aybars

Reputation: 385

Welcome to Stackoverflow. First of all, you don't really need to create seperate classes for label and button in your program. You can create them inside of main class as tkinter widgets. Then if you want to pass a variable of an instance of some class, you need to initiliaze it and pass to your update_letter function properly, which you can use lambda. Here is an example code that you can work on:

import tkinter as tk


class UpdateLabel:


  def __init__(self, master):
      self.master = master
      # Create instance of Letter class
      a = Letter(value=0)
      current_letter = a
      self.update_button = tk.Button(master, text='Update', command=lambda:self.update_letter(current_letter))
      self.update_button.grid(row=0, column=0)

      self.label = tk.Label(master, text='No Value')
      self.label.grid(row=1, column=0)

  def update_letter(self, current_letter):
      print("current_letter.value before: " + str(current_letter.value))
      current_letter.value += 1
      print("current_letter.value now: " + str(current_letter.value))
      self.label.configure(text='Value: {}'.format(current_letter.value))

class Letter:
     def __init__(self, value):
         self.value = value


if __name__ == '__main__':
    root = tk.Tk()
    app = UpdateLabel(master=root)
    root.mainloop()

In that link How to change label text, you can find other options for changing a text in tkinter label widget. I hope it helps

Upvotes: 1

Related Questions