VOOZH about

URL: https://dev.to/matetechnologie/build-an-advanced-screenshot-tool-with-python-tkinter-29jd

⇱ Build an Advanced Screenshot Tool with Python (Tkinter) - DEV Community


In this tutorial, we'll build a professional desktop screenshot tool using Python.

By the end, you'll have an app that can:

📸 Capture the full screen

🖥 Capture the active window

🎯 Select a custom screen region

🖼 Show a live preview

📋 Copy screenshots to clipboard

🗂 Automatically name and save files

📊 Show a processing log

Source code:

https://github.com/rogers-cyber/python-tiny-tools/tree/main/76-Screenshot%20tool

Final Result

Our application will look like a professional desktop tool with:

Screenshot controls

Preview panel

Processing log

Progress bar

Step 1 — Install Required Libraries

Before starting, install the dependencies:

pip install ttkbootstrap pillow pygetwindow pywin32

These libraries provide:

Library Purpose
tkinter GUI framework
ttkbootstrap Modern UI styling
Pillow Image processing
pygetwindow Access active window
pywin32 Clipboard support
Step 2 — Import Required Modules

Now let's import the modules we need.

import os
import sys
import threading
import time
import traceback
from datetime import datetime
from queue import Queue, Empty

These modules help with:

file management

threading

logging errors

queue communication

Next we import the GUI libraries.

import tkinter as tk
from tkinter import filedialog, messagebox

import ttkbootstrap as tb
from ttkbootstrap.constants import *

And finally the screenshot tools.

from PIL import ImageGrab, Image, ImageTk
import pygetwindow as gw

Step 3 — Application Configuration

We define the application name and version.

APP_NAME = "Screenshot PRO"
APP_VERSION = "2.0.0"

Step 4 — Create the Main Application Window

Now we initialize the Tkinter application.

app = tk.Tk()
app.title(f"{APP_NAME}{APP_VERSION}")
app.geometry("1200x700")

We also apply a modern ttkbootstrap theme.

tb.Style("darkly")

This gives the application a dark professional UI.

Step 5 — Utility Functions
Resource Path

Helps load files when the app is packaged into an executable.

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)

Error Logger

Any unexpected errors are written to error.log.

def log_error():
 with open("error.log", "a", encoding="utf-8") as f:
 f.write(traceback.format_exc() + "\n")

About Window

Displays application information.

def show_about():
 messagebox.showinfo(
 f"About {APP_NAME}",
 f"{APP_NAME} v{APP_VERSION}\n\n"
 "Advanced Screen Capture Tool\n\n"
 "Features:\n"
 "• Full screen capture\n"
 "• Window capture\n"
 "• Smart region selector\n"
 "• Screenshot preview panel\n"
 "• Clipboard copy\n"
 "• Auto file naming\n"
 "• Processing log\n\n"
 "Built with Python + Tkinter + ttkbootstrap\n"
 )

Step 6 — Create the Menu Bar

We add a simple Help → About menu.

menubar = tb.Menu(app)
help_menu = tb.Menu(menubar, tearoff=0)

help_menu.add_command(label="About", command=show_about)

menubar.add_cascade(label="Help", menu=help_menu)

app.config(menu=menubar)

Step 7 — Application State Variables

We create shared variables used throughout the application.

ui_queue = Queue()

output_path = tb.StringVar(value=os.getcwd())
file_prefix = tb.StringVar(value="screenshot")

last_image = None

Explanation:

Variable Purpose
ui_queue communication between threads
output_path folder where screenshots are saved
file_prefix screenshot file naming
last_image latest captured screenshot
Step 8 — Application Title

Let's add a clean application header.

tb.Label(
 app,
 text=APP_NAME,
 font=("Segoe UI", 24, "bold")
).pack(pady=(10, 2))

Subtitle:

tb.Label(
 app,
 text="Professional Screen Capture Tool",
 font=("Segoe UI", 10, "italic"),
 foreground="#9ca3af"
).pack(pady=(0, 10))

Step 9 — Capture Settings Panel

Now we build the settings panel.

frame1 = tb.Labelframe(app, text="Capture Settings", padding=10)
frame1.pack(fill="x", padx=10, pady=6)
File Prefix Input
tb.Label(frame1, text="File Prefix:").pack(side="left")
tb.Entry(frame1, textvariable=file_prefix, width=20).pack(side="left", padx=6)
Output Folder
tb.Label(frame1, text="Output Folder:", width=13).pack(side="left", padx=(20,0))
tb.Entry(frame1, textvariable=output_path, width=40).pack(side="left", padx=6)
Browse Button
def browse_output():
 folder = filedialog.askdirectory()
 if folder:
 output_path.set(folder)

tb.Button(frame1, text="Browse", command=browse_output).pack(side="left", padx=4)

Step 10 — Automatic File Naming

Every screenshot will automatically receive a timestamped name.

def generate_filename():

 ts = datetime.now().strftime("%Y%m%d_%H%M%S")

 return f"{file_prefix.get()}_{ts}.png"

Example output:

screenshot_20260311_194550.png
Step 11 — Saving the Screenshot

Now we create the function that saves the image.

def save_image(img):

 global last_image

 try:

 filename = generate_filename()

 path = os.path.join(output_path.get(), filename)

 img.save(path)

 last_image = img

 ui_queue.put(("preview", img))

 ui_queue.put(("log", f"✔ Saved: {filename}"))

 except:
 log_error()
 ui_queue.put(("log", "❌ Save failed"))

This function:

Generates a filename

Saves the screenshot

Updates the preview panel

Writes to the log

Step 12 — Full Screen Capture

The simplest capture mode.

def capture_fullscreen():

 try:

 img = ImageGrab.grab()

 save_image(img)

 except:
 log_error()

 ui_queue.put(("progress", 100))

ImageGrab.grab() captures the entire screen.

Step 13 — Active Window Capture

This captures only the currently focused window.

def capture_window():

 try:

 win = gw.getActiveWindow()

 if not win:
 ui_queue.put(("log","❌ No active window"))
 return

 bbox = (win.left, win.top, win.right, win.bottom)

 img = ImageGrab.grab(bbox)

 save_image(img)

 except:
 log_error()

 ui_queue.put(("progress",100))

We use pygetwindow to get the window position.

Step 14 — Region Selection Tool

This feature allows users to draw a rectangle to capture a custom area.

def capture_region():

 selector = tk.Toplevel()
 selector.attributes("-fullscreen", True)
 selector.attributes("-alpha", 0.25)
 selector.configure(bg="black")

 canvas = tk.Canvas(selector, cursor="cross")
 canvas.pack(fill="both", expand=True)

The window becomes a transparent overlay.

Users drag to draw a capture box.

 start_x = start_y = 0
 rect = None

Mouse press:

 def press(e):
 nonlocal start_x, start_y, rect
 start_x = e.x
 start_y = e.y
 rect = canvas.create_rectangle(start_x,start_y,start_x,start_y,outline="red",width=2)

Mouse drag:

 def drag(e):
 canvas.coords(rect,start_x,start_y,e.x,e.y)

Mouse release:

 def release(e):

 x1 = min(start_x,e.x)
 y1 = min(start_y,e.y)
 x2 = max(start_x,e.x)
 y2 = max(start_y,e.y)

 selector.destroy()

 try:
 img = ImageGrab.grab(bbox=(x1,y1,x2,y2))
 save_image(img)

 except:
 log_error()

 ui_queue.put(("progress",100))

Bind mouse events:

 canvas.bind("<ButtonPress-1>",press)
 canvas.bind("<B1-Motion>",drag)
 canvas.bind("<ButtonRelease-1>",release)

Step 15 — Copy Screenshot to Clipboard

This feature copies the latest screenshot directly to the Windows clipboard.

def copy_clipboard():

 global last_image

 if not last_image:
 messagebox.showerror("Error","No screenshot yet")
 return

Clipboard conversion:

 try:

 import win32clipboard
 from io import BytesIO

 output = BytesIO()
 last_image.convert("RGB").save(output,"BMP")
 data = output.getvalue()[14:]
 output.close()

 win32clipboard.OpenClipboard()
 win32clipboard.EmptyClipboard()
 win32clipboard.SetClipboardData(win32clipboard.CF_DIB,data)
 win32clipboard.CloseClipboard()

 ui_queue.put(("log","📋 Copied to clipboard"))

 except:
 ui_queue.put(("log","❌ Clipboard copy failed"))

Step 16 — Capture Buttons

We now add the control buttons.

frame_buttons = tb.Frame(app)
frame_buttons.pack(fill="x", padx=10, pady=6)

Full screen button:

tb.Button(
 frame_buttons,
 text="📸 Full Screen",
 bootstyle="success",
 command=lambda: threading.Thread(
 target=capture_fullscreen,
 daemon=True
 ).start()
).pack(side="left",padx=4)

Window capture:

tb.Button(
 frame_buttons,
 text="🖥 Window Capture",
 bootstyle="info",
 command=lambda: threading.Thread(
 target=capture_window,
 daemon=True
 ).start()
).pack(side="left",padx=4)

Region capture:

tb.Button(
 frame_buttons,
 text="🎯 Region Capture",
 bootstyle="warning",
 command=capture_region
).pack(side="left",padx=4)

Clipboard copy:

tb.Button(
 frame_buttons,
 text="📋 Copy Clipboard",
 bootstyle="secondary",
 command=copy_clipboard
).pack(side="left",padx=4)

Step 17 — Preview Panel

We create a panel to display the latest screenshot.

preview_frame = tb.Labelframe(main_frame,text="Preview",padding=8)
preview_frame.pack(side="left",fill="both",expand=True,padx=6)

preview_label = tk.Label(preview_frame)
preview_label.pack(expand=True)

Step 18 — Processing Log

A log panel shows application activity.

log_frame = tb.Labelframe(main_frame,text="Processing Log",padding=8)
log_frame.pack(side="right",fill="both",expand=True,padx=6)

Text log:

log_text = tk.Text(log_frame,height=10)
log_text.pack(side="left",fill="both",expand=True)

Scrollbar:

scroll = tk.Scrollbar(log_frame,command=log_text.yview)
scroll.pack(side="right",fill="y")

log_text.config(yscrollcommand=scroll.set,state="disabled")

Step 19 — UI Queue Processing

Threads send UI updates through a queue.

def process_ui_queue():

 try:

 while True:

 cmd,data = ui_queue.get_nowait()

Handle progress updates:

 if cmd=="progress":
 progress_var.set(data)

Handle log messages:

 elif cmd=="log":

 log_text.config(state="normal")
 log_text.insert("end",data+"\n")
 log_text.see("end")
 log_text.config(state="disabled")

Handle preview images:

 elif cmd=="preview":

 img = data.copy()
 img.thumbnail((550,400))

 tk_img = ImageTk.PhotoImage(img)

 preview_label.config(image=tk_img)
 preview_label.image = tk_img

Repeat every 100ms:

 except Empty:
 pass

 app.after(100,process_ui_queue)

Step 20 — Start the Application

Finally we start the UI loop.

app.after(100,process_ui_queue)

app.mainloop()

Conclusion

You just built a professional screenshot application in Python.

Key features include:

📸 Full screen capture

🖥 Active window capture

🎯 Region selector

🖼 Live preview panel

📋 Clipboard support

📊 Processing log

Complete source code:

https://github.com/rogers-cyber/python-tiny-tools/tree/main/76-Screenshot%20tool

👁