PyQt란?
PyQt는 파이썬 플러그인으로 구현된 크로스 플랫폼 GUI 툴킷 Qt의 파이썬 바인딩이다.
계산기를 만들자

위와 같은 형태의 계산기를 만든다고 하자.
2개의 화면이 있고,
최상단 화면에서는 지금까지 입력된 계산식을,
그 아래 큰 화면에서는 현재 입력중인 숫자 또는 계산의 결과에 해당하는 숫자를 표시한다.

천단위마다 콤마를 표시하고, 소수점 이하 숫자는 2번째 자리까지 표시한다.
현재 입력 내용만 지우려면 CE 버튼을,
지금까지 입력한 모든 내용을 지우려면 AC 버튼을 클릭한다.
이 계산기는 정수는 9번째 자리까지, 소수는 2번째 자리까지 지원하며, 표시할 수 있는 최댓값은 실수라면 999,999,999.99, 정수라면 999,999,999이다.
계산결과가 최댓값보다 크다면 계산결과를 최댓값으로 표시한다.
8/0과 같이 계산이 불가능한 값이 입력되면 "ERROR"를 표출하고, 이때 숫자키나 AC 버튼을 누르면 초기 상태로 돌아간다. (다른 버튼을 눌렀을 때 동작은 하나, ERROR에서 숫자키/AC 버튼을 눌러야 초기값 원복 함수 실행)
순서도
0. 전체

- 사칙연산 계산기인데 왜 이렇게 복잡하냐면요.. 코드를 먼저 짜고 순서도를 그렸더니 케이스가 중구난방이 되었습니다. 2편에서는 순서도부터 그리고 다시 시작 예정.
1. 시작

- MAX_FLOAT와 MAX_INT로 최댓값을 상수 선언
- 초기값을 setInit 함수로 설정 (이후 AC 버튼 클릭 또는 에러 이후 초기화면으로 돌아오기 위해 사용)
2. point 처리

- [case1] status == 0 && "." not in now_input (입력값을 보여주는 상태)
- [case 1-1] now_input == "" # 입력값이 없는 상태
- [case 1-2] now_input != "" # 입력값이 있는 상태
- now_input += "." # 기존 입력값에 .만 붙인다
- 화면에 입력값 표시(setTextModeZero)
- [case2] status == 1 && "." not in before_input (결과를 보여주는 상태)
- now_input = before_input + "."
- 화면에 결과값 표시(setTextModeOne)
- [case3] show_mode == 2 (에러 상태)
- 초기값으로 돌아감(setInit)
- now_input = "0."
- numberDisplay.setText(now_input)
3. 0 처리
- 앞의 숫자가 0이면 무시한다.

- 에러 상태이면(show_mode==2) setInit
- [case1] now_input != "0"
- 화면에 입력값 표시(setTextModeZero)
4. 1~9 처리
- 앞의 숫자가 0이면 새로 입력된 숫자로 대체한다.

- 에러 상태이면(show_mode==2) setInit
- [case1] now_input == "0"
- [case2] now_input != "0"
- 화면에 입력값 표시(setTextModeZero)
5. 음수/양수 처리

- 에러 상태이면(show_mode==2) setInit
- [process 1] show_mode == 1 || (show_mode == 0 && now_input != "0")
- [case 1] number_mode == 0
- [case 2] number_mode == 1
- [process 2-1] number_mode == 0
- [case 1] show_mode == 1
- now_input = "-" + formula
- formula = ""
- [case 2] show_mode != 1
- now_input = "-" + now_input
- [process 2-2] number_mode != 0
- [case 1] show_mode == 1
- now_input = formula.replace("-", "")
- formula = ""
- [case 2] show_mode != 1
6. 연산자 처리

- [case 1] history >=1 && before_input[-1] != " " && now_input != "0"
- before_input = now_input + operator
- [case 2] now_input != "0"
- before_input += now_input + operator
- [case 3] now_input == "0"
7. 계산

- [case 1] operator not in before_input
- show input as result
- raise Exception
- [case 2] operator in before_input
- text replace (* -> x, / -> ÷)
- formulaDisplay.setText(before_input)
- [process 2-1] now_input == ""
- [process 2-2] now_input != ""
- try: eval
- except
- status = 2
- numberDisplay.setText("ERROR")
- [process 2-3] result % 1 == 0
- [process 2-4] "." in result && len(result.split(".")[1]) > 2
- result = "{:.2f}".format(result))
- [process 2-5] (all condition)
- history += 1
- 화면에 결과값 표시(setTextModeOne)
입력값 표시 함수 setTextModeZero

- [case1] "." in now_input
- int_part = now_input.split(".")[0]
- float_part = now_input.split(".")[1]
- [case 1-1] len(float_part) == 0
- text = int with commas + "."
- [case 1-2] len(float_part) > 2 => 처리 후 case 1-3 실행
- now_input = int_part + "." + float_part[:2]
- [case 1-3] len(float_part) == 1 or 2
- text = float with commmas
- [case2] "." not in now_input
- now_input = now_input[:9]
- text = int with commas
- numberDisplay.setText(text)
결과 표시 함수 setTextModeOne

- [case1] "." in result
- int_part = result.split(".")[0]
- float_part = result.split(".")[1]
- [case 1-1] len(int_part) > 9
- result = MAX_FLOAT
- before_input = result
- [case 1-2] len(int_part) > 2 => 처리 후 case 1-4 실행
- result = int_part + "." + float_part[:2]
- before_input = result
- [case 1-3] len(int_part) == 0
- text = int with commas + "."
- [case 1-4] len(int_part) == 1 or 2
- [case2] "." not in result
- [process 2-1] len(result) > 9
- result = MAX_INT
- before_input = result
- [process 2-2] len(result) =< 9
- numberDisplay.setText(text)

- [process] len(now_input) == 0: 숫자 입력 없이 연산자만 있을 때
- 마지막 6자리를 마지막 3자리로 변경 = 여러 연산자 입력 시 마지막 연산자만 처리
- formulaDisplay.setText(formula_text)
- numberDisplay.setText(now_input)