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

환율 계산기 만들기 - 4. GUI 환율 계산기 - 실행버튼 없이 실행(change 이벤트)

파기차차 2024. 7. 13. 18:52
728x90
반응형
SMALL

ㅁ 개요

 

O 프로젝트 소개

 

 

 - 이번 글은 이전글([파이썬 프로젝트 강좌(초급)/환율 계산기] - 환율 계산기 만들기 - 4. GUI 환율 계산기 - 실행버튼 없이 실행(change 이벤트))에 이은 5번째 글로 실행버튼을 클릭하지 않고, 무엇가 값이 바뀌었을때(change 이벤트) 환율이 자동적으로 계산되는 방법을 알아 보겠습니다.

 

 

 

 

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

 

 

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

 

 

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

메인 코드가 없어 단순히 lineEdit(위의 입력박스), lineEdit_2(아래 입력박스)에 값이 있는지 여부만 체크하고 있습니다.

 

 

 

 

 

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

lineEdit(위의 입력박스)에 값입력시, 즉 변화가 발생하면 트리거되며, 환율변환 함수를 호출하여 textEdit(실행결과 화면)에 변환된 환율을 보여줍니다.

 

 

 

 

 

 

2. 4_3.py 실행 시 아래와 같이 실행됩니다.

4_2.py와 반대로 lineEdit_2(아래의 입력박스)에 값입력시, EUR 통화-> USD 통화로 변환한 값을 textEdit(실행결과 화면)에 보여줍니다.

 

 

 

 


 

ㅁ 세부 내용

 

O 완성된 소스

 

소스파일 : 4_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]

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

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


        ###############################################################
        # 클릭하지 않고 변경되면 실행하도록 수정
        ###############################################################
        # self.pushButton.clicked.connect(self.main)
         # 이벤트 핸들러 연결
        # self.pushButton.clicked.connect(self.calculate)
        self.comboBox.currentIndexChanged.connect(self.calculate)
        self.comboBox_2.currentIndexChanged.connect(self.calculate)
        self.lineEdit.textChanged.connect(self.calculate)
        self.lineEdit_2.textChanged.connect(self.calculate)
        ###############################################################


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

        # lineEdit에 값이 있는 경우
        if self.lineEdit.text() and not self.lineEdit_2.text():
            print("lineEdit에 값이 존재하고, lineEdit_2에 값이 존재하지 않습니다.")
            self.textEdit.setText("lineEdit에 값이 존재하고, lineEdit_2에 값이 존재하지 않습니다.")

            # self.convert_currency(self.lineEdit, self.lineEdit_2, fromCurrency, toCurrency)

        # lineEdit_2에 값이 있는 경우
        elif self.lineEdit_2.text() and not self.lineEdit.text():
            print("lineEdit에 값이 존재하고, lineEdit_2에 값이 존재하지 않습니다.")
            self.textEdit.setText("lineEdit에 값이 존재하지 않고, lineEdit_2에 값이 존재합니다.")

            # 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:
            self.textEdit.setText("입력값은 숫자가 아닙니다. 숫자를 입력하여 주시기 바랍니다.")


    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}")

  

    # def main(self):

    #     # present_value = self.lineEdit.text()
    #     # print(present_value, type(present_value))
    #     fromCurrency = self.comboBox.currentText()
    #     toCurrency = self.comboBox_2.currentText()


    #     # lineEdit에 값이 있는 경우
    #     if self.lineEdit.text() and not self.lineEdit_2.text():
    #         present_value = self.lineEdit.text()
    #         if re.match(r'^-?\d+(?:\.\d+)?$', present_value):
    #             present_value = float(present_value)
    #             rate, last_updated = self.get_exchange_rate(fromCurrency, toCurrency)
    #             converted_value = present_value * rate
    #             self.lineEdit_2.setText(f"{converted_value:.6f}")
    #             self.update_result_text(present_value, converted_value, rate, fromCurrency, toCurrency, last_updated)
    #         else:
    #             self.textEdit.setText("입력값은 숫자가 아닙니다. 숫자를 입력하여 주시기 바랍니다.")

    #     # lineEdit_2에 값이 있는 경우
    #     elif self.lineEdit_2.text() and not self.lineEdit.text():
    #         present_value = self.lineEdit_2.text()
    #         if re.match(r'^-?\d+(?:\.\d+)?$', present_value):
    #             present_value = float(present_value)
    #             rate, last_updated = self.get_exchange_rate(toCurrency, fromCurrency)  # 주의: 통화 순서 변경
    #             converted_value = present_value * rate
    #             self.lineEdit.setText(f"{converted_value:.6f}")
    #             self.update_result_text(present_value, converted_value, 1/rate, toCurrency, fromCurrency, last_updated)
    #         else:
    #             self.textEdit.setText("입력값은 숫자가 아닙니다. 숫자를 입력하여 주시기 바랍니다.")

    #     else:
    #         self.textEdit.setText("하나의 입력 필드에만 값을 입력해 주세요.")
        

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

 

 

 

소스파일 : 4_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]

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

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


        ###############################################################
        # 클릭하지 않고 변경되면 실행하도록 수정
        ###############################################################
        # self.pushButton.clicked.connect(self.main)
         # 이벤트 핸들러 연결
        # self.pushButton.clicked.connect(self.calculate)
        self.comboBox.currentIndexChanged.connect(self.calculate)
        self.comboBox_2.currentIndexChanged.connect(self.calculate)
        self.lineEdit.textChanged.connect(self.calculate)
        self.lineEdit_2.textChanged.connect(self.calculate)
        ###############################################################


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

        # lineEdit에 값이 있는 경우
        if self.lineEdit.text() and not self.lineEdit_2.text():
            print("lineEdit에 값이 존재하고, lineEdit_2에 값이 존재하지 않습니다.")
            self.textEdit.setText("lineEdit에 값이 존재하고, lineEdit_2에 값이 존재하지 않습니다.")

            self.convert_currency(self.lineEdit, self.lineEdit_2, fromCurrency, toCurrency)

        # lineEdit_2에 값이 있는 경우
        elif self.lineEdit_2.text() and not self.lineEdit.text():
            print("lineEdit에 값이 존재하고, lineEdit_2에 값이 존재하지 않습니다.")
            self.textEdit.setText("lineEdit에 값이 존재하지 않고, lineEdit_2에 값이 존재합니다.")

            # 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:
            self.textEdit.setText("입력값은 숫자가 아닙니다. 숫자를 입력하여 주시기 바랍니다.")


    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}")

  

    # def main(self):

    #     # present_value = self.lineEdit.text()
    #     # print(present_value, type(present_value))
    #     fromCurrency = self.comboBox.currentText()
    #     toCurrency = self.comboBox_2.currentText()


    #     # lineEdit에 값이 있는 경우
    #     if self.lineEdit.text() and not self.lineEdit_2.text():
    #         present_value = self.lineEdit.text()
    #         if re.match(r'^-?\d+(?:\.\d+)?$', present_value):
    #             present_value = float(present_value)
    #             rate, last_updated = self.get_exchange_rate(fromCurrency, toCurrency)
    #             converted_value = present_value * rate
    #             self.lineEdit_2.setText(f"{converted_value:.6f}")
    #             self.update_result_text(present_value, converted_value, rate, fromCurrency, toCurrency, last_updated)
    #         else:
    #             self.textEdit.setText("입력값은 숫자가 아닙니다. 숫자를 입력하여 주시기 바랍니다.")

    #     # lineEdit_2에 값이 있는 경우
    #     elif self.lineEdit_2.text() and not self.lineEdit.text():
    #         present_value = self.lineEdit_2.text()
    #         if re.match(r'^-?\d+(?:\.\d+)?$', present_value):
    #             present_value = float(present_value)
    #             rate, last_updated = self.get_exchange_rate(toCurrency, fromCurrency)  # 주의: 통화 순서 변경
    #             converted_value = present_value * rate
    #             self.lineEdit.setText(f"{converted_value:.6f}")
    #             self.update_result_text(present_value, converted_value, 1/rate, toCurrency, fromCurrency, last_updated)
    #         else:
    #             self.textEdit.setText("입력값은 숫자가 아닙니다. 숫자를 입력하여 주시기 바랍니다.")

    #     else:
    #         self.textEdit.setText("하나의 입력 필드에만 값을 입력해 주세요.")
        

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

 

 

 

 

소스파일 : 4_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]

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

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


        ###############################################################
        # 클릭하지 않고 변경되면 실행하도록 수정
        ###############################################################
        # self.pushButton.clicked.connect(self.main)
         # 이벤트 핸들러 연결
        # self.pushButton.clicked.connect(self.calculate)
        self.comboBox.currentIndexChanged.connect(self.calculate)
        self.comboBox_2.currentIndexChanged.connect(self.calculate)
        self.lineEdit.textChanged.connect(self.calculate)
        self.lineEdit_2.textChanged.connect(self.calculate)
        ###############################################################


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

        # lineEdit에 값이 있는 경우
        if self.lineEdit.text() and not self.lineEdit_2.text():
            print("lineEdit에 값이 존재하고, lineEdit_2에 값이 존재하지 않습니다.")
            self.textEdit.setText("lineEdit에 값이 존재하고, lineEdit_2에 값이 존재하지 않습니다.")

            self.convert_currency(self.lineEdit, self.lineEdit_2, fromCurrency, toCurrency)

        # lineEdit_2에 값이 있는 경우
        elif self.lineEdit_2.text() and not self.lineEdit.text():
            print("lineEdit에 값이 존재하고, lineEdit_2에 값이 존재하지 않습니다.")
            self.textEdit.setText("lineEdit에 값이 존재하지 않고, lineEdit_2에 값이 존재합니다.")

            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:
            self.textEdit.setText("입력값은 숫자가 아닙니다. 숫자를 입력하여 주시기 바랍니다.")


    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}")

  

    # def main(self):

    #     # present_value = self.lineEdit.text()
    #     # print(present_value, type(present_value))
    #     fromCurrency = self.comboBox.currentText()
    #     toCurrency = self.comboBox_2.currentText()


    #     # lineEdit에 값이 있는 경우
    #     if self.lineEdit.text() and not self.lineEdit_2.text():
    #         present_value = self.lineEdit.text()
    #         if re.match(r'^-?\d+(?:\.\d+)?$', present_value):
    #             present_value = float(present_value)
    #             rate, last_updated = self.get_exchange_rate(fromCurrency, toCurrency)
    #             converted_value = present_value * rate
    #             self.lineEdit_2.setText(f"{converted_value:.6f}")
    #             self.update_result_text(present_value, converted_value, rate, fromCurrency, toCurrency, last_updated)
    #         else:
    #             self.textEdit.setText("입력값은 숫자가 아닙니다. 숫자를 입력하여 주시기 바랍니다.")

    #     # lineEdit_2에 값이 있는 경우
    #     elif self.lineEdit_2.text() and not self.lineEdit.text():
    #         present_value = self.lineEdit_2.text()
    #         if re.match(r'^-?\d+(?:\.\d+)?$', present_value):
    #             present_value = float(present_value)
    #             rate, last_updated = self.get_exchange_rate(toCurrency, fromCurrency)  # 주의: 통화 순서 변경
    #             converted_value = present_value * rate
    #             self.lineEdit.setText(f"{converted_value:.6f}")
    #             self.update_result_text(present_value, converted_value, 1/rate, toCurrency, fromCurrency, last_updated)
    #         else:
    #             self.textEdit.setText("입력값은 숫자가 아닙니다. 숫자를 입력하여 주시기 바랍니다.")

    #     else:
    #         self.textEdit.setText("하나의 입력 필드에만 값을 입력해 주세요.")
        

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

 

 

 

 

 

 

 

 

O 소스 실행 방법

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

 

 


 
 

O 주요 내용

 

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

 

 

소스 파일 : 4_1.py

실행버튼을 누르지 않고, 변경이 발생하면(즉, change이벤트 발생 시) 바로 환율 변환값이 적용되도록 하는 소스입니다.

line 32~33 : 콤보박스는 currentIndexChange 속성을 이용하여 변경시 이벤트를 처리할 수 있습니다.(소스에서는 calculate메서드 호출)

line 34~35 : 라인에디터(lineEdit)는 textChanged 속성을 이용하여 무언가 입력/삭제시 이벤트를 처리할 수 있습니다. (소스에서는 calculate메서드 호출)

line 39 : calcuate()함수는 여기서는 라인에디트에 값이 존재하는지 여부만 체크하고 있습니다.

 

 

 

 

 

소스 파일 : 4_2.py

이 소스는 다른 내용은 이전과 동일하고 환율 변환 함수(convert_currency())를 호출하는 부분만 다릅니다.

line 48 : lineEdit에만 값이 있는 경우 입력된 값을 인자로 환율 변환을 위해 convert_currency()함수를 호출합니다.

 

 

line 65~69 : convert_currency()함수는 실제 환율을 계산하는 get_exchange_rate()를 다시 호출하여 계산 후, update_result_text()함수를 호출하여 계산된 환율 정보를 textEdit(실행결과 화면)에 뿌려줍니다.

line 68 : 한쪽의 입력상자에 값 입력 시 다른 입력상자에 환율 변환 정보를 넣어줍니다.

 

 

 

 

 

 

 

소스 파일 : 4_3.py

line 55만 추가되었으며, 사실상 4_2.py와 내용이 동일합니다.

line 55 : lineEdit_2에만 값이 있는 경우 그 값을 기준으로 반대편 입력박스에 자동으로 환율 변환 값을 입력합니다.

 

 

 

 

 


 

ㅁ 정리

 

O 우리가 배운 내용

 
 - 오늘은 실행버튼을 클릭하지 않고, 무엇가 값이 바뀌었을때(change 이벤트) 환율이 자동적으로 계산되는 방법을 알아 보았습니다.
 
 

 

오늘은 여기까지이며, 위의 내용이 유익하셨다면, 광고 한번씩만 클릭 부탁드립니다.

 

 

감사합니다.

728x90
반응형
LIST