Python is more famous for console scripts,data science apps,web development apps,event driven,multithreaded apps – but even GUI development can be done in Python (Almost everything can be done in Python)
This chapter builds a clean-looking Scientific Calculator using Tkinter. Tkinter is one of the most used GUI (Graphical User Interface) library of Python as its open source and can be customized (upto a point)
To create a scientific calculator as outlined in the sources, the development approach focuses on building a Python-based graphical user interface (GUI) that leverages a safe evaluation mechanism to process mathematical expressions.
Libraries Used
The application relies on two primary built-in Python libraries:
Approach Summary
The construction of the calculator is divided into logic-based evaluation and UI management:
Without waiting much,we’ll get to the code
import tkinter as tk
import math
# --------- Safe evaluation helpers ----------
ALLOWED = {
"pi": math.pi,
"e": math.e,
"sin": math.sin,
"cos": math.cos,
"tan": math.tan,
"asin": math.asin,
"acos": math.acos,
"atan": math.atan,
"sqrt": math.sqrt,
"log": math.log10,
"ln": math.log,
"abs": abs,
"round": round,
"pow": pow,
}
def safe_eval(expr: str):
expr = expr.replace("×", "*").replace("÷", "/").replace("^", "**")
return eval(expr, {"__builtins__": {}}, ALLOWED)
# --------- UI App ----------
class SciCalc(tk.Tk):
def __init__(self):
super().__init__()
self.title("Scientific Calculator")
self.geometry("420x520")
self.minsize(420, 520)
self.configure(padx=12, pady=12)
for c in range(6):
self.grid_columnconfigure(c, weight=1, uniform="col")
for r in range(8):
self.grid_rowconfigure(r, weight=1)
display_frame = tk.Frame(self, bd=0)
display_frame.grid(row=0, column=0, columnspan=6, sticky="nsew", pady=(0, 10))
display_frame.grid_columnconfigure(0, weight=1)
self.display = tk.Entry(
display_frame,
font=("Segoe UI", 22),
justify="right",
bd=0,
highlightthickness=2,
highlightbackground="#d0d0d0",
highlightcolor="#8aaae5",
relief="flat",
)
self.display.grid(row=0, column=0, sticky="nsew", ipady=14, padx=2)
self.display.insert(0, "0")
self.mode = tk.Label(self, text="SCI", font=("Segoe UI", 10))
self.mode.grid(row=1, column=0, columnspan=6, sticky="w", pady=(0, 6))
btns = [
("sin", "func"), ("cos", "func"), ("tan", "func"), ("ln", "func"), ("log", "func"), ("⌫", "back"),
("(", "ins"), (")", "ins"), ("π", "pi"), ("e", "e"), ("^", "ins"), ("CE", "ce"),
("7", "ins"), ("8", "ins"), ("9", "ins"), ("÷", "ins"), ("√", "sqrt"), ("C", "clear"),
("4", "ins"), ("5", "ins"), ("6", "ins"), ("×", "ins"), ("x²", "sq"), ("%", "percent"),
("1", "ins"), ("2", "ins"), ("3", "ins"), ("-", "ins"), ("xʸ", "pow"), ("abs", "func"),
("0", "ins"), (".", "ins"), ("±", "neg"), ("+", "ins"), ("=", "eq"), ("", "noop"),
]
self.btn_font = ("Segoe UI", 12)
self.btn_font_big = ("Segoe UI", 12, "bold")
r = 2
idx = 0
for rr in range(6):
for cc in range(6):
text, kind = btns[idx]
idx += 1
if kind == "noop":
continue
is_eq = (text == "=")
is_op = text in {"+", "-", "×", "÷", "^"}
is_ctrl = text in {"C", "CE", "⌫"}
btn = tk.Button(
self,
text=text,
font=self.btn_font_big if (is_eq or is_ctrl) else self.btn_font,
bd=0,
relief="flat",
cursor="hand2",
padx=6,
pady=10,
command=lambda t=text, k=kind: self.on_press(t, k),
)
if is_eq:
btn.configure(bg="#e6eefc", activebackground="#d7e5ff")
elif is_ctrl:
btn.configure(bg="#f3f3f3", activebackground="#e7e7e7")
elif is_op:
btn.configure(bg="#f8f8f8", activebackground="#efefef")
elif kind in {"func", "sqrt", "sq", "pow"}:
btn.configure(bg="#fbfbfb", activebackground="#f0f0f0")
else:
btn.configure(bg="#ffffff", activebackground="#f4f4f4")
btn.grid(row=r + rr, column=cc, sticky="nsew", padx=5, pady=5)
self.bind("", lambda e: self.equals())
self.bind("", lambda e: self.backspace())
self.bind("", lambda e: self.clear_all())
for ch in "0123456789.+-*/()":
self.bind(ch, self.key_insert)
def get_text(self):
return self.display.get()
def set_text(self, s: str):
self.display.delete(0, tk.END)
self.display.insert(0, s)
def insert(self, s: str):
cur = self.get_text()
if cur == "0" and s not in {".", ")", "(", "+", "-", "×", "÷", "^"}:
self.set_text(s)
else:
self.display.insert(tk.END, s)
def on_press(self, text, kind):
if kind == "ins":
self.insert(text)
elif kind == "func":
self.insert(f"{text}(")
elif kind == "pi":
self.insert("pi")
elif kind == "e":
self.insert("e")
elif kind == "sqrt":
self.insert("sqrt(")
elif kind == "sq":
self.insert("^2")
elif kind == "pow":
self.insert("^")
elif kind == "percent":
self.percent()
elif kind == "neg":
self.toggle_sign()
elif kind == "back":
self.backspace()
elif kind == "clear":
self.clear_all()
elif kind == "ce":
self.clear_entry()
elif kind == "eq":
self.equals()
def key_insert(self, event):
ch = event.char
if ch == "*":
self.insert("×")
elif ch == "/":
self.insert("÷")
else:
self.insert(ch)
def clear_all(self):
self.set_text("0")
def clear_entry(self):
self.set_text("0")
def backspace(self):
cur = self.get_text()
if len(cur) <= 1:
self.set_text("0")
else:
self.set_text(cur[:-1])
def toggle_sign(self):
cur = self.get_text().strip()
if cur == "0":
return
if cur.startswith("-(") and cur.endswith(")"):
self.set_text(cur[2:-1])
elif cur.startswith("-"):
self.set_text(cur[1:])
else:
self.set_text("-" + cur)
def percent(self):
try:
val = safe_eval(self.get_text())
self.set_text(str(val / 100))
except Exception:
self.set_text("Error")
def equals(self):
try:
result = safe_eval(self.get_text())
if isinstance(result, float):
result = round(result, 12)
self.set_text(str(result))
except Exception:
self.set_text("Error")
if __name__ == "__main__":
app = SciCalc()
app.mainloop()