DEV Community

Mate Technologies
Mate Technologies

Posted on

Build a Modern Tkinter Calculator with History

In this tutorial, we’ll create a pro-style calculator using Python's Tkinter library. It will feature:

A sleek dark theme

Input via buttons or keyboard

Result display

Calculation history (last 10 calculations)

Let’s dive in step by step.

Step 1: Import Tkinter and Setup

First, we import Tkinter and messagebox for alerts. Then, we define a theme for our app.

import tkinter as tk
from tkinter import messagebox
Enter fullscreen mode Exit fullscreen mode
# =========================
# THEME COLORS
# =========================
APP_BG = "#121212"
PANEL_BG = "#1F1F1F"
BTN_BG = "#2C2C2C"
BTN_HOVER = "#3A3A3A"
BTN_ACTIVE = "#FF6F61"
ACCENT = "#FF6F61"
TEXT_CLR = "#E0E0E0"
SUBTEXT_CLR = "#AAAAAA"
INPUT_BG = "#333333"
INPUT_FG = "#FFFFFF"
Enter fullscreen mode Exit fullscreen mode

Explanation:
We define a set of colors to give our app a modern dark look. Using constants makes it easy to change the theme later.

Step 2: Create the Main App Class

We will wrap the entire calculator in a class to keep our code organized.

class CalculatorApp:
    def __init__(self, root):
        self.root = root
        root.title("MateTools – Pro Calculator")
        root.geometry("1000x500")
        root.configure(bg=APP_BG)
        root.resizable(False, False)
Enter fullscreen mode Exit fullscreen mode

Explanation:

root is the main Tkinter window.

We set the title, size, background, and prevent resizing.

Using a class makes it easier to manage methods and UI components.

Step 3: Build the Left Panel (Actions)

The left panel will contain buttons for clearing input, clearing history, and About.

# LEFT PANEL
left = tk.Frame(root, bg=PANEL_BG, width=420)
left.pack(side="left", fill="y")

# Header
header = tk.Frame(left, bg=PANEL_BG)
header.pack(fill="x", padx=16, pady=(18, 10))
tk.Label(header, text="MateTools", bg=PANEL_BG, fg=ACCENT, font=("Segoe UI", 20, "bold")).pack(side="left")

# Subheader
tk.Label(left, text="Pro Calculator", bg=PANEL_BG, fg=TEXT_CLR, font=("Segoe UI", 14, "bold")).pack(anchor="w", padx=16, pady=(0, 2))
tk.Label(left, text="Perform calculations with history", bg=PANEL_BG, fg=SUBTEXT_CLR, font=("Segoe UI", 10)).pack(anchor="w", padx=16, pady=(0, 16))
Enter fullscreen mode Exit fullscreen mode

Explanation:
We create a vertical left panel with a header and subtext. Tkinter’s Frame allows grouping UI elements together.

Step 4: Add Action Buttons with Hover Effects

We’ll create a helper function to make buttons reusable with hover and click effects.

def make_btn(text, cmd, color=BTN_BG):
    btn = tk.Button(
        left, text=text, command=cmd, bg=color, fg="white",
        font=("Segoe UI", 11, "bold"), relief="flat", height=2, width=20
    )
    btn.bind("<Enter>", lambda e: btn.config(bg=BTN_HOVER))
    btn.bind("<Leave>", lambda e: btn.config(bg=color))
    btn.bind("<ButtonPress-1>", lambda e: btn.config(bg=BTN_ACTIVE))
    btn.bind("<ButtonRelease-1>", lambda e: btn.config(bg=BTN_HOVER))
    return btn

make_btn("Clear Input", self.clear_input, ACCENT).pack(pady=8)
make_btn("Clear History", self.clear_history).pack(pady=8)
make_btn("About", self.show_about).pack(pady=20)
Enter fullscreen mode Exit fullscreen mode

Explanation:

make_btn creates buttons with hover and active states.

We reuse it for multiple buttons to avoid repeating code.

Step 5: Create the Right Panel (Calculator UI)

The right panel contains input, buttons, result, and history.

right = tk.Frame(root, bg=APP_BG)
right.pack(side="right", fill="both", expand=True)

# Result Card
self.result_card = tk.Frame(right, bg=PANEL_BG, bd=2, relief="ridge")
self.result_card.pack(padx=30, pady=20, fill="both", expand=True)

tk.Label(self.result_card, text="Calculator", bg=PANEL_BG, fg=TEXT_CLR, font=("Segoe UI", 18, "bold")).pack(pady=(20, 10))
Enter fullscreen mode Exit fullscreen mode

Explanation:

The right frame expands to fill available space.

result_card is a card-like frame to hold calculator UI components.

Step 6: Add Input Field and Button Grid

We’ll create an entry widget and a grid of buttons for digits and operators.

# Input Entry
self.input_var = tk.StringVar()
self.input_entry = tk.Entry(self.result_card, textvariable=self.input_var, bg=INPUT_BG, fg=INPUT_FG, font=("Segoe UI", 18), relief="flat", justify="right")
self.input_entry.pack(fill="x", pady=(0, 10))
self.input_entry.bind("<Return>", lambda event: self.calculate())
Enter fullscreen mode Exit fullscreen mode
# Buttons
buttons = [
    ('7', '8', '9', '/'),
    ('4', '5', '6', '*'),
    ('1', '2', '3', '-'),
    ('0', '.', '=', '+'),
]

for r, row in enumerate(buttons):
    for c, char in enumerate(row):
        action = self.calculate if char == '=' else lambda ch=char: self.add_to_input(ch)
        tk.Button(self.result_card, text=char, width=5, height=2, command=action).grid(row=r, column=c, padx=5, pady=5)
Enter fullscreen mode Exit fullscreen mode

Explanation:

Entry allows typing expressions.

Grid buttons make input easy with mouse clicks.

= button triggers calculation.

Step 7: Add Result Display and History

We’ll show the current result and last 10 calculations.

# Result label
self.result_label = tk.Label(self.result_card, text="--", bg=PANEL_BG, fg=ACCENT, font=("Segoe UI", 18, "bold"))
self.result_label.pack(anchor="e", padx=10, pady=(0, 5))

# History listbox
self.history_box = tk.Listbox(self.result_card, bg=INPUT_BG, fg=INPUT_FG, font=("Segoe UI", 12), height=10)
self.history_box.pack(fill="both", expand=True, padx=10, pady=(0, 10))
self.history = []
Enter fullscreen mode Exit fullscreen mode

Explanation:

result_label shows the latest calculation result.

Listbox displays the last 10 calculations.

Step 8: Add Core Methods

These methods handle input, calculation, and history management.

def add_to_input(self, char):
    self.input_var.set(self.input_var.get() + char)

def calculate(self):
    expr = self.input_var.get()
    if not expr.strip():
        return
    try:
        result = round(eval(expr), 6)
        self.result_label.config(text=str(result))
        self.history.append(f"{expr} = {result}")
        self.history = self.history[-10:]
        self.update_history()
        self.input_var.set(str(result))
    except Exception as e:
        messagebox.showerror("Error", f"Invalid expression: {e}")

def update_history(self):
    self.history_box.delete(0, tk.END)
    for item in self.history:
        self.history_box.insert(tk.END, item)

def clear_input(self):
    self.input_var.set("")

def clear_history(self):
    self.history = []
    self.update_history()

def show_about(self):
    messagebox.showinfo("About", "MateTools – Pro Calculator\nBuilt by MateTools")
Enter fullscreen mode Exit fullscreen mode

Explanation:

add_to_input appends button presses to the entry.

calculate evaluates the expression safely and updates history.

clear_input and clear_history reset fields.

show_about shows an info dialog.

Step 9: Run the App

Finally, instantiate the class and run the Tkinter main loop.

if __name__ == "__main__":
    root = tk.Tk()
    CalculatorApp(root)
    root.mainloop()
Enter fullscreen mode Exit fullscreen mode

Explanation:

Creates the main window and runs the app.

Everything is neatly organized inside CalculatorApp.

✅ Congrats! You now have a modern, dark-themed calculator with input, buttons, results, and history.

Pro Calculator

Top comments (0)