파이썬 프로젝트 강좌(초급)/환율 계산기

환율 계산기 만들기 - 6. GUI 환율 계산기 - 구글 환율 계산기와 기능적으로 유사하게

파기차차 2024. 7. 17. 21:18
728x90
반응형
SMALL

ㅁ 개요

 

O 프로젝트 소개

 

 

 - 이번 글은 이전글(

2024.07.07 - [파이썬 프로젝트 강좌(초급)/환율 계산기] - 환율 계산기 만들기 - 5. GUI 환율 계산기 - 실행버튼 없이 실행(엔터시 실행))에 이은 7번째 마지막 글로  구글에서 "환율"로 검색 시 환율 계산 화면이 나오는데, 이와 가장 유사하게 만들어 보는 방법에 대해 알아보겠습니다.

 

 

 

 

O 완성된 프로그램 실행 화면

 

 

 - 최종 완성된 프로그램의 결과화면은 아래와 같습니다.

 

 

1. 6_1.py 실행 시 아래와 같이 잘 실행됩니다.

 

 

 

하지만 대상통화의 KRW->EUR로 변경시 EUR 1373.99의 값에 해당하는 USD의 값이 변경되지 않고, 실행결과 창에 "하나의 입력 필드에 값을 입력해 주세요."라고 뜹니다. 이부분을 수정해야 합니다.

 

 

2. 6_2.py 실행 시 아래와 같이 잘 실행됩니다.

 

하지만 대상통화의 KRW->EUR로 변경시 EUR 1373.99의 값에 해당하는 USD의 값이 변경되지 않고  EUR 옆의 lineEdit_2의 값이 변경되었습니다. 이부분을 수정해야 합니다.

 

 

 

3. 6_3.py 실행 시 아래와 같이 잘 실행됩니다.

 

 

대상통화의 KRW->EUR로 변경시 EUR 1373.99의 값에 해당하는 USD의 값이 1497.64로 우리가 예상한 대로 잘 변경되었습니다.

 

 

 


 

ㅁ 세부 내용

 

O 완성된 소스

 

소스파일 : 6_1.py

# -*- coding: utf-8 -*-
import sys
from PyQt5.QtWidgets import *
from PyQt5 import uic, QtWidgets
import os
from PyQt5.QtGui import *
import re

import requests
import json
from datetime import datetime

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

# lineEdit 변경시 -> lineEdit_2에 값 자동 삽입
# lineEdit_2 변경시 -> lineEdit에 값 자동 삽입하도록 수정

class MyWindow(QMainWindow, form_class):
    def __init__(self):
        super().__init__()

        self.setFixedSize(800,600)
        self.setWindowIcon(QIcon("pagichacha.png"))
        self.setupUi(self)

        self.is_updating = False

        self.comboBox.currentIndexChanged.connect(self.calculate)
        self.comboBox_2.currentIndexChanged.connect(self.calculate)
        self.lineEdit.textChanged.connect(self.calculate_from_lineEdit)
        self.lineEdit_2.textChanged.connect(self.calculate_from_lineEdit2)

    def calculate_from_lineEdit(self):
        if not self.is_updating:
            self.is_updating = True
            self.calculate(source='lineEdit')
            self.is_updating = False

    def calculate_from_lineEdit2(self):
        if not self.is_updating:
            self.is_updating = True
            self.calculate(source='lineEdit2')
            self.is_updating = False

    def calculate(self, source=None):
        fromCurrency = self.comboBox.currentText()
        toCurrency = self.comboBox_2.currentText()

        if source == 'lineEdit' or (source is None and self.lineEdit.text()):
            self.convert_currency(self.lineEdit, self.lineEdit_2, fromCurrency, toCurrency)
        elif source == 'lineEdit2' or (source is None and self.lineEdit_2.text()):
            self.convert_currency(self.lineEdit_2, self.lineEdit, toCurrency, fromCurrency)
        else:
            self.textEdit.setText("하나의 입력 필드에 값을 입력해 주세요.")

    def convert_currency(self, input_field, output_field, from_currency, to_currency):
        present_value = input_field.text()
        if re.match(r'^-?\d+(?:\.\d+)?$', present_value):
            present_value = float(present_value)
            rate, last_updated = self.get_exchange_rate(from_currency, to_currency)
            converted_value = present_value * rate
            output_field.setText(f"{converted_value:.6f}")
            self.update_result_text(present_value, converted_value, rate, from_currency, to_currency, last_updated)
        else:
            if present_value:  # 입력값이 있을 때만 메시지 표시
                self.textEdit.setText("입력값은 숫자가 아닙니다. 숫자를 입력하여 주시기 바랍니다.")
            else:
                output_field.clear()  # 입력값이 없으면 출력 필드도 클리어
                self.textEdit.clear()  # 결과 텍스트도 클리어

    def update_result_text(self, input_value, output_value, rate, from_currency, to_currency, last_updated):
        result_text = f"{input_value:,.6f} {from_currency}는 {output_value:,.6f} {to_currency} 입니다."
        result_text += f"\n\n환율: 1 {from_currency} = {rate:,.6f} {to_currency}"
        result_text += f"\n마지막 업데이트: {last_updated}"
        self.textEdit.setText(result_text)

    def get_exchange_rate(self, base_currency, target_currency):
        url = f"https://api.exchangerate-api.com/v4/latest/{base_currency}"
        
        try:
            response = requests.get(url)
            data = json.loads(response.text)
            
            if response.status_code == 200:
                rate = data['rates'][target_currency]
                last_updated = datetime.fromtimestamp(data['time_last_updated'])
                
                print(f"현재 환율: 1 {base_currency} = {rate} {target_currency}")
                print(f"마지막 업데이트: {last_updated}")

                return rate, last_updated
            else:
                print("환율 정보를 가져오는데 실패했습니다.")
        
        except requests.exceptions.RequestException as e:
            print(f"오류 발생: {e}")

app=QApplication(sys.argv)
window = MyWindow()
window.show()
print("Before event loop")
app.exec_()
print("After event loop")

 

 

 

 

소스파일 : 6_2.py

# -*- coding: utf-8 -*-
import sys
from PyQt5.QtWidgets import *
from PyQt5 import uic, QtWidgets
import os
from PyQt5.QtGui import *
import re

import requests
import json
from datetime import datetime

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

# lineEdit 변경시 -> lineEdit_2에 값 자동 삽입
# lineEdit_2 변경시 -> lineEdit에 값 자동 삽입하도록 수정

class MyWindow(QMainWindow, form_class):
    def __init__(self):
        super().__init__()

        self.setFixedSize(800,600)
        self.setWindowIcon(QIcon("pagichacha.png"))
        self.setupUi(self)

        self.is_updating = False

        self.comboBox.currentIndexChanged.connect(self.on_combo_changed)
        self.comboBox_2.currentIndexChanged.connect(self.on_combo_changed)
        self.lineEdit.textChanged.connect(self.calculate_from_lineEdit)
        self.lineEdit_2.textChanged.connect(self.calculate_from_lineEdit2)

    def on_combo_changed(self):
        if self.lineEdit.text():
            self.calculate_from_lineEdit()
        elif self.lineEdit_2.text():
            self.calculate_from_lineEdit2()

    def calculate_from_lineEdit(self):
        if not self.is_updating:
            self.is_updating = True
            self.calculate(source='lineEdit')
            self.is_updating = False

    def calculate_from_lineEdit2(self):
        if not self.is_updating:
            self.is_updating = True
            self.calculate(source='lineEdit2')
            self.is_updating = False

    def calculate(self, source=None):
        fromCurrency = self.comboBox.currentText()
        toCurrency = self.comboBox_2.currentText()

        if source == 'lineEdit' or (source is None and self.lineEdit.text()):
            self.convert_currency(self.lineEdit, self.lineEdit_2, fromCurrency, toCurrency)
        elif source == 'lineEdit2' or (source is None and self.lineEdit_2.text()):
            self.convert_currency(self.lineEdit_2, self.lineEdit, toCurrency, fromCurrency)

    def convert_currency(self, input_field, output_field, from_currency, to_currency):
        present_value = input_field.text()
        if re.match(r'^-?\d+(?:\.\d+)?$', present_value):
            present_value = float(present_value)
            rate, last_updated = self.get_exchange_rate(from_currency, to_currency)
            converted_value = present_value * rate
            output_field.setText(f"{converted_value:.6f}")
            self.update_result_text(present_value, converted_value, rate, from_currency, to_currency, last_updated)
        else:
            if present_value:  # 입력값이 있을 때만 메시지 표시
                self.textEdit.setText("입력값은 숫자가 아닙니다. 숫자를 입력하여 주시기 바랍니다.")
            else:
                output_field.clear()  # 입력값이 없으면 출력 필드도 클리어
                self.textEdit.clear()  # 결과 텍스트도 클리어

    def update_result_text(self, input_value, output_value, rate, from_currency, to_currency, last_updated):
        result_text = f"{input_value:,.6f} {from_currency}는 {output_value:,.6f} {to_currency} 입니다."
        result_text += f"\n\n환율: 1 {from_currency} = {rate:,.6f} {to_currency}"
        result_text += f"\n마지막 업데이트: {last_updated}"
        self.textEdit.setText(result_text)

    def get_exchange_rate(self, base_currency, target_currency):
        url = f"https://api.exchangerate-api.com/v4/latest/{base_currency}"
        
        try:
            response = requests.get(url)
            data = json.loads(response.text)
            
            if response.status_code == 200:
                rate = data['rates'][target_currency]
                last_updated = datetime.fromtimestamp(data['time_last_updated'])
                
                print(f"현재 환율: 1 {base_currency} = {rate} {target_currency}")
                print(f"마지막 업데이트: {last_updated}")

                return rate, last_updated
            else:
                print("환율 정보를 가져오는데 실패했습니다.")
        
        except requests.exceptions.RequestException as e:
            print(f"오류 발생: {e}")

app=QApplication(sys.argv)
window = MyWindow()
window.show()
print("Before event loop")
app.exec_()
print("After event loop")

 

 

 

 

소스파일 : 6_3.py

# -*- coding: utf-8 -*-
import sys
from PyQt5.QtWidgets import *
from PyQt5 import uic, QtWidgets
import os
from PyQt5.QtGui import *
import re

import requests
import json
from datetime import datetime

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

# lineEdit 변경시 -> lineEdit_2에 값 자동 삽입
# lineEdit_2 변경시 -> lineEdit에 값 자동 삽입하도록 수정

class MyWindow(QMainWindow, form_class):
    def __init__(self):
        super().__init__()

        self.setFixedSize(800,600)
        self.setWindowIcon(QIcon("pagichacha.png"))
        self.setupUi(self)

        self.is_updating = False

        self.comboBox.currentIndexChanged.connect(self.on_combo1_changed)
        self.comboBox_2.currentIndexChanged.connect(self.on_combo2_changed)
        self.lineEdit.textChanged.connect(self.calculate_from_lineEdit)
        self.lineEdit_2.textChanged.connect(self.calculate_from_lineEdit2)

    def on_combo1_changed(self):
        if self.lineEdit.text():
            self.calculate_from_lineEdit()

    def on_combo2_changed(self):
        if self.lineEdit_2.text():
            self.calculate_from_lineEdit2()

    def calculate_from_lineEdit(self):
        if not self.is_updating:
            self.is_updating = True
            self.calculate(source='lineEdit')
            self.is_updating = False

    def calculate_from_lineEdit2(self):
        if not self.is_updating:
            self.is_updating = True
            self.calculate(source='lineEdit2')
            self.is_updating = False

    def calculate(self, source=None):
        fromCurrency = self.comboBox.currentText()
        toCurrency = self.comboBox_2.currentText()

        if source == 'lineEdit' or (source is None and self.lineEdit.text()):
            self.convert_currency(self.lineEdit, self.lineEdit_2, fromCurrency, toCurrency)
        elif source == 'lineEdit2' or (source is None and self.lineEdit_2.text()):
            self.convert_currency(self.lineEdit_2, self.lineEdit, toCurrency, fromCurrency)

    def convert_currency(self, input_field, output_field, from_currency, to_currency):
        present_value = input_field.text()
        if re.match(r'^-?\d+(?:\.\d+)?$', present_value):
            present_value = float(present_value)
            rate, last_updated = self.get_exchange_rate(from_currency, to_currency)
            converted_value = present_value * rate
            output_field.setText(f"{converted_value:.6f}")
            self.update_result_text(present_value, converted_value, rate, from_currency, to_currency, last_updated)
        else:
            if present_value:  # 입력값이 있을 때만 메시지 표시
                self.textEdit.setText("입력값은 숫자가 아닙니다. 숫자를 입력하여 주시기 바랍니다.")
            else:
                output_field.clear()  # 입력값이 없으면 출력 필드도 클리어
                self.textEdit.clear()  # 결과 텍스트도 클리어

    def update_result_text(self, input_value, output_value, rate, from_currency, to_currency, last_updated):
        result_text = f"{input_value:,.6f} {from_currency}는 {output_value:,.6f} {to_currency} 입니다."
        result_text += f"\n\n환율: 1 {from_currency} = {rate:,.6f} {to_currency}"
        result_text += f"\n마지막 업데이트: {last_updated}"
        self.textEdit.setText(result_text)

    def get_exchange_rate(self, base_currency, target_currency):
        url = f"https://api.exchangerate-api.com/v4/latest/{base_currency}"
        
        try:
            response = requests.get(url)
            data = json.loads(response.text)
            
            if response.status_code == 200:
                rate = data['rates'][target_currency]
                last_updated = datetime.fromtimestamp(data['time_last_updated'])
                
                print(f"현재 환율: 1 {base_currency} = {rate} {target_currency}")
                print(f"마지막 업데이트: {last_updated}")

                return rate, last_updated
            else:
                print("환율 정보를 가져오는데 실패했습니다.")
        
        except requests.exceptions.RequestException as e:
            print(f"오류 발생: {e}")

app=QApplication(sys.argv)
window = MyWindow()
window.show()
print("Before event loop")
app.exec_()
print("After event loop")

 

 

 

 

O 소스 실행 방법

 
 
 - 소스파일 다운로드 후 cmd 또는 파워쉘 등에서 아래와 같이 실행하시기 바랍니다.
 
 > python 6_1.py
 > python 6_2.py
 > python 6_3.py
 

 

 


 
 

O 주요 내용

 

아래 소스코드에 대한 주요 내용만 설명하겠습니다.

 

 

소스 파일 : 6_1.py

라인에디트에 값 입력시 상대 통화의 라인에디트에 계산된 환율이 잘 입력되고 있으나, 콤보박스 변경시 별다른 코드를 지정해주지 않아 "하나의 입력 필드에 값을 입력해 주세요" 라고만 뜹니다.

 

소스코드는 아래 화면을 참고하여 주시기 바랍니다.

 

 

 

 

 

 

소스 파일 : 6_2.py

comboBox_2변경시 lineEdit에 값이 들어가지 않고, lineEdit_2에 값이 입력되고 있습니다.

 

해당 이유는 아래 설명을 참고하여 주시기 바랍니다.

 

 

 

 

 

 

소스 파일 : 6_3.py

콤보박스 이벤트별로 on_combo1,2_changed() 메소드로 분리하여 각 각 다른 ~lineEdit()/~lineEdit2() 메소드를 호출하도록 하여 상대편 라인에디트에 값이 입력될 수 있도록 개선하였습니다.

 

 

 

 

 


 

ㅁ 정리

 

O 우리가 배운 내용

 
 - 오늘은 구글에서 "환율"로 검색 시 환율 계산 화면이 나오는데, 이와 가장 유사하게 만들어 보는 방법에 대해 알아보았습니다.
즉, lineEdit 에 값 입력시 환율 계산한 내용이 lineEdit_2에 입력되고,
comboBox2를 변경하면 lineEdit_2 해당통화에 해당하는의 값이 comboBox 통화의 환율로 계산되어 lineEdit에 값이 자동으로 입력되도록 개선한 방법을 알아 보았습니다.
 
이것으로 환율 계산기 프로그램 만들기를 모두 마칩니다.
 
 
 

 

여기까지 읽어 주셔서 감사드리며, 위의 내용이 유익하셨다면, 광고 한번씩만 클릭 부탁드립니다.

 

 

감사합니다.

728x90
반응형
LIST