Dalam postingan kali ini saya akan membagikan bagaimana cara membuat calculator cantik untuk menghitung sesuatu menggunakan bahasa pemrograman python dengan kodingan di tuliis di aplikasi visual studio code
ini hasil yang sudah berjalannya
tampilannya masih terlihat sederhana, tetapi lumayan lah buat pemula yang lagi belajar. sambil terus belajar kamu bisa memahami baris-baris code yang diberikan agar logika berfikirnya bisa terus terasah.
Pertama-tama kamu harus install dulu visual studio code application bisa di windows maupun di macbook, kemudian save as project "calculator" kemudian tuliskan code panjang seperti berikut,
kamu bisa copy pastekan code ini di visual studio kamu agar tidak perlu di tulis ulang.
import tkinter as tk
from tkinter import ttk
import math
class Calculator(tk.Tk):
def __init__(self):
super().__init__()
self.title("Calculator")
self.resizable(False, False)
# ===== State (otak kalkulator) =====
self.acc = None # nilai yang disimpan sementara (accumulator)
self.pending_op = None # operator yang menunggu: '+', '-', '*', '/'
self.new_entry = True # True = digit berikutnya mulai angka baru
self.last_op = None # untuk perilaku menekan '=' berulang
self.last_operand = None
# Memory
self.memory = 0.0
# ===== UI variables =====
self.expr_var = tk.StringVar(value="")
self.display_var = tk.StringVar(value="0")
self._build_ui()
self._bind_keys()
# ---------- UI ----------
def _build_ui(self):
root = ttk.Frame(self, padding=12)
root.grid(row=0, column=0)
# baris atas (ekspresi kecil)
expr = ttk.Label(root, textvariable=self.expr_var, anchor="e", width=26, font=("Segoe UI", 10))
expr.grid(row=0, column=0, columnspan=4, sticky="ew", pady=(0, 4))
# display besar
disp = ttk.Label(root, textvariable=self.display_var, anchor="e", width=26, font=("Segoe UI", 22))
disp.grid(row=1, column=0, columnspan=4, sticky="ew", pady=(0, 8))
# tombol memory: MC MR M+ M- (MS menyusul di kanan)
self._btn(root, "MC", lambda: self.mem_clear(), row=2, col=0)
self._btn(root, "MR", lambda: self.mem_recall(), row=2, col=1)
self._btn(root, "M+", lambda: self.mem_add(), row=2, col=2)
self._btn(root, "M−", lambda: self.mem_sub(), row=2, col=3)
# baris: % CE C ⌫
self._btn(root, "%", lambda: self.percent(), row=3, col=0)
self._btn(root, "CE", lambda: self.clear_entry(), row=3, col=1)
self._btn(root, "C", lambda: self.clear_all(), row=3, col=2)
self._btn(root, "⌫", lambda: self.backspace(), row=3, col=3)
# baris: 1/x x² √ ÷
self._btn(root, "1/x", lambda: self.unary("inv"), row=4, col=0)
self._btn(root, "x²", lambda: self.unary("sqr"), row=4, col=1)
self._btn(root, "√x", lambda: self.unary("sqrt"), row=4, col=2)
self._btn(root, "÷", lambda: self.op_press("/"), row=4, col=3)
# 7 8 9 ×
self._btn(root, "7", lambda: self.digit("7"), row=5, col=0)
self._btn(root, "8", lambda: self.digit("8"), row=5, col=1)
self._btn(root, "9", lambda: self.digit("9"), row=5, col=2)
self._btn(root, "×", lambda: self.op_press("*"), row=5, col=3)
# 4 5 6 −
self._btn(root, "4", lambda: self.digit("4"), row=6, col=0)
self._btn(root, "5", lambda: self.digit("5"), row=6, col=1)
self._btn(root, "6", lambda: self.digit("6"), row=6, col=2)
self._btn(root, "−", lambda: self.op_press("-"), row=6, col=3)
# 1 2 3 +
self._btn(root, "1", lambda: self.digit("1"), row=7, col=0)
self._btn(root, "2", lambda: self.digit("2"), row=7, col=1)
self._btn(root, "3", lambda: self.digit("3"), row=7, col=2)
self._btn(root, "+", lambda: self.op_press("+"), row=7, col=3)
# +/- 0 . = (besar)
self._btn(root, "±", lambda: self.toggle_sign(), row=8, col=0)
self._btn(root, "0", lambda: self.digit("0"), row=8, col=1)
self._btn(root, ".", lambda: self.dot(), row=8, col=2)
btn_eq = self._btn(root, "=", lambda: self.equals(), row=8, col=3)
btn_eq.configure(style="Accent.TButton")
# style sederhana
style = ttk.Style(self)
try:
style.theme_use("clam")
except:
pass
style.configure("TButton", width=8, padding=8)
style.configure("Accent.TButton", width=8, padding=8)
def _btn(self, parent, text, cmd, row, col):
b = ttk.Button(parent, text=text, command=cmd)
b.grid(row=row, column=col, padx=3, pady=3, sticky="nsew")
return b
def _bind_keys(self):
self.bind("<Return>", lambda e: self.equals())
self.bind("<KP_Enter>", lambda e: self.equals())
self.bind("<BackSpace>", lambda e: self.backspace())
self.bind("<Escape>", lambda e: self.clear_all())
for k in "0123456789":
self.bind(k, lambda e, d=k: self.digit(d))
for k, op in [("+", "+"), ("-", "-"), ("*", "*"), ("/", "/")]:
self.bind(k, lambda e, o=op: self.op_press(o))
self.bind(".", lambda e: self.dot())
# ---------- Helpers ----------
def _get(self) -> float:
s = self.display_var.get().strip()
if s in ("", "-", "."):
return 0.0
return float(s)
def _set(self, value: float):
# format ringkas: hilangkan .0
if math.isfinite(value):
if abs(value - int(value)) < 1e-12:
self.display_var.set(str(int(value)))
else:
self.display_var.set(str(value))
else:
self.display_var.set("Error")
def _compute(self, a: float, b: float, op: str) -> float:
if op == "+": return a + b
if op == "-": return a - b
if op == "*": return a * b
if op == "/":
if b == 0:
raise ZeroDivisionError
return a / b
return b
def _update_expr(self):
if self.acc is None or self.pending_op is None:
self.expr_var.set("")
else:
# contoh: "12 +"
op_map = {"+": "+", "-": "−", "*": "×", "/": "÷"}
self.expr_var.set(f"{self._fmt(self.acc)} {op_map.get(self.pending_op, self.pending_op)}")
def _fmt(self, x: float) -> str:
if abs(x - int(x)) < 1e-12:
return str(int(x))
return str(x)
def _error(self):
self.display_var.set("Error")
self.acc = None
self.pending_op = None
self.new_entry = True
self.last_op = None
self.last_operand = None
self.expr_var.set("")
# ---------- Input angka ----------
def digit(self, d: str):
cur = self.display_var.get()
if self.new_entry or cur == "0" or cur == "Error":
self.display_var.set(d)
self.new_entry = False
else:
self.display_var.set(cur + d)
def dot(self):
cur = self.display_var.get()
if self.new_entry or cur == "Error":
self.display_var.set("0.")
self.new_entry = False
return
if "." not in cur:
self.display_var.set(cur + ".")
def toggle_sign(self):
cur = self.display_var.get()
if cur == "Error":
return
if cur.startswith("-"):
self.display_var.set(cur[1:])
else:
if cur != "0":
self.display_var.set("-" + cur)
# ---------- Operator & equals ----------
def op_press(self, op: str):
if self.display_var.get() == "Error":
return
x = self._get()
if self.acc is None:
self.acc = x
else:
# jika sebelumnya sudah pilih operator dan user sudah input angka baru, hitung dulu
if self.pending_op is not None and not self.new_entry:
try:
self.acc = self._compute(self.acc, x, self.pending_op)
self._set(self.acc)
except Exception:
self._error()
return
self.pending_op = op
self.new_entry = True
self.last_op = None
self.last_operand = None
self._update_expr()
def equals(self):
if self.display_var.get() == "Error":
return
x = self._get()
# Case 1: ada operasi yang menunggu
if self.pending_op is not None and self.acc is not None:
try:
result = self._compute(self.acc, x, self.pending_op)
except Exception:
self._error()
return
# simpan untuk '=' berulang
self.last_op = self.pending_op
self.last_operand = x
self._set(result)
self.acc = result
self.pending_op = None
self.expr_var.set("")
self.new_entry = True
return
# Case 2: '=' berulang (mis. 10 + 2 = = =)
if self.last_op is not None and self.acc is not None and self.last_operand is not None:
try:
result = self._compute(self.acc, self.last_operand, self.last_op)
except Exception:
self._error()
return
self._set(result)
self.acc = result
self.new_entry = True
# ---------- Clear / backspace ----------
def clear_entry(self):
self.display_var.set("0")
self.new_entry = True
def clear_all(self):
self.display_var.set("0")
self.expr_var.set("")
self.acc = None
self.pending_op = None
self.new_entry = True
self.last_op = None
self.last_operand = None
def backspace(self):
cur = self.display_var.get()
if self.new_entry or cur == "Error":
self.display_var.set("0")
self.new_entry = True
return
if len(cur) <= 1 or (len(cur) == 2 and cur.startswith("-")):
self.display_var.set("0")
self.new_entry = True
else:
self.display_var.set(cur[:-1])
# ---------- Unary ops ----------
def unary(self, kind: str):
if self.display_var.get() == "Error":
return
x = self._get()
try:
if kind == "inv":
if x == 0:
raise ZeroDivisionError
y = 1 / x
elif kind == "sqr":
y = x * x
elif kind == "sqrt":
if x < 0:
raise ValueError
y = math.sqrt(x)
else:
return
self._set(y)
self.new_entry = True
except Exception:
self._error()
def percent(self):
# versi sederhana: ubah 50 menjadi 0.5
if self.display_var.get() == "Error":
return
x = self._get()
self._set(x / 100.0)
self.new_entry = True
# ---------- Memory ----------
def mem_clear(self):
self.memory = 0.0
def mem_recall(self):
self._set(self.memory)
self.new_entry = True
def mem_add(self):
if self.display_var.get() == "Error":
return
self.memory += self._get()
self.new_entry = True
def mem_sub(self):
if self.display_var.get() == "Error":
return
self.memory -= self._get()
self.new_entry = True
if __name__ == "__main__":
app = Calculator()
app.mainloop()







0 comments:
Post a Comment