I'm battling with tkinter's .after() functionality, and I see all the examples, these all work as demo in my environment if applied on a well-known amount of labels
The challenge I have here is that I have an unknown amount of labels generated by a loop.
I need to have these labels regenerated and overwritten every x seconds. The number of labels may change, text and color of the labels will change accordingly, as well.
I think the challenge here is to re-run the whole labels generation function _construct_label_colorise after x seconds, and have it replace previous labels.
Think of it as like these labels would be a list of windows processes, each time it constructs labels - some processes might go down and disappear, and some appear on top. so, every second the number of labels will be different. For this example, I limit the delta to 3-5.labels.
Please advise a way to correctly implement _construct_label_colorise function rerun, after x seconds intervals.
from tkinter import StringVar, Tk, Frame, Label, LabelFrame, mainloop
from platform import system
from random import randint
class Window(Tk):
def __init__(self):
super(Window, self).__init__()
# self.geometry('100x150')
self.build_ui()
def build_ui(self):
mainFrame = Frame(self)
mainFrame.pack()
status_frame = LabelFrame(mainFrame, text='EP status')
status_frame.pack(padx=5,pady=5)
self._construct_label_colorise(status_frame)
self.after(1000,self._update_status(status_frame))
#Note!: The number of LABELs delivered by this function in production changes dynamically, it is an unknown total label quantity at each refresh
def _construct_label_colorise(self,master):
self.label_list=[]
for x in range(0,randint(3,5)):
c = randint(0,1)
fg = "green" if c == 0 else "red"
label = StringVar
label = Label(master, text=f'color {fg}', foreground= fg)
label.pack(padx=5,pady=5)
self.label_list.append (label)
def _update_status(self,master):
for label in self.label_list:
label.destroy()
self.after(1000,self._construct_label_colorise(master))
pass
window = Window()
window.mainloop()
CodePudding user response:
When you use after
, it will only use the callback once.
If you want to keep repeating an action, you have to re-schedule it with after
every time.
CodePudding user response:
Note that self.after(1000, self._update_status(status_frame))
will execute self._update_status(status_frame)
immediately, not 1000ms later. Also you don't need self._update_status()
at all for your case.
...
from random import randint, choice
class Window(Tk):
def __init__(self):
super(Window, self).__init__()
# self.geometry('100x150')
self.build_ui()
def build_ui(self):
mainFrame = Frame(self)
mainFrame.pack()
status_frame = LabelFrame(mainFrame, text='EP status')
status_frame.pack(padx=5,pady=5)
self.label_list = [] # initialize the list here
self._construct_label_colorise(status_frame) # start the after loop
#Note!: The number of LABELs delivered by this function in production changes dynamically, it is an unknown total label quantity at each refresh
def _construct_label_colorise(self,master):
# delete existing labels
for label in self.label_list:
label.destroy()
# clear the list
self.label_list.clear()
# create random number of labels with random foreground color
for x in range(0,randint(3,5)):
fg = choice(["green", "red"])
label = Label(master, text=f'color {fg}', foreground= fg)
label.pack(padx=5,pady=5)
self.label_list.append (label)
# call this function one second later
self.after(1000, self._construct_label_colorise, master)
...