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
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
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"
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
πͺ 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")
Try loading an icon (fails silently if missing):
try:
app.iconbitmap(str(resource_path("logo.ico")))
except:
pass
π 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")
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)
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()
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
Now filter filenames:
matches = [
f for f in indexed_files
if query in os.path.basename(f).lower()
]
Display up to 500 results:
for m in matches[:500]:
results_list.insert(tk.END, m)
status_text.set(f"{len(matches)} result(s)")
π 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])
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))
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}"
)
π§© Step 10 β Build the UI Layout
Title
tb.Label(app, text=APP_NAME, font=("Segoe UI", 18, "bold")).pack(pady=(10,2))
Subtitle:
tb.Label(
app,
text="Instant local file search",
font=("Segoe UI",10,"italic"),
foreground="#9ca3af"
).pack(pady=(0,10))
Main Container
main_frame = tb.Frame(app)
main_frame.pack(fill="both", expand=True, padx=10, pady=10)
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)
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)
Control Panel
Folder display:
tb.Label(right, text="Indexed Folder:").pack(anchor="w")
tb.Entry(right, textvariable=current_folder).pack(fill="x", pady=3)
Buttons:
tb.Button(right, text="Select Folder", bootstyle="primary",
command=select_folder).pack(fill="x", pady=5)
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)
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)
Status bar:
tb.Label(right, textvariable=status_text).pack(pady=10)
βΆοΈ Step 11 β Run the App
Finally:
app.mainloop()
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)