In this tutorial, we’ll build QuickExtract v2.0.0 — a modern batch archive extractor with:
Drag & Drop support
Pause / Resume
Stop button
Real-time progress
Error logging
Windows EXE build
🚀 Option 1 — Download the Ready-to-Use EXE
If you don’t want to set up Python, download the compiled Windows version:
https://github.com/rogers-cyber/QuickExtract/releases
✔ No Python required
✔ Portable
✔ Double-click to run
💻 Option 2 — Clone the Source Code
git clone https://github.com/rogers-cyber/QuickExtract.git
cd QuickExtract
Install dependencies:
pip install ttkbootstrap patool tkinterdnd2
Then run:
python QuickExtract.py
Step 1 — Import Required Modules
We need:
Tkinter (GUI)
ttkbootstrap (modern theme)
patool (archive extraction)
threading (background tasks)
queue (safe UI updates)
tkinterdnd2 (drag & drop)
import os
import sys
import threading
import time
import traceback
from queue import Queue, Empty
from tkinter import filedialog, messagebox
import ttkbootstrap as tb
import patoolib
import tkinter as tk
from tkinterdnd2 import DND_FILES, TkinterDnD
Step 2 — Application Configuration
Define the app name and version:
APP_NAME = "QuickExtract - Archive Extractor"
APP_VERSION = "2.0.0"
Create the main window with drag-and-drop support:
app = TkinterDnD.Tk()
app.title(f"{APP_NAME} {APP_VERSION}")
app.geometry("1000x600")
tb.Style("darkly")
Step 3 — Utility Functions
These help with:
EXE compatibility
Error logging
About dialog
def resource_path(file_name):
base_path = getattr(sys, "_MEIPASS", os.path.dirname(os.path.abspath(__file__)))
return os.path.join(base_path, file_name)
def log_error():
with open("error.log", "a", encoding="utf-8") as f:
f.write(traceback.format_exc() + "\n")
Step 4 — Add a Menu
menubar = tb.Menu(app)
help_menu = tb.Menu(menubar, tearoff=0)
help_menu.add_command(label="About", command=lambda:
messagebox.showinfo(
"About",
f"{APP_NAME} v{APP_VERSION}\nSupports 70+ formats."
)
)
menubar.add_cascade(label="Help", menu=help_menu)
app.config(menu=menubar)
Step 5 — Threading & Queue Setup
We never update the UI directly from a thread.
Instead, we use a Queue:
stop_flag = False
pause_flag = False
ui_queue = Queue()
Step 6 — Archive Selection Panel
Create a listbox to display selected archives:
archive_list = []
output_path = tb.StringVar()
frame1 = tb.Labelframe(app, text="Archive Selection", padding=10)
frame1.pack(fill="x", padx=10, pady=6)
archive_listbox = tk.Listbox(frame1, height=6)
archive_listbox.pack(fill="x")
Add files:
def add_archives():
files = filedialog.askopenfilenames(title="Select Archives")
for f in files:
if f not in archive_list:
archive_list.append(f)
ui_queue.put(("add", f))
Step 7 — Drag & Drop Support
Enable drop functionality:
archive_listbox.drop_target_register(DND_FILES)
archive_listbox.dnd_bind('<<Drop>>', lambda e: drop(e))
def drop(event):
files = app.tk.splitlist(event.data)
for f in files:
if os.path.isfile(f):
archive_list.append(f)
ui_queue.put(("add", f))
Step 8 — Progress Bar
frame2 = tb.Labelframe(app, text="Progress", padding=8)
frame2.pack(fill="x", padx=10)
progress_var = tb.IntVar()
tb.Progressbar(
frame2,
variable=progress_var,
maximum=100,
length=500
).pack(side="left", padx=10)
status_lbl = tb.Label(frame2, text="Status: Ready")
status_lbl.pack(side="left", padx=10)
Step 9 — Extraction Logic (Background Thread)
This runs in a separate thread to keep the UI responsive.
def extract_archives():
global stop_flag, pause_flag
stop_flag = pause_flag = False
total_files = len(archive_list)
if total_files == 0:
messagebox.showerror("Error", "No archives selected.")
return
for idx, archive in enumerate(archive_list, 1):
if stop_flag:
ui_queue.put(("log", "Stopped by user."))
break
while pause_flag:
time.sleep(0.1)
ui_queue.put(("log", f"Extracting: {archive}"))
try:
patoolib.extract_archive(archive, interactive=False)
ui_queue.put(("log", f"Completed: {archive}"))
except Exception:
log_error()
ui_queue.put(("log", f"Failed: {archive}"))
percent = int((idx / total_files) * 100)
ui_queue.put(("progress", percent))
ui_queue.put(("complete", "Done"))
Step 10 — UI Queue Processor
Safely update UI from the main thread:
def process_ui_queue():
try:
while True:
cmd, data = ui_queue.get_nowait()
if cmd == "add":
archive_listbox.insert("end", data)
elif cmd == "progress":
progress_var.set(data)
elif cmd == "log":
print(data)
elif cmd == "complete":
status_lbl.config(text="Finished")
except Empty:
pass
app.after(100, process_ui_queue)
Start the queue processor:
app.after(100, process_ui_queue)
Step 11 — Run Extraction in Thread
tb.Button(
app,
text="Extract",
command=lambda: threading.Thread(
target=extract_archives,
daemon=True
).start()
).pack(pady=10)
Step 12 — Build Windows EXE
Install PyInstaller:
pip install pyinstaller
Build:
pyinstaller --onefile --windowed --name "QuickExtract" QuickExtract.py
Your EXE will be inside:
dist/QuickExtract.exe
🎯 Final Result
You now have:
✔ Drag & Drop archive extractor
✔ Background threaded extraction
✔ Pause / Stop support
✔ Real-time progress
✔ Windows standalone EXE
📦 Project Links
Clone source:
https://github.com/rogers-cyber/QuickExtract
Download EXE:

Top comments (0)