DEV Community

Mate Technologies
Mate Technologies

Posted on

Build an Advanced Screenshot Tool with Python (Tkinter)

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
Enter fullscreen mode Exit fullscreen mode

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 *
Enter fullscreen mode Exit fullscreen mode

And finally the screenshot tools.

from PIL import ImageGrab, Image, ImageTk
import pygetwindow as gw
Enter fullscreen mode Exit fullscreen mode

Step 3 — Application Configuration

We define the application name and version.

APP_NAME = "Screenshot PRO"
APP_VERSION = "2.0.0"
Enter fullscreen mode Exit fullscreen mode

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")
Enter fullscreen mode Exit fullscreen mode

We also apply a modern ttkbootstrap theme.

tb.Style("darkly")
Enter fullscreen mode Exit fullscreen mode

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)
Enter fullscreen mode Exit fullscreen mode

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")
Enter fullscreen mode Exit fullscreen mode

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"
    )
Enter fullscreen mode Exit fullscreen mode

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)
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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))
Enter fullscreen mode Exit fullscreen mode

Subtitle:

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

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)
Enter fullscreen mode Exit fullscreen mode

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"
Enter fullscreen mode Exit fullscreen mode

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"))
Enter fullscreen mode Exit fullscreen mode

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))
Enter fullscreen mode Exit fullscreen mode

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))
Enter fullscreen mode Exit fullscreen mode

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)
Enter fullscreen mode Exit fullscreen mode

The window becomes a transparent overlay.

Users drag to draw a capture box.

    start_x = start_y = 0
    rect = None
Enter fullscreen mode Exit fullscreen mode

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)
Enter fullscreen mode Exit fullscreen mode

Mouse drag:

    def drag(e):
        canvas.coords(rect,start_x,start_y,e.x,e.y)
Enter fullscreen mode Exit fullscreen mode

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))
Enter fullscreen mode Exit fullscreen mode

Bind mouse events:

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

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
Enter fullscreen mode Exit fullscreen mode

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"))
Enter fullscreen mode Exit fullscreen mode

Step 16 — Capture Buttons

We now add the control buttons.

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

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)
Enter fullscreen mode Exit fullscreen mode

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)
Enter fullscreen mode Exit fullscreen mode

Region capture:

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

Clipboard copy:

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

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)
Enter fullscreen mode Exit fullscreen mode

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)
Enter fullscreen mode Exit fullscreen mode

Text log:

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

Scrollbar:

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

log_text.config(yscrollcommand=scroll.set,state="disabled")
Enter fullscreen mode Exit fullscreen mode

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()
Enter fullscreen mode Exit fullscreen mode

Handle progress updates:

            if cmd=="progress":
                progress_var.set(data)
Enter fullscreen mode Exit fullscreen mode

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")
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

Repeat every 100ms:

    except Empty:
        pass

    app.after(100,process_ui_queue)
Enter fullscreen mode Exit fullscreen mode

Step 20 — Start the Application

Finally we start the UI loop.

app.after(100,process_ui_queue)

app.mainloop()
Enter fullscreen mode Exit fullscreen mode

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

Top comments (0)