Membangun Kalkulator Sederhana dengan PyQt5: Panduan Lengkap untuk Pemula


**Pendahuluan**  

Membuat aplikasi kalkulator adalah cara sempurna untuk mempelajari konsep dasar pengembangan GUI. Artikel ini akan memandu Anda membuat kalkulator fungsional menggunakan PyQt5 dengan fitur dasar aritmatika, manajemen layout, dan event handling. Kode ini menggunakan QGridLayout untuk tata letak rapi dan menerapkan logika operasi matematika dasar.


---


### **Struktur Proyek**  

1. **`main.py`**: File utama untuk menjalankan aplikasi  

2. **`MainForm.py`**: Implementasi logika kalkulator dan GUI  


---


### **File main.py**  

```python

#!/usr/bin/python3


import sys

from PyQt5.QtWidgets import QApplication

from MainForm import MainForm


if __name__ == '__main__':

    app = QApplication(sys.argv)

    calculator = MainForm()

    calculator.show()

    app.exec_()

```


**Penjelasan:**  

- Inisialisasi aplikasi Qt  

- Membuat instance dari kelas MainForm  

- Menjalankan event loop  


---


### **File MainForm.py**  

#### **1. Inisialisasi Komponen GUI**  

```python

from PyQt5.QtWidgets import (QWidget, QGridLayout, QLineEdit, QPushButton)

from PyQt5.QtCore import Qt

from PyQt5.QtGui import QFont


class MainForm(QWidget):

    def __init__(self):

        super().__init__()

        self.setupUI()

        

    def setupUI(self):

        # Konfigurasi window

        self.setGeometry(300, 300, 250, 250)

        self.setWindowTitle('Kalkulator')

        

        # Text display

        self.lineEdit = QLineEdit()

        self.lineEdit.setAlignment(Qt.AlignRight)

        self.lineEdit.setFont(QFont('SansSerif', 14))

        self.lineEdit.setDisabled(True)

```


**Fitur Display:**  

- Alignment teks ke kanan  

- Font SansSerif ukuran 14px  

- Mode read-only  


#### **2. Tata Letak dengan QGridLayout**  

```python

        # Button creation

        buttons = [

            ('7', 1, 0), ('8', 1, 1), ('9', 1, 2), ('CLR', 1, 3),

            ('4', 2, 0), ('5', 2, 1), ('6', 2, 2), ('x', 2, 3),

            ('1', 3, 0), ('2', 3, 1), ('3', 3, 2), ('/', 3, 3),

            ('0', 4, 0), ('.', 4, 1), ('-', 4, 2), ('+', 4, 3),

            ('%', 5, 0), ('=', 5, 1, 1, 3)  # Span 3 kolom untuk tombol '='

        ]


        layout = QGridLayout()

        layout.addWidget(self.lineEdit, 0, 0, 1, 4)  # Span 4 kolom

        

        # Add buttons to layout

        for btn in buttons:

            button = QPushButton(btn[0])

            if len(btn) == 3:

                layout.addWidget(button, btn[1], btn[2])

            else:

                layout.addWidget(button, btn[1], btn[2], btn[3], btn[4])

```


**Struktur Grid:**  

```

[         Display         ]

[7][8][9][CLR]

[4][5][6][ x ]

[1][2][3][ / ]

[0][.][-][ + ]

[%][    =     ]

```


---


#### **3. Logika dan Event Handling**  

```python

        # Koneksi sinyal-sinyal tombol

        digits = [str(i) for i in range(10)]

        for digit in digits:

            self.findChild(QPushButton, f'_{digit}Button').clicked.connect(

                lambda _, d=digit: self.writeDigit(d))

            

        operators = {'plusButton': '+', 'minusButton': '-', 

                    'mulButton': '*', 'divButton': '/'}

        for btn, op in operators.items():

            self.findChild(QPushButton, btn).clicked.connect(

                lambda _, o=op: self.writeOperator(o))

            

        self.dotButton.clicked.connect(self.writePoint)

        self.clearButton.clicked.connect(self.lineEdit.clear)

        self.calculateButton.clicked.connect(self.calculate)

        self.percentageButton.clicked.connect(self.percentage)

```


**Mekanisme Input:**  

- Validasi input ganda operator  

- Penanganan titik desimal  

- Pencegahan input tidak valid  


```python

    def writeDigit(self, digit):

        current = self.lineEdit.text()

        self.lineEdit.setText(current + str(digit))

    

    def writeOperator(self, operator):

        current = self.lineEdit.text()

        if current and current[-1] not in '+-*/':

            self.lineEdit.setText(current + operator)

    

    def writePoint(self):

        current = self.lineEdit.text()

        if current and current[-1] not in '+-*/.':

            self.lineEdit.setText(current + '.')

```


---


#### **4. Logika Perhitungan**  

```python

    def calculate(self):

        try:

            result = eval(self.lineEdit.text())

            self.lineEdit.setText(str(result))

        except:

            self.lineEdit.setText('ERROR')

    

    def percentage(self):

        try:

            value = float(self.lineEdit.text())

            self.lineEdit.setText(str(value/100))

        except:

            self.lineEdit.setText('ERROR')

```


**Catatan Keamanan:**  

- Penggunaan `eval()` hanya untuk demonstrasi  

- Pada aplikasi produksi, gunakan parser matematika yang lebih aman  


---


### **Cara Menjalankan**  

1. Install PyQt5:  

   ```bash

   pip install pyqt5

   ```  

2. Simpan kedua file dalam folder yang sama  

3. Jalankan:  

   ```bash

   python main.py

   ```


---


### **Optimisasi dan Best Practice**  

1. **Validasi Input**  

   ```python

   def validate_input(self, new_char):

       last_char = self.lineEdit.text()[-1] if self.lineEdit.text() else ''

       # Cegah operator berturut-turut

       if new_char in '+-*/' and last_char in '+-*/':

           return False

       # Cegah multiple decimal points

       if new_char == '.' and '.' in self.get_current_number():

           return False

       return True

   ```


2. **Styling Tambahan**  

   ```python

   button.setStyleSheet("""

       QPushButton {

           font-size: 16px;

           padding: 10px;

           background: #f0f0f0;

       }

       QPushButton:hover {

           background: #e0e0e0;

       }

   """)

   ```


3. **Keyboard Support**  

   Implementasikan event handler untuk input keyboard  


---


### **Kesimpulan**  

Kalkulator ini menunjukkan:  

✅ Penggunaan QGridLayout untuk tata letak kompleks  

✅ Manajemen state sederhana  

✅ Penanganan event dasar  


**Potensi Pengembangan:**  

- Tambahkan memory function (M+, M-, MR)  

- Implementasikan scientific calculator  

- Tambahkan history perhitungan  


**[📥 Download Source Code Lengkap](https://example.com/calculator-pyqt5)**


---


**Challenge:** Coba tambahkan fitur akar kuadrat dan pangkat!  


```python

def add_sqrt_function(self):

    self.sqrtButton = QPushButton('√')

    self.sqrtButton.clicked.connect(lambda: 

        self.lineEdit.setText(str(math.sqrt(float(self.lineEdit.text()))))

```

Komentar