Instead of using configure to repeatedly change the text within our label, wouldn't it be better if we could assign a variable to it and just change this variable? The good news is you can! The bad news? Regular Python variables aren't perfectly compatible with Tkinter widgets. Shall we take a look?
Using variables
Our first try
Let's give it a try the regular way. Open up your previous code and change it to look like this:
class Window(tk.Tk):
def __init__(self):
super().__init__()
self.title("Hello Tkinter")
self.label_text = "Choose One"
self.label = tk.Label(self, text=self.label_text)
self.label.pack(fill=tk.BOTH, expand=1, padx=100, pady=30)
hello_button = tk.Button(self, text="Say Hello",
command=self.say_hello)
hello_button.pack(side=tk.LEFT, padx=(20, 0), pady=(0, 20))
goodbye_button = tk.Button(self, text="Say Goodbye",
command=self.say_goodbye)
goodbye_button.pack(side=tk.RIGHT, padx=(0, 20), pady=(0, 20))
def say_hello(self):
self.label_text = "Hello World"
def say_goodbye(self):
self.label_text="Goodbye! \n (Closing in 2 seconds)"
self.after(2000, self.destroy)
if __name__ == "__main__":
window = Window()
window.mainloop()
Give this code a whirl and click on your Say Hello button. Nothing happens. Now try your Say Goodbye button. The label will not update, but the window will still close after 2 seconds. This goes to show that the code written is not invalid, but will not behave as we may expect it to.
Creating Tkinter-compatible variables
So, how would we go about using a variable to update this label? Tkinter comes with four built-in variable objects for us to handle different data types:
- StringVar: This holds characters like a Python string.
- IntVar: This holds an integer value.
- DoubleVar: This holds a double value (a number with a decimal place).
- BooleanVar: This holds a Boolean to act like a flag.
To create a variable, just instantiate it like any other class. These do not require any arguments. For example:
label_text = tk.StringVar()
Using and updating
Since these variables are objects, we cannot assign to them a statement like label_text = "Hello World!". Instead, each variable exposes a get and set method. Let's have a play with these in the interactive shell:
>>> from tkinter import *
>>> win = Tk()
>>> sv = StringVar()
>>> sv
<tkinter.StringVar object at 0x05F82D50>
>>> sv.get()
''
>>> sv.set("Hello World!")
>>> sv.get()
'Hello World!'
>>> sv.set(sv.get() + " How's it going?")
>>> sv.get()
"Hello World! How's it going?"
These variables are passed to widgets inside their keyword arguments upon creation (or at a later stage, using configure). The keyword arguments expecting these special variables will usually end in var. In the case of a label, the argument is textvar.
Fixing our application
Let's get our Hello World application working as intended again using our new knowledge of Tkinter variables. After setting the title, change the label_text property as follows:
self.label_text = tk.StringVar()
self.label_text.set("Choose One")
Now, alter our other two methods like so:
def say_hello(self):
self.label_text.set("Hello World")
def say_goodbye(self):
self.label_text.set("Goodbye! \n (Closing in 2 seconds)")
self.after(2000, self.destroy)
Once again, run the application and click both buttons. Everything should now be all working as before.
Great! We now know how to take advantage of Tkinter's special variables, and it's super easy.