DEV Community

Mate Technologies
Mate Technologies

Posted on

πŸ—‚οΈ Build a Desktop File Search Engine in Python (Tkinter + ttkbootstrap)

Ever wanted a lightweight desktop search tool like Spotlight or Everything β€” but written in pure Python?

In this tutorial, we’ll build a local desktop file search engine that:

βœ… Indexes folders
βœ… Searches filenames instantly
βœ… Opens files on double-click
βœ… Works fully offline
βœ… Uses a modern UI with ttkbootstrap

By the end, you’ll have your own desktop search app.

πŸ“¦ Requirements

Install the only external dependency:

pip install ttkbootstrap
Enter fullscreen mode Exit fullscreen mode

Everything else is included with Python.

πŸ“ Project Reference

Full source code:

πŸ‘‰ https://github.com/rogers-cyber/python-tiny-tools/tree/main/116_Desktop_Search_Engine

🧱 Step 1 β€” Imports

Start by importing the libraries we need.

import sys
import os
from pathlib import Path
import tkinter as tk
from tkinter import filedialog, messagebox
import ttkbootstrap as tb
import subprocess
Enter fullscreen mode Exit fullscreen mode

What each one does

tkinter β†’ GUI framework

ttkbootstrap β†’ modern themes for Tkinter

os β†’ file walking

subprocess β†’ open files cross-platform

filedialog β†’ folder picker

messagebox β†’ popup dialogs

βš™οΈ Step 2 β€” App Configuration

Define some metadata for your application.

APP_NAME = "Mate Desktop Search"
APP_VERSION = "1.0.0"
APP_AUTHOR = "Mate Technologies"
APP_WEBSITE = "https://matetools.gumroad.com"
Enter fullscreen mode Exit fullscreen mode

These values are later shown in the UI.

Optional: Resource Helper

If you ever package your app (PyInstaller), this helps locate files like icons:

def resource_path(name):
    base = getattr(sys, "_MEIPASS", Path(__file__).parent)
    return Path(base) / name
Enter fullscreen mode Exit fullscreen mode

πŸͺŸ Step 3 β€” Create the Main Window

Initialize Tkinter and apply a ttkbootstrap theme.

app = tk.Tk()
style_obj = tb.Style(theme="superhero")

app.title(f"{APP_NAME} {APP_VERSION}")
app.geometry("1000x600")
Enter fullscreen mode Exit fullscreen mode

Try loading an icon (fails silently if missing):

try:
    app.iconbitmap(str(resource_path("logo.ico")))
except:
    pass
Enter fullscreen mode Exit fullscreen mode

πŸ“Š Step 4 β€” Application State Variables

These hold shared app data.

indexed_files = []

current_folder = tk.StringVar(master=app, value="")
search_query = tk.StringVar(master=app, value="")
status_text = tk.StringVar(master=app, value="Idle")
Enter fullscreen mode Exit fullscreen mode

Purpose

indexed_files β†’ every discovered file

current_folder β†’ selected directory

search_query β†’ live search text

status_text β†’ bottom status label

πŸ“‚ Step 5 β€” Folder Selection

Let users choose a folder:

def select_folder():
    folder = filedialog.askdirectory()
    if folder:
        current_folder.set(folder)
        index_folder(folder)
Enter fullscreen mode Exit fullscreen mode

Once selected, we immediately index it.

πŸ—ƒοΈ Step 6 β€” Indexing Files

Walk through every subfolder and collect file paths.

def index_folder(folder):
    indexed_files.clear()

    for root, dirs, files in os.walk(folder):
        for f in files:
            indexed_files.append(os.path.join(root, f))

    status_text.set(f"Indexed {len(indexed_files)} files")
    update_results()
Enter fullscreen mode Exit fullscreen mode

This uses os.walk() to recursively scan everything.

πŸ” Step 7 β€” Searching

Every key press triggers this function.

def update_results(*args):
    query = search_query.get().lower()

    results_list.delete(0, tk.END)

    if not query:
        return
Enter fullscreen mode Exit fullscreen mode

Now filter filenames:


    matches = [
        f for f in indexed_files
        if query in os.path.basename(f).lower()
    ]
Enter fullscreen mode Exit fullscreen mode

Display up to 500 results:

    for m in matches[:500]:
        results_list.insert(tk.END, m)

    status_text.set(f"{len(matches)} result(s)")
Enter fullscreen mode Exit fullscreen mode

πŸ“‚ Step 8 β€” Opening Files

Double-clicking or pressing β€œOpen Selected” runs this:

def open_selected(event=None):
    sel = results_list.curselection()
    if not sel:
        return

    path = results_list.get(sel[0])
Enter fullscreen mode Exit fullscreen mode

Platform-specific file opening:

    try:
        if sys.platform.startswith("win"):
            os.startfile(path)
        elif sys.platform.startswith("darwin"):
            subprocess.call(["open", path])
        else:
            subprocess.call(["xdg-open", path])
    except Exception as e:
        messagebox.showerror("Error", str(e))
Enter fullscreen mode Exit fullscreen mode

This works on Windows, macOS, and Linux.

ℹ️ Step 9 β€” About Dialog

A simple info popup:

def show_about():
    messagebox.showinfo(
        f"About {APP_NAME}",
        f"{APP_NAME} v{APP_VERSION}\n\n"
        "A fast lightweight desktop file search engine.\n\n"
        "Features:\n"
        "β€’ Folder indexing\n"
        "β€’ Instant filename search\n"
        "β€’ Double-click to open files\n"
        "β€’ Works fully offline\n"
        "β€’ Modern ttkbootstrap UI\n\n"
        "Use Cases:\n"
        "β€’ Find documents quickly\n"
        "β€’ Locate media files\n"
        "β€’ Search project folders\n\n"
        f"{APP_AUTHOR}\n{APP_WEBSITE}"
    )
Enter fullscreen mode Exit fullscreen mode

🧩 Step 10 β€” Build the UI Layout
Title

tb.Label(app, text=APP_NAME, font=("Segoe UI", 18, "bold")).pack(pady=(10,2))
Enter fullscreen mode Exit fullscreen mode

Subtitle:

tb.Label(
    app,
    text="Instant local file search",
    font=("Segoe UI",10,"italic"),
    foreground="#9ca3af"
).pack(pady=(0,10))
Enter fullscreen mode Exit fullscreen mode

Main Container

main_frame = tb.Frame(app)
main_frame.pack(fill="both", expand=True, padx=10, pady=10)
Enter fullscreen mode Exit fullscreen mode

Split into left and right panels:

left = tb.Frame(main_frame)
left.pack(side="left", fill="both", expand=True)

right = tb.Frame(main_frame, width=260)
right.pack(side="right", fill="y", padx=5)
Enter fullscreen mode Exit fullscreen mode

Results List

results_list = tk.Listbox(left, bg="#222", fg="white")
results_list.pack(fill="both", expand=True)

results_list.bind("<Double-Button-1>", open_selected)
Enter fullscreen mode Exit fullscreen mode

Control Panel

Folder display:

tb.Label(right, text="Indexed Folder:").pack(anchor="w")
tb.Entry(right, textvariable=current_folder).pack(fill="x", pady=3)
Enter fullscreen mode Exit fullscreen mode

Buttons:

tb.Button(right, text="Select Folder", bootstyle="primary",
          command=select_folder).pack(fill="x", pady=5)
Enter fullscreen mode Exit fullscreen mode

Search field:

tb.Label(right, text="Search:").pack(anchor="w")

search_entry = tb.Entry(right, textvariable=search_query)
search_entry.pack(fill="x", pady=3)
search_entry.bind("<KeyRelease>", update_results)
Enter fullscreen mode Exit fullscreen mode

More actions:

tb.Button(right, text="Open Selected", bootstyle="success",
          command=open_selected).pack(fill="x", pady=5)

tb.Button(right, text="About", bootstyle="secondary",
          command=show_about).pack(fill="x", pady=5)
Enter fullscreen mode Exit fullscreen mode

Status bar:

tb.Label(right, textvariable=status_text).pack(pady=10)
Enter fullscreen mode Exit fullscreen mode

▢️ Step 11 β€” Run the App

Finally:

app.mainloop()
Enter fullscreen mode Exit fullscreen mode

Your desktop search engine is alive.

πŸš€ Ideas for Extensions

Try adding:

Content search (not just filenames)

File type filters

Recent searches

SQLite indexing

Tray icon

Keyboard shortcuts

Packaging with PyInstaller

Top comments (0)