-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcalculator.py
More file actions
113 lines (93 loc) · 3.67 KB
/
calculator.py
File metadata and controls
113 lines (93 loc) · 3.67 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
import tkinter as tk
from tkinter import ttk
class Calculator(tk.Tk):
def __init__(self):
super().__init__()
self.title("Calculator")
self.resizable(False, False)
self.expr = ""
self.result_var = tk.StringVar(value="0")
self._build_ui()
self._bind_keys()
def _build_ui(self):
# Display
display = ttk.Entry(
self,
textvariable=self.result_var,
font=("Segoe UI", 18),
justify="right",
state="readonly",
width=18
)
display.grid(row=0, column=0, columnspan=4, padx=10, pady=(10, 6), ipady=10)
# Buttons layout
buttons = [
("C", 1, 0), ("⌫", 1, 1), ("(", 1, 2), (")", 1, 3),
("7", 2, 0), ("8", 2, 1), ("9", 2, 2), ("/", 2, 3),
("4", 3, 0), ("5", 3, 1), ("6", 3, 2), ("*", 3, 3),
("1", 4, 0), ("2", 4, 1), ("3", 4, 2), ("-", 4, 3),
("0", 5, 0), (".", 5, 1), ("=", 5, 2), ("+", 5, 3),
]
# Style
style = ttk.Style(self)
style.configure("Calc.TButton", font=("Segoe UI", 14), padding=10)
for (text, r, c) in buttons:
btn = ttk.Button(self, text=text, style="Calc.TButton",
command=lambda t=text: self.on_press(t))
btn.grid(row=r, column=c, padx=6, pady=6, sticky="nsew")
# Make grid cells consistent size
for i in range(4):
self.grid_columnconfigure(i, minsize=70)
for i in range(1, 6):
self.grid_rowconfigure(i, minsize=60)
# Small hint label
hint = ttk.Label(self, text="Keyboard: Enter/=, Esc=C, Backspace=⌫", font=("Segoe UI", 9))
hint.grid(row=6, column=0, columnspan=4, pady=(0, 10))
def _bind_keys(self):
self.bind("<Return>", lambda e: self.on_press("="))
self.bind("<KP_Enter>", lambda e: self.on_press("="))
self.bind("<Escape>", lambda e: self.on_press("C"))
self.bind("<BackSpace>", lambda e: self.on_press("⌫"))
allowed = "0123456789.+-*/()"
for ch in allowed:
self.bind(ch, lambda e, c=ch: self.on_press(c))
def on_press(self, key):
if key == "C":
self.expr = ""
self.result_var.set("0")
return
if key == "⌫":
self.expr = self.expr[:-1]
self.result_var.set(self.expr if self.expr else "0")
return
if key == "=":
self._evaluate()
return
# Prevent starting with multiple operators (simple guard)
if key in "+*/" and (not self.expr or self.expr[-1] in "+-*/.("):
return
# Append character
self.expr += key
self.result_var.set(self.expr)
def _evaluate(self):
if not self.expr.strip():
self.result_var.set("0")
return
try:
# Safer eval: allow only numbers and operators
safe = "".join(ch for ch in self.expr if ch in "0123456789.+-*/() ")
if safe != self.expr:
raise ValueError("Invalid characters")
# Evaluate
value = eval(safe, {"__builtins__": {}})
# Clean display (avoid 5.0 if it's an int)
if isinstance(value, float) and value.is_integer():
value = int(value)
self.expr = str(value)
self.result_var.set(self.expr)
except Exception:
self.expr = ""
self.result_var.set("Error")
if __name__ == "__main__":
app = Calculator()
app.mainloop()