Monday, December 15, 2025

Cara Membuat Kodingan Python untuk Calculator Cantik

Salam Sehat para pembaca blogger

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()

Share:

0 comments:

Post a Comment

jumlah pengunjung

BTemplates.com

Search This Blog

Powered by Blogger.

Translate

about us

My photo
Tangerang, Kota Tangerang, Indonesia
Mudah beradaptasi dengan lingkungan baru, senang bermain komputer atau laptop.