How to create a download progress bar in Tkinter?

When creating applications that download files or perform time-consuming tasks, a progress bar provides visual feedback to users. Tkinter's ttk.Progressbar widget is perfect for this purpose, allowing you to track and display progress in real-time.

Basic Download Progress Bar

Let's create a simple progress bar that simulates a download process ?

import tkinter as tk
from tkinter import ttk
import time

# Create main window
root = tk.Tk()
root.title("Download Progress")
root.geometry("400x200")

def start_download():
    # Reset progress bar
    progress_bar['value'] = 0
    
    # Simulate download with 10 steps
    for i in range(11):
        time.sleep(0.5)  # Simulate download time
        progress_bar['value'] = i * 10
        percentage_label.config(text=f"{i * 10}%")
        root.update_idletasks()  # Update GUI
    
    status_label.config(text="Download Complete!")

# Create progress bar
progress_bar = ttk.Progressbar(root, orient='horizontal', length=300, mode='determinate')
progress_bar.pack(pady=20)

# Create labels
percentage_label = tk.Label(root, text="0%", font=('Arial', 12))
percentage_label.pack(pady=5)

status_label = tk.Label(root, text="Ready to download", font=('Arial', 10))
status_label.pack(pady=5)

# Create download button
download_btn = ttk.Button(root, text="Start Download", command=start_download)
download_btn.pack(pady=10)

root.mainloop()

Enhanced Progress Bar with File Size

Here's a more realistic example that simulates downloading with file size information ?

import tkinter as tk
from tkinter import ttk
import time
import threading

class DownloadProgressBar:
    def __init__(self, root):
        self.root = root
        self.root.title("File Download Progress")
        self.root.geometry("500x250")
        
        # File info
        self.total_size = 1024 * 1024  # 1 MB in bytes
        self.downloaded = 0
        
        self.setup_ui()
    
    def setup_ui(self):
        # Title label
        title_label = tk.Label(self.root, text="Downloading: sample_file.zip", 
                              font=('Arial', 12, 'bold'))
        title_label.pack(pady=10)
        
        # Progress bar
        self.progress_bar = ttk.Progressbar(self.root, orient='horizontal', 
                                           length=400, mode='determinate')
        self.progress_bar.pack(pady=10)
        
        # Progress info frame
        info_frame = tk.Frame(self.root)
        info_frame.pack(pady=5)
        
        self.percentage_label = tk.Label(info_frame, text="0%", font=('Arial', 10))
        self.percentage_label.pack(side=tk.LEFT)
        
        self.size_label = tk.Label(info_frame, text="0 KB / 1024 KB", font=('Arial', 10))
        self.size_label.pack(side=tk.RIGHT)
        
        # Status label
        self.status_label = tk.Label(self.root, text="Ready", font=('Arial', 10))
        self.status_label.pack(pady=5)
        
        # Buttons
        button_frame = tk.Frame(self.root)
        button_frame.pack(pady=10)
        
        self.download_btn = ttk.Button(button_frame, text="Start Download", 
                                      command=self.start_download)
        self.download_btn.pack(side=tk.LEFT, padx=5)
        
        self.cancel_btn = ttk.Button(button_frame, text="Cancel", 
                                    command=self.cancel_download, state='disabled')
        self.cancel_btn.pack(side=tk.LEFT, padx=5)
    
    def start_download(self):
        self.download_btn.config(state='disabled')
        self.cancel_btn.config(state='normal')
        self.downloaded = 0
        self.progress_bar['value'] = 0
        self.status_label.config(text="Downloading...")
        
        # Start download in separate thread
        self.download_thread = threading.Thread(target=self.simulate_download)
        self.download_thread.daemon = True
        self.download_thread.start()
    
    def simulate_download(self):
        chunk_size = 8192  # 8 KB chunks
        
        while self.downloaded < self.total_size:
            time.sleep(0.1)  # Simulate network delay
            self.downloaded += chunk_size
            
            if self.downloaded > self.total_size:
                self.downloaded = self.total_size
            
            # Update progress
            progress = (self.downloaded / self.total_size) * 100
            self.progress_bar['value'] = progress
            
            # Update labels
            downloaded_kb = self.downloaded // 1024
            total_kb = self.total_size // 1024
            self.percentage_label.config(text=f"{progress:.1f}%")
            self.size_label.config(text=f"{downloaded_kb} KB / {total_kb} KB")
            
            self.root.update_idletasks()
        
        # Download complete
        self.status_label.config(text="Download Complete!")
        self.download_btn.config(state='normal')
        self.cancel_btn.config(state='disabled')
    
    def cancel_download(self):
        self.status_label.config(text="Download Cancelled")
        self.download_btn.config(state='normal')
        self.cancel_btn.config(state='disabled')

# Create and run application
root = tk.Tk()
app = DownloadProgressBar(root)
root.mainloop()

Key Components

Component Purpose Key Properties
ttk.Progressbar Visual progress indicator orient, length, mode
update_idletasks() Refresh GUI during loops Prevents UI freezing
threading.Thread Non-blocking operations Keeps UI responsive

Progress Bar Modes

The ttk.Progressbar supports two modes ?

import tkinter as tk
from tkinter import ttk

root = tk.Tk()
root.geometry("300x150")

# Determinate mode - shows specific progress
determinate_bar = ttk.Progressbar(root, length=250, mode='determinate')
determinate_bar.pack(pady=10)
determinate_bar['value'] = 70  # 70% complete

# Indeterminate mode - shows activity without specific progress
indeterminate_bar = ttk.Progressbar(root, length=250, mode='indeterminate')
indeterminate_bar.pack(pady=10)
indeterminate_bar.start(10)  # Animation speed

tk.Label(root, text="Determinate (70%)").pack()
tk.Label(root, text="Indeterminate (Activity)").pack()

root.mainloop()

Conclusion

Use ttk.Progressbar with update_idletasks() for simple progress tracking. For responsive applications, implement downloads in separate threads to prevent UI freezing during long operations.

Updated on: 2026-03-25T18:24:17+05:30

2K+ Views

Kickstart Your Career

Get certified by completing the course

Get Started
Advertisements