Python’s tkinter often gets dismissed as “old-school”, but with the right styling and structure, you can build clean, modern desktop apps surprisingly fast.
In this post, we’ll build a simple calculator using:
tkinter & ttk
sv-ttk for modern light/dark themes
A clean, grid-based layout
Minimal but extensible logic
By the end, you’ll have a fully working calculator with Dark Mode support.
🧰 Requirements
Make sure you have Python 3 installed, then install sv-ttk:
pip install sv-ttk
🖥️ App Features
Basic arithmetic (+ - * /)
Responsive button grid
Error handling for invalid expressions
Light / Dark mode toggle
Clean, modern UI styling
📁 Project Structure
This app is contained in a single Python file, making it perfect for beginners or quick desktop utilities.
🧠 Key Concepts Used
- StringVar for Reactive UI
We use tk.StringVar() to automatically update the display whenever the expression changes.
- eval() for Fast Prototyping
For simplicity, the calculator evaluates expressions using eval().
⚠️ This is fine for learning or personal tools, but not recommended for untrusted input.
- sv-ttk Themes
sv-ttk instantly upgrades the look of ttk widgets and provides seamless dark mode support.
🧮 Full Calculator Code
import sys
import os
import tkinter as tk
from tkinter import ttk, messagebox
import sv_ttk
def resource_path(file_name):
"""Get the absolute path to a resource, works for PyInstaller."""
base_path = getattr(sys, "_MEIPASS", os.path.dirname(os.path.abspath(__file__)))
return os.path.join(base_path, file_name)
# =========================
# App Setup
# =========================
root = tk.Tk()
root.title("Simple Calculator")
root.geometry("360x520")
root.resizable(False, False)
sv_ttk.set_theme("light")
# =========================
# Globals
# =========================
expression = tk.StringVar(value="")
dark_mode_var = tk.BooleanVar(value=False)
# =========================
# Helpers
# =========================
def append_value(val):
expression.set(expression.get() + str(val))
def clear_all():
expression.set("")
def calculate():
try:
result = eval(expression.get())
expression.set(str(result))
except Exception:
messagebox.showerror("Error", "Invalid Expression")
expression.set("")
def toggle_theme():
sv_ttk.set_theme("dark" if dark_mode_var.get() else "light")
# =========================
# Styles
# =========================
style = ttk.Style()
style.theme_use("clam")
style.configure(
"Calc.TButton",
font=("Segoe UI", 14, "bold"),
padding=10
)
style.configure(
"Equals.TButton",
font=("Segoe UI", 14, "bold"),
padding=10
)
# =========================
# Display
# =========================
display_frame = ttk.Frame(root, padding=10)
display_frame.pack(fill="x")
display = ttk.Entry(
display_frame,
textvariable=expression,
font=("Consolas", 20),
justify="right"
)
display.pack(fill="x", ipady=10)
# =========================
# Buttons
# =========================
btn_frame = ttk.Frame(root, padding=10)
btn_frame.pack(expand=True, fill="both")
buttons = [
("7", 1, 0), ("8", 1, 1), ("9", 1, 2), ("/", 1, 3),
("4", 2, 0), ("5", 2, 1), ("6", 2, 2), ("*", 2, 3),
("1", 3, 0), ("2", 3, 1), ("3", 3, 2), ("-", 3, 3),
("0", 4, 0), (".", 4, 1), ("C", 4, 2), ("+", 4, 3),
]
for (text, r, c) in buttons:
action = clear_all if text == "C" else lambda t=text: append_value(t)
ttk.Button(
btn_frame,
text=text,
command=action,
style="Calc.TButton"
).grid(row=r, column=c, sticky="nsew", padx=5, pady=5)
# Equals button
ttk.Button(
btn_frame,
text="=",
command=calculate,
style="Equals.TButton"
).grid(row=5, column=0, columnspan=4, sticky="nsew", padx=5, pady=10)
# =========================
# Options
# =========================
options_frame = ttk.Frame(root, padding=10)
options_frame.pack(fill="x")
ttk.Checkbutton(
options_frame,
text="Dark Mode",
variable=dark_mode_var,
command=toggle_theme
).pack(anchor="w")
# =========================
# Grid Configuration
# =========================
for i in range(4):
btn_frame.columnconfigure(i, weight=1)
for i in range(6):
btn_frame.rowconfigure(i, weight=1)
# =========================
# Run App
# =========================
root.mainloop()
🚀 Possible Improvements
If you want to extend this project:
Replace eval() with a safer expression parser
Add keyboard input support
Implement scientific functions (√, %, sin, cos)
Package it as an .exe with PyInstaller
Add history tracking
🎯 Final Thoughts
Tkinter doesn’t have to look outdated. With ttk, modern themes, and clean layout logic, you can build polished desktop tools quickly — especially for internal utilities, learning projects, or lightweight apps.
If you found this useful, feel free to remix it or build something bigger on top of it.
Happy hacking 🧠🐍


Top comments (0)