본문 바로가기

Study/Python

1. 계산기 만들기

프로그래밍에서 가장 기본이되는 계산기 만들기

다른 언어에서는 스택 구조를 이용해 후위 표기식을 통해 구현해야하지만, 

Python 에서는 eval 함수로 간단하게 계산식을 구현할 수 있다.

Ui는 Qt designer를 사용해서 만들었다.

 

*전체코드

import numpy as np
import math
import sys

from PyQt5.QtWidgets import *
from PyQt5 import uic

form_class = uic.loadUiType("RCalc.ui")[0]

class CalcClass(QMainWindow, form_class):
    def __init__(self):
        super().__init__()
        self.setupUi(self)
        self.setWindowTitle("Xiang's Calc")
        # self.Cal = PostfixOper()

        Numbers = [self.Num_0,self.Num_1,self.Num_2,self.Num_3,self.Num_4,self.Num_5,self.Num_6,
                    self.Num_7,self.Num_8,self.Num_9]
        # print(self.Line_res.text())
        for number in Numbers:
            number.clicked.connect(self.Nums)
        # self.Num_1.clicked.connect(self._tmp)

        self.Btn_Dot.clicked.connect(self.btn_dot)
        self.Btn_Equal.clicked.connect(self.btn_equal)
        self.Btn_Clear.clicked.connect(self.btn_clear)
        self.Btn_Del.clicked.connect(self.btn_del)
        self.Btn_LBrak.clicked.connect(self.btn_lbrak)
        self.Btn_RBrak.clicked.connect(self.btn_rbrak)
        self.Btn_Div.clicked.connect(self.btn_div)
        self.Btn_Minus.clicked.connect(self.btn_minus)
        self.Btn_Mul.clicked.connect(self.btn_mul)
        self.Btn_Plus.clicked.connect(self.btn_plus)
        self.Btn_Pi.clicked.connect(self.btn_pi)
        self.Btn_Log.clicked.connect(self.btn_log)
        self.Btn_Root.clicked.connect(self.btn_root)
        self.Btn_Square.clicked.connect(self.btn_square)

    def Nums(self):
        sender = self.sender()
        new_num = int(sender.text())
        num_str = str(new_num)
        if self.Line_res.text() == '0':
            self.Line_res.setText(num_str)
        else:
            self.Line_res.setText(self.Line_res.text() + num_str)

    def btn_pi(self):
        if self.Line_res.text() == '0':
            self.Line_res.setText('π')
        else:
            self.Line_res.setText(self.Line_res.text() + 'π')

    def btn_log(self):
        if self.Line_res.text() == '0':
            self.Line_res.setText('log(')
        else:
            self.Line_res.setText(self.Line_res.text() + 'log(')

    def btn_root(self):
        if self.Line_res.text() == '0':
            self.Line_res.setText('√(')
        else:
            self.Line_res.setText(self.Line_res.text() + '√(')

    def btn_square(self):
        if self.Line_res.text() == '0' :
            pass
        else:
            try :
                float(self.Line_res.text()[-1])
                self.Line_res.setText(self.Line_res.text() + '^(2)')
            except:
                pass

    def btn_dot(self):
        self.Line_res.setText(self.Line_res.text() + '.')

    def btn_clear(self):

        self.Line_res.setText('0')

    def btn_del(self):

        n = len(self.Line_res.text())
        if self.Line_res.text()[-1] == ' ':
            self.Line_res.setText(self.Line_res.text()[0:n-2])
        else:
            self.Line_res.setText(self.Line_res.text()[0:n-1])
        if self.Line_res.text() == '':
            self.Line_res.setText('0')

    def btn_lbrak(self):
        if self.Line_res.text() == '0':
            self.Line_res.setText(' ( ')
        else:
            self.Line_res.setText(self.Line_res.text() + ' ( ')
    def btn_rbrak(self):
        if self.Line_res.text() == '0':
            self.Line_res.setText('Error// Press Clear Button')
        else:
            self.Line_res.setText(self.Line_res.text() + ' ) ')

    def btn_div(self):
        if self.Line_res.text() == '0':
            self.Line_res.setText('Error// Press Clear Button')
        else:
            self.Line_res.setText(self.Line_res.text() + ' / ')

    def btn_minus(self):
        if self.Line_res.text() == '0':
            self.Line_res.setText('Error// Press Clear Button')
        else:
            self.Line_res.setText(self.Line_res.text() + ' - ')

    def btn_mul(self):
        if self.Line_res.text() == '0':
            self.Line_res.setText('Error// Press Clear Button')
        else:
            self.Line_res.setText(self.Line_res.text() + ' * ')

    def btn_plus(self):
        if self.Line_res.text() == '0':
            self.Line_res.setText('Error// Press Clear Button')
        else:
            self.Line_res.setText(self.Line_res.text() + ' + ')

    def btn_equal(self):
        res = self.Line_res.text()
        # print(res)

        res = res.replace('√','math.sqrt')
        res = res.replace('log','math.log')
        res= res.replace('π','math.pi')
        res= res.replace('^','**')

        # print(res)
        result = round(eval(res),4)
        self.Line_res.setText(str(result))


app = QApplication(sys.argv)
myWindow = CalcClass()
myWindow.show()
app.exec_()

1. 숫자 연결

        Numbers = [self.Num_0,self.Num_1,self.Num_2,self.Num_3,self.Num_4,self.Num_5,self.Num_6,
                    self.Num_7,self.Num_8,self.Num_9]

        for number in Numbers:
            number.clicked.connect(self.Nums)

먼저, 짜여 있는 Ui는 각 Num_* 으로 객체이름을 설정해 놓았다.

 

10개의 숫자 버튼을 각각 시그널로 연결하기에는 귀찮고 공간낭비도 많음으로 Numbers 리스트로 묶어 for문을 통해 시그널을 연결해 주었다.

 

    def Nums(self):
        sender = self.sender()
        num_str = sender.text()
        if self.Line_res.text() == '0':
            self.Line_res.setText(num_str)
        else:
            self.Line_res.setText(self.Line_res.text() + num_str)

이후, 각 숫자 버튼을 눌러 시그널이 보내지면, 먼저 sender()를 통해 sender에 눌린 버튼을 저장하고,

sender.text()로 내가 designer로 해당 버튼에 적어놓은 텍스트를 가져온다.

현재 식을 출력하는 Line_res에 0밖에 없다면 (기존에 입력된 숫자가 없으면), 내가 버튼을 누른 숫자를 입력하고,

기존에 다른 숫자가 있다면, text()를 통해 기존에 있는 텍스트에다가 입력 숫자를 추가해준다.

다른 기호식들도 TextLine에 표기하는건 똑같은 알고리즘으로 하면 된다.

 

2. 제곱식

    def btn_square(self):
        if self.Line_res.text() == '0' :
            pass
        else:
            try :
                float(self.Line_res.text()[-1])
                self.Line_res.setText(self.Line_res.text() + '^(2)')
            except:
                pass

제곱식에서 다른점은 기존식에 0밖에 없다면, 제곱식을 눌러도 아무런 동작을 수행시키지 않았고(기존 0그대로 출력)

만약 라인에 있는 마지막글자가 숫자라면, (에러가 발생하지 않으면) Line_res에 제곱식을 넣도록 했고,

그렇지 않으면(숫자가 아닌 기호 등) 다시 pass로 동작을 주지 않았다.

 

3. Del버튼

    def btn_del(self):

        n = len(self.Line_res.text())
        if self.Line_res.text()[-1] == ' ':
            self.Line_res.setText(self.Line_res.text()[0:n-2])
        else:
            self.Line_res.setText(self.Line_res.text()[0:n-1])
        if self.Line_res.text() == '':
            self.Line_res.setText('0')

기호를 눌렀을때는 한 칸 뛰기가 입력되도록 코딩하였기 때문에(1 + 2)
공백이 있을 경우에는 뒤에 두칸을 지우도록 코딩하였다.

 

3. Eqaul 결과 출력

    def btn_equal(self):
        res = self.Line_res.text()
        # print(res)

        res = res.replace('√','math.sqrt')
        res = res.replace('log','math.log')
        res= res.replace('π','math.pi')
        res= res.replace('^','**')

        # print(res)
        result = round(eval(res),4)
        self.Line_res.setText(str(result))

먼저 Line에 있는 text를 받고, 

eval함수에서의 작동을 위해 각각의 수학기호들을 eval 함수에서 작동하도록 바꿔준다.

나눗셈의 경우 결과가 지저분 해 질 수 있으므로 round 함수로 4자리 까지 출력되도록 했다.

 

 

학교에서 프로그래밍을 배우면서 가장 첫 학기에 만들어본 계산기,,,

당장 designer와 class 사용법도 제대로 모르고 했던 기억이 있다.

 

다시보면 여러모로 지저분하고 비효율적이지만 처음 계산기를 만들면서 pyqt와 designer 사용법을 배우고

처음 윈도우를 창에 띄웠을때는 짜릿했다.