Skip to content

개인 프로젝트 - Shunting Yard 연산 알고리즘을 활용한 PyQt6 괄호 포함 계산기

Notifications You must be signed in to change notification settings

jinhyuk2me/QCalculator

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

66 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

🧮 PyQt6 괄호 포함 계산기 프로젝트

📅 프로젝트 기간: 2025.04.22 ~ 2025.04.25
🎯 구조: MVC 아키텍처 / 상태 기반 입력 처리 / 후위 표기법 기반 수식 계산기 💻 실행 환경: Python 3.12 / PyQt6 / Ubuntu 24.04

괄호 연산, 음수 처리, 연산자 우선순위, 오류 메시지 출력 등 실제 계산기 수준의 입력 UX를 구현한 PyQt6 기반 GUI 계산기입니다.
Shunting Yard 알고리즘과 스택 계산기를 직접 구현하여 정확한 수식 평가를 보장하며, MVC 구조 기반으로 유지보수성과 확장성을 모두 확보했습니다.


👨‍💻 제작자

장진혁 (Jang Jin-Hyuk)   GitHub Profile


💡 프로젝트 특징 요약

항목 내용
구조 PyQt6 기반 MVC 아키텍처
수식 처리 괄호 포함 중위 → 후위 변환 (Shunting Yard)
계산 로직 스택 기반 후위 표기 수식 평가
입력 UX 숫자, 소수점, ±, 괄호, 초기화, 삭제 등 전체 UX 처리
오류 대응 0으로 나누기, 괄호 불일치 등 자동 복구 및 메시지 출력
상태 관리 READY / INPUTTING / CALCULATED / ERROR 전이 설계
스타일 확장성 Casio 스타일 테마 확장 가능

🖼 GUI 화면 구성

📷 전체 화면 예시

display

🧾 화면 요소 설명

▸ 상단 / 하단 디스플레이

  • 상단 디스플레이 (lineEdit_2): 현재 수식 표현 (토큰 기반 수식 표시)
  • 하단 디스플레이 (lineEdit): 현재 입력 숫자 또는 계산 결과 표시

▸ 버튼 기능 정리

버튼 구분 항목 설명
숫자 버튼 0 ~ 9 숫자 입력
연산자 버튼 +, -, ×, ÷ 사칙연산 입력
괄호 (, ) 괄호 입력
계산 = 수식 평가 후 결과 출력
초기화 AC 전체 입력 초기화
삭제 C 마지막 항목 삭제
부호 전환 ± 숫자 부호 전환 (+ ↔ -)
소수점 . 소수점 입력 (중복 방지 포함)

▸ 텍스트 메시지 영역

  • 사용자 오류 및 안내 메시지를 일시적으로 표시하는 하단 텍스트 영역
    예: "소수점은 한 번만 입력할 수 있습니다"
    예: "닫는 괄호가 더 많을 수 없습니다"

🔢 기능 세부 설명

✔ 사칙연산 및 괄호

  • +, -, *, / 연산 모두 지원
  • 중첩 괄호, 우선순위 계산 완벽 지원
  • -(2+3) 입력 시 자동으로 -1*(2+3) 변환

✔ 입력 제한 및 UX 보호

  • 숫자 입력은 최대 20자리로 제한
  • 소수점 중복 입력 방지: 한 숫자에 . 한 번만 허용
    • 예: -0.001은 유효, 0.00.1은 무효
  • C: 최근 입력 항목 1개 삭제
  • AC: 전체 수식 및 입력 초기화
  • ±: 부호 전환 기능
    • -1212
    • 0-

✔ 괄호 입력 로직

  • 괄호 수가 맞지 않을 경우 자동 보완
    • 여는 괄호가 남아 있을 경우 ) 자동 삽입
    • 닫는 괄호가 더 많으면 무시 또는 삭제
  • 연산자 뒤에 괄호가 바로 올 경우 무효 처리
    • 예: (+3) → 무효
  • 숫자 뒤 괄호 입력 시 암시적 곱셈 처리
    • 예: 2(3+4)2*(3+4)로 자동 변환

✔ 오류 감지 및 자동 복구

  • 1 + )처럼 닫는 괄호가 과도할 경우:
    • "닫는 괄호가 더 많을 수 없습니다" 메시지 출력
  • 괄호 불일치 시 자동 보완 후 계산 수행
  • 계산 중 0으로 나누기 시 "Error" 메시지 출력

🧠 MVC 아키텍처 구조

📌 핵심 개념

  • 전체 프로그램을 Model, View, Controller로 명확히 분리
  • ModelView는 서로 직접 접근하지 않으며, Controller를 통해 간접 연결됨

🔄 흐름 구조

사용자 입력 (View)
↓ signal
Controller (입력 핸들링 및 상태 갱신)
↓ Model 호출 및 계산 결과 전달
Model (계산 로직 및 상태 관리)
↑ 계산 결과 반환
Controller → View.update_xxx()로 결과 반영

📦 각 요소별 역할 정리

구성 요소 역할 설명
Controller 중심 허브. View와 Model 모두를 알고 있으며, 사용자 입력을 받아 Model을 호출하고 View를 갱신
Model 계산 로직과 상태 처리를 담당. 직접 UI를 업데이트하지 않음
View 사용자 인터페이스 구성과 사용자 입력 signal 전달 담당. 자체 로직은 없음
qt-calculator/
├── main.py             # 진입점
├── model.py            # 수식 파싱 / 계산기 로직 / 상태 관리
├── view.py             # PyQt6 UI 처리 / 메시지 표시
├── controller.py       # 입력 처리 → 모델 호출 → 뷰 갱신
├── calculator.ui       # Qt Designer 기반 UI 정의
├── img/                # 배너, 스크린샷 이미지
├── flow_chart/         # 기능별 순서도
└── doc/                # 발표자료 등 프로젝트 문서

상태 전이 구조 (CalcState)

계산기 내부 상태는 다음 4가지 중 하나로 존재하며, 사용자 행동에 따라 상태 전이가 발생합니다:

상태 설명
READY 초기 상태. 입력이 없는 대기 상태
INPUTTING 숫자, 연산자, 괄호 등 수식이 입력되고 있는 중
CALCULATED 계산 완료 후 결과가 출력된 상태
ERROR 잘못된 수식, 0으로 나누기 등의 오류가 발생한 상태

상태 전이 예시

  • READYINPUTTING: 숫자나 괄호, 연산자 입력 시작
  • INPUTTINGCALCULATED: = 입력 후 결과 계산
  • INPUTTINGERROR: 괄호 오류, 수식 오류 등 발생
  • CALCULATEDREADY 또는 INPUTTING: 새 수식 입력 또는 연산자 추가
  • ERRORREADY: C, AC 또는 새 숫자 입력 시 복구

🔄 순서도 (Flowcharts)

main

main

handle 함수 예시 (handle_lparen())

handle_lparen


🧪 테스트 설계 기준

6가지 기능 분류 기준에 따라 총 45개의 테스트 시나리오를 설계하였으며, 각 시나리오는 입력값 → 상태 변화(CalcState) → 내부 변수 변화 → 출력 결과 흐름까지 전 과정을 검증합니다.

기능 분류 테스트 개수 설명
초기 상태 입력 흐름 9 READY 상태에서의 숫자/연산자 입력 처리 검증
오류 직후 입력 복구 흐름 9 ERROR 상태 이후 입력 복원 가능 여부 확인
계산 후 입력 처리 흐름 9 CALCULATED 상태에서 연산 연속성 및 초기화 검증
괄호/우선순위 처리 8 괄호 중첩, 연산자 우선순위, 암시적 곱셈 처리 검증
에러 처리 및 에러 방지 6 잘못된 수식에 대한 자동 보정 및 UX 보호 로직 확인
초기화 흐름 4 C, AC 버튼에 따른 입력/상태 초기화 검증

각 테스트는 내부 변수(current_input, tokens) 변화와 디스플레이(lineEdit) 출력 결과까지 함께 추적합니다.


🧪 예시 테스트 케이스

번호 입력값 예상 결과 설명
TC_10 에러 발생 후 숫자 입력 정상 입력으로 복구됨 오류 상태에서도 새 입력으로 정상 복구 가능한지 검증
TC_20 계산 직후 연산자 입력 결과값에 연산자 추가됨 계산 완료 후 바로 연산자 입력이 자연스럽게 이어지는지 검증
TC_22 계산 직후 괄호 입력 결과 뒤 곱셈(*) 자동 삽입 후 괄호 입력됨 계산 완료된 수치 뒤에 괄호 입력 시 암시적 곱셈 처리 검증
TC_30 중첩 괄호 수식 계산 올바른 결과 반환 복잡한 괄호 중첩 구조에서 수식이 정확히 계산되는지 검증
TC_34 숫자 입력 후 괄호 입력 숫자 뒤에 곱셈(*) 자동 삽입 후 괄호 입력됨 숫자 뒤 괄호 입력 시 암시적 곱셈이 적용되는지 검증
TC_37 수식 끝에 연산자 입력 후 계산 오류 메시지 출력 수식 끝에 연산자가 남아있을 경우 에러를 감지하는지 검증
TC_38 닫는 괄호 부족 상태로 계산 자동으로 닫는 괄호 삽입 후 계산 수행 괄호가 불일치할 경우 자동 보완 로직이 정상 작동하는지 검증
TC_39 괄호를 이중으로 닫을 경우 무효 괄호 제거 및 수식 유지 여는 괄호 없이 닫는 괄호를 입력해도 시스템이 정상 복구하는지 검증
TC_40 괄호 닫기 직전에 연산자가 남은 경우 잘못된 연산자 제거 후 괄호 닫힘 처리 괄호 내부 수식이 불완전할 때도 자동 보정이 되는지 검증
TC_42 소수점 중복 입력 시도 "소수점은 한 번만 입력할 수 있습니다" 메시지 출력 소수점 입력 UX 보호 기능이 정상 작동하는지 검증

🧪 대표 테스트 케이스: TC_30 - 중첩 괄호 수식 계산

입력: (1+(2+3))*2 =  
목표 결과: 12  
테스트 목적: 괄호 중첩 수식에 대한 정확한 평가 및 디스플레이 출력 흐름 검증
입력 상태 current_input tokens lineEdit_2 (상단 수식) lineEdit (하단 결과)
( INPUTTING - ['('] ( -
1 INPUTTING 1 ['('] ( 1
+ INPUTTING - ['(', '1', '+'] (1+ -
( INPUTTING - ['(', '1', '+', '('] (1+( -
2 INPUTTING 2 ['(', '1', '+', '(', '2'] (1+( 2
+ INPUTTING - ['(', '1', '+', '(', '2', '+'] (1+(2+ -
3 INPUTTING 3 ['(', '1', '+', '(', '2', '+', '3'] (1+(2+ 3
) INPUTTING - ['(', '1', '+', '(', '2', '+', '3', ')'] (1+(2+3) -
) INPUTTING - ['(', '1', '+', '(', '2', '+', '3', ')', ')'] (1+(2+3)) -
2 INPUTTING 2 ['(', '1', '+', '(', '2', '+', '3', ')', ')', '*', '2'] (1+(2+3))* 2
= CALCULATED 12 ['(', '1', '+', '(', '2', '+', '3', ')', ')', '*', '2'] (1+(2+3))*2 12

🧪 테스트 결과 요약

항목 수치 비고
총 테스트 케이스 수 45개 정상 흐름 + 예외 흐름 포함
정상 흐름 테스트 수 31개 사칙연산, 괄호 처리 등 기능 정상 작동 검증
예외 흐름 테스트 수 14개 오류 입력 방어, UX 보호 기능 검증
정상 흐름 성공률 100% 모든 정상 케이스 기대 동작 성공
예외 흐름 성공률 100% 모든 예외 케이스 보호 로직 정상 작동
전체 테스트 성공률 100% 전체 45개 테스트 모두 성공

⚙ 실행 방법

git clone https://github.com/jinhyuk2me/qt-calculator.git
cd qt-calculator
pip install PyQt6
python main.py

📬 문의

장진혁 (Jang Jin-Hyuk)
📧 Email: jinhyuk2ya@gmail.com
🌐 GitHub: @jinhyuk2me

About

개인 프로젝트 - Shunting Yard 연산 알고리즘을 활용한 PyQt6 괄호 포함 계산기

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages