Progress Bar in Tk (tkinter)

A progress bar is useful to display the status of an operation or task. The ttk.Progressbar widget can indicate the evolution of a certain process (for example, downloading a file from the Internet) or simply represent that an operation is being executed, in those cases in which the remaining time is unknown.

Standard Progress Bar

Let's start with a little code that creates a window with a horizontal progress bar.

import tkinter as tk
from tkinter import ttk
root = tk.Tk()
root.title("Progress Bar in Tk")
progressbar = ttk.Progressbar()
progressbar.place(x=30, y=60, width=200)
root.geometry("300x200")
root.mainloop()
/images/progress-bar-in-tk-tkinter/progressbar-horizontal.png

We can also indicate a vertical orientation via the orient parameter:

import tkinter as tk
from tkinter import ttk
root = tk.Tk()
root.title("Progress Bar in Tk")
progressbar = ttk.Progressbar(orient=tk.VERTICAL)
progressbar.place(x=30, y=30, height=160)
root.geometry("300x200")
root.mainloop()
/images/progress-bar-in-tk-tkinter/progressbar-vertical.png

The default value for orient is tk.HORIZONTAL.

Note that, depending on the chosen orientation, the length of the widget is determined by the width (horizontal) or height (vertical) argument. To set the length regardless of its orientation, the length parameter can be used.

import tkinter as tk
from tkinter import ttk
root = tk.Tk()
root.title("Progress Bar in Tk")
progressbar = ttk.Progressbar(orient=tk.VERTICAL, length=160)
progressbar.place(x=30, y=30)
root.geometry("300x200")
root.mainloop()

Back to the first code, by default the progress bar is set to represent a percentage. That is, it takes values from 0 (totally empty) to 100 (totally full). We set the progress via the step function by indicating a value between the aforementioned range.

# Somewhere in the code.
progressbar.step(50)

Once this method is executed, the progress will be halfway:

/images/progress-bar-in-tk-tkinter/progressbar-50.png

If the argument is omitted, the increment is equal to 1.0 (note that the function can take floating point numbers).

A peculiarity in Tk is that a progress bar cannot be shown "complete". When it reaches its maximum value, the progress returns to 0. For this reason, the following code shows an empty bar:

# The progress goes back to 0 when the bar reaches
# its maximum value.
progressbar.step(100)

Therefore, to display the (almost) complete bar, it will be convenient to use a value close to the maximum (which by default is 100):

# Full progress bar.
progressbar.step(99.9)

The maximum value of a progress bar can be set via the maximum parameter:

progressbar = ttk.Progressbar(maximum=200)

In this case, since the maximum value is 200, a call to progressbar.step(50) will set a quarter of the progress.

The value of a progress bar can also be handled by a variable, such as tk.IntVar, by indicating it in the variable parameter.

progress = tk.IntVar()
progressbar = ttk.Progressbar(variable=progress)

In this case, to set the progress of the progress bar, you must call the set() method of the assigned variable:

# Set the progress to 50.
progress.set(50)

Note that set() sets the value of the progress bar, while step() increases it. Two calls to step(10) set the progress at 20, but two calls to set(10) simply keep it at 10.

Indeterminate Progress Bar

An indeterminate progress bar is useful when we want to tell the user that something is happening, but we don't know exactly how long it will take. When using the indeterminate mode, the progress bar shows a small "load" scrolling back and forth.

import tkinter as tk
from tkinter import ttk
root = tk.Tk()
root.title("Progress Bar in Tk")
progressbar = ttk.Progressbar(mode="indeterminate")
progressbar.place(x=30, y=60, width=200)
# Start moving the indeterminate progress bar.
progressbar.start()
root.geometry("300x200")
root.mainloop()
/images/progress-bar-in-tk-tkinter/progressbar-indeterminate.gif

The mode parameter defaults to "determinate".

We can alter the movement speed by indicating the milliseconds (50 by default):

# Move the load every 10 milliseconds.
progressbar.start(10)

To stop the movement, use the stop() method:

# Stop moving the indeterminate bar.
progressbar.stop()

Examples

Download a file via HTTP and display the progress:

import tkinter as tk
from tkinter import ttk
from threading import Thread
from urllib.request import urlretrieve, urlcleanup
def download():
    url = "https://www.python.org/ftp/python/3.10.6/python-3.10.6-amd64.exe"
    urlretrieve(url, "python-3.10.6-amd64.exe", download_status)
    urlcleanup()
def download_button_clicked():
    # Download the file in a new thread.
    Thread(target=download).start()
def download_status(count, data_size, total_data):
    """
    This function is called by urlretrieve() every time
    a chunk of data is downloaded.
    """
    if count == 0:
        # Set the maximum value for the progress bar.
        progressbar.configure(maximum=total_data)
    else:
        # Increase the progress.
        progressbar.step(data_size)
root = tk.Tk()
root.title("Download File with Progress in Tk")
progressbar = ttk.Progressbar()
progressbar.place(x=30, y=60, width=200)
download_button = ttk.Button(text="Download", command=download_button_clicked)
download_button.place(x=30, y=20)
root.geometry("300x200")
root.mainloop()
/images/progress-bar-in-tk-tkinter/download-file-with-progress.png

Note that this code example lacks thread safety. See Background Tasks with Tk (tkinter).

Comments