I have a window with two different Progressbar
s. I want to add different text information over them (i.e. "88/1524" on the first one and "88/10000" on the second).
I've found a solution for one Progressbar
on this question: Displaying percentage in ttk progressbar
However it uses a style modification workaround to add text on the progress bar, and as I understand it, the style attribute text.Horizontal.TProgressbar
is shared for all progress bars. This means I can't have a different text on each progress bar. When I need to update the text, I don't know how to target one specific progress bar.
Is there any other way to do it, or am I missing something?
Can I instantiate the label to have something like text.Horizontal.TProgressbar1
and text.Horizontal.TProgressbar2
?
Here's my current setup without labels:
And portion of my code:
style = tkinter.ttk.Style(root)
style.layout('text.Horizontal.TProgressbar',
[('Horizontal.Progressbar.trough',
{'children': [('Horizontal.Progressbar.pbar',
{'side': 'left', 'sticky': 'ns'})],
'sticky': 'nswe'}),
('Horizontal.Progressbar.label', {'sticky': ''})])
style.configure('text.Horizontal.TProgressbar', text='0/0')
ProgressBarOfDirectory = tkinter.ttk.Progressbar(ProgressbarFrame,
style='text.Horizontal.TProgressbar',
orient="horizontal",
length=WidthOfElements,
mode="determinate",
maximum=NbStepOfProgressBar,
variable=PourcentageOfDirectoryAnalysisDone)
ProgressBarOfDirectory.pack(side="top")
ProgressBarOfAll = tkinter.ttk.Progressbar(ProgressbarFrame,
style='text.Horizontal.TProgressbar',
orient="horizontal",
length=WidthOfElements,
mode="determinate",
maximum=NbStepOfProgressBar,
variable=PourcentageOfAllAnalysisDone)
Widget styles aren't shared unless the same one it specified for more than one widget (or the same default one gets assigned to more than one because something else wasn't specified).
To take advantage of that here's an updated version of the code to my answer to that other question. In order to ensure the independence of the each Progressbar
instance, it derives a new class from the built-in ttk.Progressbar
which creates a separate style object for each instance created.
Below is the code along with a runnable demo at the end.
import tkinter as tk
import tkinter.ttk as ttk
class MyProgressBar(ttk.Progressbar):
_inst_count = 0 # Number of class instances created.
def __init__(self, *args, **kwargs):
classname = type(self).__name__
assert 'style' not in kwargs, \
f'{classname} initializer does not support providing a ttk "style".'
type(self)._inst_count += 1 # Increment class attribute.
# Create a style with a different name for each instance.
self.style = ttk.Style(root)
self.stylename = f'text.Horizontal.TProgressbar{self._inst_count}'
self.style.layout(self.stylename,
[('Horizontal.Progressbar.trough',
{'children': [('Horizontal.Progressbar.pbar',
{'side': 'left', 'sticky': 'ns'})],
'sticky': 'nswe'}),
('Horizontal.Progressbar.label', {'sticky': ''})])
maximum = kwargs['maximum']
self.style.configure(self.stylename, text=f'0/{maximum}')
kwargs.update(style=self.stylename)
super().__init__(*args, **kwargs)
if __name__ == '__main__':
DELAY1 = 100
DELAY2 = 25
MAX1 = 1524
MAX2 = 10000
def progress_bar_func(delay, progress_bar):
# Start periodic progress-bar update process.
maximum = progress_bar.cget('maximum')
style = progress_bar.style # Progressbar must have a style attribute.
root.after(delay, update_progress_bar, delay, style, progress_bar, 1, maximum)
def update_progress_bar(delay, style, progress_bar, num, maximum):
if num <= maximum:
progress_bar.config(value=num)
style.configure(progress_bar.stylename, text=f'{num}/{maximum}')
num += 1
root.after(delay, update_progress_bar, delay, style, progress_bar, num, maximum)
root = tk.Tk()
root.geometry("300x300")
progress_bar1 = MyProgressBar(root, length=200, maximum=MAX1, value=0)
progress_bar1.pack()
progress_bar2 = MyProgressBar(root, length=200, maximum=MAX2, value=0)
progress_bar2.pack()
def start_progress_bars():
progress_bar_func(DELAY1, progress_bar1)
progress_bar_func(DELAY2, progress_bar2)
progress_button = tk.Button(root, text="Start", command=start_progress_bars)
progress_button.pack()
root.mainloop()
Here's a couple of screenshots of it running: