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

환율 계산기 만들기 - 5. GUI 환율 계산기 - 실행버튼 없이 실행(엔터시 실행)

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

ㅁ 개요

 

O 프로젝트 소개

 

 

 - 이번 글은 이전글(

2024.07.07 - [파이썬 프로젝트 강좌(초급)/환율 계산기] - 환율 계산기 만들기 - 4. GUI 환율 계산기 - 실행버튼 없이 실행(change 이벤트))에 이은 6번째 글로 아래 2가지로 프로그램을 개선하는 방법에 대하여 알아 보겠습니다.

1. 실행버튼을 클릭하지 않고, change이벤트가 발생 시 실행하되, 여기서는 변경 발생 후 1초 후에 실행되도록 시간 딜레이를 주어 보겠습니다.

2.위의 경우 여러가지 문제점이 있으므로 시간 딜레이 대신 엔터 이벤트가 발생한 경우 실행되도록 수정해 보고, 눈에 띄도록 환율 계산 결과의 색상을 바꿔 보도록 하겠습니다.

 

 

 

 

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

 

 

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

 

 

1. 5_1.py 실행 후 lineEdit에 1입력 시(change이벤트 발생) 1초 후에 lineEdit_2(대상통화 입력란)와 textEdit(실행결과)에 환율정보가 나타납니다.

 

 

 

 

 

 

2. 5_2.py 실행 후 lineEdit에 1입력 후 엔터를 치면 lineEdit_2(대상통화 입력란)와 textEdit(실행결과)에 환율정보가 나타납니다.

 

 

 

3. 5_3.py 실행 후 lineEdit에 1입력 후 엔터를 치면 lineEdit_2(대상통화 입력란)와 textEdit(실행결과)에 환율정보가 색상이 표시되어 나타납니다.

 

 

 

 


 

ㅁ 세부 내용

 

O 완성된 소스

 

소스파일 : 5_1.py

# -*- coding: utf-8 -*-
import sys
from PyQt5.QtWidgets import *
from PyQt5 import uic, QtWidgets
from PyQt5.QtGui import *
from PyQt5.QtCore import QTimer
import os
import re
import requests
import json
from datetime import datetime

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

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

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

        ###################################
        # 타이머 초기화 (값입력 후 2초 후에 환율 표시)
        ###################################
        self.timer = QTimer(self)
        self.timer.setSingleShot(True)
        self.timer.timeout.connect(self.calculate)
        ###################################


        self.comboBox.currentIndexChanged.connect(self.start_timer) ####<---------------------
        self.comboBox_2.currentIndexChanged.connect(self.start_timer)
        self.lineEdit.textChanged.connect(self.start_timer)
        self.lineEdit_2.textChanged.connect(self.start_timer)


    ########### 타이머 초기화 시작 #################
    def start_timer(self):
        self.timer.start(1000)  # 500ms 후에 calculate 함수 호출
    ########### 타이머 초기화 끝 #################

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

        # lineEdit에 값이 있는 경우
        if self.lineEdit.text() and not self.lineEdit_2.text():
            self.convert_currency(self.lineEdit, self.lineEdit_2, fromCurrency, toCurrency)

        # lineEdit_2에 값이 있는 경우
        elif self.lineEdit_2.text() and not self.lineEdit.text():
            self.convert_currency(self.lineEdit_2, self.lineEdit, toCurrency, fromCurrency)

        # 둘 다 값이 있거나 둘 다 값이 없는 경우
        else:
            self.textEdit.setText("하나의 입력 필드에만 값을 입력해 주세요.")

        self.timer.stop() # 타이머를 멈추지 않으면 2초 후 다시 실행됨

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



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

 

 

 

소스파일 : 5_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("exchangeRate2.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.is_clearing = False

        # self.pushButton.clicked.connect(self.main)
         # 이벤트 핸들러 연결
        # self.pushButton.clicked.connect(self.calculate)
        self.comboBox.currentIndexChanged.connect(self.clear_inputs)
        self.comboBox_2.currentIndexChanged.connect(self.clear_inputs)

        ###### 값 입력 후 엔터를 치면 환율 변환 하기 ################
        self.lineEdit.returnPressed.connect(self.calculate)
        self.lineEdit_2.returnPressed.connect(self.calculate)
        ##########################################################


    ############# 라인에디터 및 텍스트 에디터의 내용 삭제 ############
    def clear_inputs(self):
        self.lineEdit.clear()
        self.lineEdit_2.clear()
        self.textEdit.clear()


    def calculate(self):
        # if self.is_clearing: # 초기화 중이면 함수 종료
        #     return
        fromCurrency = self.comboBox.currentText()
        toCurrency = self.comboBox_2.currentText()

        # lineEdit에 값이 있는 경우
        if self.lineEdit.text() and not self.lineEdit_2.text():
            self.convert_currency(self.lineEdit, self.lineEdit_2, fromCurrency, toCurrency)

        # lineEdit_2에 값이 있는 경우
        elif self.lineEdit_2.text() and not self.lineEdit.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)
            
            #  계산 후 입력 필드 초기화
            # self.is_clearing = True  # 초기화 시작
            ##### 텍스트 에디터에 뿌려주고 라인에디터는 클리어 ##############
            self.lineEdit.clear()  
            self.lineEdit_2.clear()
            # self.is_clearing = False  # 초기화 종료
        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}")
        

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

 

 

 

소스파일 : 5_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("exchangeRate2.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.is_clearing = False

        # self.pushButton.clicked.connect(self.main)
         # 이벤트 핸들러 연결
        # self.pushButton.clicked.connect(self.calculate)
        self.comboBox.currentIndexChanged.connect(self.clear_inputs)
        self.comboBox_2.currentIndexChanged.connect(self.clear_inputs)

        self.lineEdit.returnPressed.connect(self.calculate)
        self.lineEdit_2.returnPressed.connect(self.calculate)

    def clear_inputs(self):
        self.lineEdit.clear()
        self.lineEdit_2.clear()
        self.textEdit.clear()


    def calculate(self):
        # if self.is_clearing: # 초기화 중이면 함수 종료
        #     return
        fromCurrency = self.comboBox.currentText()
        toCurrency = self.comboBox_2.currentText()

        # lineEdit에 값이 있는 경우
        if self.lineEdit.text() and not self.lineEdit_2.text():
            self.convert_currency(self.lineEdit, self.lineEdit_2, fromCurrency, toCurrency)

        # lineEdit_2에 값이 있는 경우
        elif self.lineEdit_2.text() and not self.lineEdit.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)
            
            #  계산 후 입력 필드 초기화
            # self.is_clearing = True  # 초기화 시작
            self.lineEdit.clear()  
            self.lineEdit_2.clear()
            # self.is_clearing = False  # 초기화 종료
        else:
            self.textEdit.setText("입력값은 숫자가 아닙니다. 숫자를 입력하여 주시기 바랍니다.")


    def update_result_text(self, input_value, output_value, rate, from_currency, to_currency, last_updated):
    # 빨간색으로 변경된 부분
    #################### 색상(<font>) 및 엔터(<br>)를 넣어 줌 ####################
        result_text = f"<font color='red'>{input_value:,.6f}</font> {from_currency}는 <font color='red'>{output_value:,.6f}</font> {to_currency} 입니다."
        result_text += f"<br><br>환율: <font color='red'>1</font> {from_currency} = <font color='red'>{rate:,.6f}</font> {to_currency}"
        result_text += f"<br>마지막 업데이트: {last_updated}"
        self.textEdit.setHtml(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 5_1.py
 > python 5_2.py
 > python 5_3.py
 

 

 


 
 

O 주요 내용

 

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

 

 

소스 파일 : 5_1.py

값 입력 등의 변경 발생 시 환율을 계산하여 보여줍니다.

 

소스코드 설명은 아래 화면을 참고 바랍니다.

 

 

 

 

 

 

 

 

 

소스 파일 : 5_2.py

콤보박스가 변경되면 값을 기존 값을 삭제하고, 엔터를 치면 calculate()메소드가 실행되어 환율을 계산 후 textEdit에 뿌려줍니다.

 

소스코드 설명은 아래 화면을 참고 바랍니다.

 

 

 

 

 

 

소스 파일 : 5_3.py

결과 화면을 좀 더 보기 좋게 하기위하여 색상을 넣고 있습니다.

 

소스코드 설명은 아래 화면을 참고 바랍니다.

 

 


 

ㅁ 정리

 

O 우리가 배운 내용

 
 - 오늘은아래 2가지로 프로그램을 개선하는 방법에 대하여 알아 보았습니다.

1. 실행버튼을 클릭하지 않고, change이벤트가 발생 시 실행하되, 여기서는 변경 발생 후 1초 후에 실행되도록 시간 딜레이를 주었습니다.

2.위의 경우 여러가지 문제점이 있으므로 시간 딜레이 대신 엔터 이벤트가 발생한 경우 실행되도록 수정해 보고, 눈에 띄도록 환율 계산 결과의 색상을 바꾸어 보았습니다.

 

 

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

 

 

감사합니다.

728x90
반응형
LIST