When updating a value in a widget using tkinter there's traces of the old widget's state on screen, and I was wondering if there's any fix to this. I'm assuming tkinter just re-draws whatever it needs to, not updating the old widget/old widget's state. Minimal reproducible example follows.
from tkinter import *
from tkinter.ttk import *
window=Tk()
ttk.Style().configure("Info.TLabel",foreground="white", background="#1e2124",relief="sunken")
def update_label(currvar):
current_var_levels = current_var.get()
var_label=ttk.Label(window,text=f'{current_var_levels}'+'%',style="Info.TLabel")
var_label.grid(row=0,column=1)
current_var=IntVar()
scale_bar = ttk.Scale(window, from_=0, to=100, length=200, variable=current_var, command=update_label)
current_var.set(100)
scale_bar.grid(row=0,column=0)
# Initialize scale's display label. Works without this, but it shows everything from the start
var_label=ttk.Label(window,text=f'{current_var.get()}'+'%',style="Info.TLabel")
var_label.grid(row=0,column=1)
window.mainloop()
I've tried conf_label.grid_forget()
and then re-grid-ing it on the update function, but that didn't work. I've also tried making 2 separate labels (global/local) ones, although I may be thinking too linearly. I think I'm looking for a "screen refresh" but I don't know what that looks like. This also happens without the fore/background colors, or even without a relief altogether; removing the Style config and the style assignment from the label(s) will still leave a small part of %
visible, once part if the current value is a double digit number, and 2 parts if it's a single digit number. A viable botch would be to force length by padding with whitespace, but this is a good learning opportunity. Thanks for reading!
tkinter
doesn't remove old Label
but it puts new Label
above old Label
- so you have two labels in one place.
You could use grid_forget()
or destroy()
to remove old Label
.
But this needs to keep var_label
as global
variable.
And this can make flickering widget. It shows gray background after removing old Label
and before adding new Label
.
def update_label(value):
global var_label # inform function that new label has to be assigned to global variable `var_label`, instead of local `var_label`
current_var_levels = current_var.get()
#current_var_levels = int(float(currvar))
var_label.destroy() # remove old label from screen and from memory
#var_label.grid_forget() # remove old label from screen but not from memory
var_label = ttk.Label(window, text=f'{current_var_levels}%', style="Info.TLabel")
var_label.grid(row=0, column=1)
Or you should create Label
only once and later replace text in existing Label
def update_label(currvar):
current_var_levels = current_var.get()
#current_var_levels = int(float(currvar))
var_label.config(text=f'{current_var_levels}%') # replace text
#var_label['text'] = f'{current_var_levels}%' # replace text
Full working code which I used for tests:
import tkinter as tk # `PEP8: `import *` is not preferred
import tkinter.ttk as ttk # `PEP8: `import *` is not preferred
# --- functions --- # PEP8: all functions before main code
def update_label_version_1(value):
global var_label # inform function that new label has to be assigned to global variable `var_label`, instead of local `var_label`
current_var_levels = current_var.get()
#current_var_levels = int(float(currvar))
var_label.destroy() # remove old label from screen and from memory
#var_label.grid_forget() # remove old label from screen but not from memory
var_label = ttk.Label(window, text=f'{current_var_levels}%', style="Info.TLabel")
var_label.grid(row=0, column=1)
def update_label_version_2(value):
current_var_levels = current_var.get()
#current_var_levels = int(float(value))
var_label.config(text=f'{current_var_levels}%') # replace text
#var_label['text'] = f'{current_var_levels}%' # replace text
# --- main ---
window = tk.Tk()
ttk.Style().configure("Info.TLabel", foreground="white", background="#1e2124", relief="sunken")
current_var = tk.IntVar()
#update_label = update_label_version_1 # test version 1
update_label = update_label_version_2 # test version 2
scale_bar = ttk.Scale(window, from_=0, to=100, length=200, variable=current_var, command=update_label)
current_var.set(100)
scale_bar.grid(row=0,column=0)
# Initialize scale's display label. Works without this, but it shows everything from the start
var_label = ttk.Label(window, text=f'{current_var.get()}%', style="Info.TLabel")
var_label.grid(row=0, column=1)
window.mainloop()