I created a solution for it, which works.
I use a label that is placed on top of the progressbar and the background of the label updates in sync with the progressbar using relwidth and the same color as the progressbar.
from threading import Thread
from tkinter import *
from tkinter import ttk
import time
#Tkinter window
class GUI(Frame, object):
def __init__(self, progress_frame):
super().__init__(progress_frame)
self.progress_frame = progress_frame
self.progress_frame.geometry('300x100')
self.progress_frame.title('Progressbar')
self.progressbar = ttk.Progressbar(self.progress_frame, orient='horizontal', mode='determinate', length=280)
# place the progressbar
self.progressbar.grid(column=0, row=1, columnspan=2, padx=10, ipady=3)
# initialize label
self.value = StringVar()
self.value.set(self.update_progress_label("0 MB/s"))
self.value_label = Label(self.progress_frame, textvariable=self.value, font='default 10', borderwidth=0)
#set background to grey
self.value_label['bg'] = '#e6e6e6'
self.value_label.grid(column=0, row=1, columnspan=2, padx=10, pady=20)
self.current_value = 0
self.start_download()
def update_progress_label(self, mb_s): #the value you want to show in the label
return f"{self.progressbar['value']}% / {mb_s}"
def start_download(self): #start thread that does calculation
download_thread = Download()
download_thread.start()
self.monitor(download_thread)
def monitor(self, download_thread): # monitor download progress
""" Monitor the download thread """
if download_thread.is_alive():
progress = download_thread.value
# update the label
self.value.set(self.update_progress_label(download_thread.mb_s))
widget_x, widget_width = self.value_label.winfo_x(), self.value_label.winfo_width() # get position and width of text label
progressbar_pixellen = self.progressbar.winfo_width() # get total width of progressbar
# get the current position in pxl of progressbar
calculation_ppixel = progress*progressbar_pixellen/100
# get the overlap with the text label
calculation_ptext = calculation_ppixel-widget_x+self.progressbar.winfo_x()
# ensure that no negative value is set
calculation_text = max(calculation_ptext/widget_width, 0)
if calculation_text>0: # if calculation_text (relwidth) is 0 it will still show a small bar, so don't update the label
# update the label with the new text value and the color of the progressbar
self.pblabel = Label(self.value_label, textvariable=self.value, font='default 10', background='#06b025', borderwidth=0, anchor="w")
# relwidth will only show the given percentage of the text in the color
self.pblabel.place(x=0, y=0, anchor="nw", relwidth=calculation_text)
# update the progressbar progress
self.progressbar['value'] = progress
# update the label
self.value_label.update_idletasks()
# rerun this method in 100ms
self.after(100, lambda: self.monitor(download_thread))
class Download(Thread):
def __init__(self):
super().__init__()
self.picture_file = None
self.value = 0
self.mb_s = 0
def run(self):
""" do some calculation like downloading a file """
for i in range(100):
time.sleep(1)
self.value = i
self.mb_s = "100 MB/s"
if __name__ == '__main__':
progress_frame = Tk()
app = GUI(progress_frame)
app.mainloop()
Example