From 60f4d5cc4f005aff98f56cb4be662ab98895123b Mon Sep 17 00:00:00 2001 From: Envy_PC Date: Thu, 12 Sep 2024 13:08:57 +0900 Subject: [PATCH] =?UTF-8?q?=EC=88=98=EC=A0=95=EC=A4=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 7 +- config.json | 4 +- delv.py | 272 ++++++++++++++++++++++------------------ requirements.txt | Bin 966 -> 1004 bytes search_history.json | 2 +- setup.py | 2 +- src/OptionTranslator.py | 110 ++++++++++++++++ src/currencyInfo.py | 63 ---------- src/kiprisEvent.py | 16 +++ src/kipris_settingUI.py | 1 - src/result_widget.py | 9 ++ 11 files changed, 295 insertions(+), 191 deletions(-) create mode 100644 src/OptionTranslator.py delete mode 100644 src/currencyInfo.py create mode 100644 src/kiprisEvent.py diff --git a/.gitignore b/.gitignore index 45528fa..4d718ff 100644 --- a/.gitignore +++ b/.gitignore @@ -7,4 +7,9 @@ build/ *.log *.log.* pyvenv.cfg -search_history.json \ No newline at end of file +search_history.json +# user_data 디렉터리 무시 +user_data/ + +# user_data/Default/Extensions 디렉터리만 추적 +!user_data/Default/Extensions/ diff --git a/config.json b/config.json index f215ed7..1f2b8ed 100644 --- a/config.json +++ b/config.json @@ -5,8 +5,8 @@ "maxVolumeSet": 160, "addFeeInterval": 5, "addFeeSetting": 20, - "addFee": 1000, - "fontSize": 12, + "addFee": 5000, + "fontSize": 13, "weightInterval": 0.5, "setSaveSetting": true, "favoriteDelv": "\ub178\ube60\uafb8\ud574\uc6b4(\ubc30\uc1a1\ube44)" diff --git a/delv.py b/delv.py index ec52d67..aa5cbe4 100644 --- a/delv.py +++ b/delv.py @@ -1,9 +1,11 @@ import sys import configparser -import os +import os, signal import pandas as pd import logging from PyQt5.QtCore import Qt +from qasync import QEventLoop # qasync 이벤트 루프 임포트 + from PyQt5 import QtWidgets, QtCore from PyQt5.QtGui import QFont import re, json @@ -15,8 +17,12 @@ from src.kipris_api_from_publicdata import Kipris_API # from src.kipris_web_from_playwright import Kipris_WEB from src.kiprisThread import * # from src.search_display import TrademarkSearchDisplay +from src.OptionTranslator import optionTrans from src.result_widget import ResultWidget -from src.currencyInfo import ExchangeRateScraper +from forex_python.converter import CurrencyRates +from currency_converter import CurrencyConverter +from src.kiprisEvent import LineEditWithHistory +from qfluentwidgets import IndeterminateProgressRing, setTheme, toggleTheme, Theme # def minimize_console(): # """ 콘솔 창을 최소화하는 함수 """ @@ -32,6 +38,9 @@ class DeliveryFeeCalculator(QtWidgets.QWidget): # self.config = configparser.ConfigParser() self.config_path = 'config.ini' + self.is_dark_theme = False # 다크 테마 상태 저장 + self.dialogs = [] # 열린 다이얼로그와 창들을 저장할 리스트 + self.use_kipris = False self.usage_mode = "web" self.api_key = "" @@ -43,6 +52,7 @@ class DeliveryFeeCalculator(QtWidgets.QWidget): self.web_scraper = None # 웹방식 Playwright 객체 미리 초기화 self.currentURL = "" self.config_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'config.json') + self.history_model = QtCore.QStringListModel() self.maxWeightSet = 25 self.maxLengthSet = 100 @@ -64,7 +74,10 @@ class DeliveryFeeCalculator(QtWidgets.QWidget): self.currentCurrency = None # self.searchDisplay = TrademarkSearchDisplay() self.searchDisplayWidget = ResultWidget() - self.currencyInfoObject = ExchangeRateScraper() + self.currencyInfo = CurrencyRates() + self.currencyConv = CurrencyConverter() + + self.favoriteDelv = "" @@ -110,14 +123,39 @@ class DeliveryFeeCalculator(QtWidgets.QWidget): self.settingDialog = SettingsDialog(parent=self, initial_settings=self.user_settings) - currencis = ['USD','CNY'] - self.currencyInfoObject.getCurrency(currencis) - self.setUSD = self.currencyInfoObject.currencyInfo['USD']['basePrice'] - logger.debug(f"setUSD : {self.setUSD}") - self.setCNY = self.currencyInfoObject.currencyInfo['CNY']['basePrice'] - logger.debug(f"setCNY : {self.setCNY}") + currencis = ['USD', 'CNY'] + try: + # CurrencyConverter로 환율 정보 가져오기 + self.setUSD = int(self.currencyConv.convert(1, 'USD', 'KRW')) + logger.debug(f"CurrencyConverter USD to KRW: {self.setUSD}") + + self.setCNY = int(self.currencyConv.convert(1, 'CNY', 'KRW')) + logger.debug(f"CurrencyConverter CNY to KRW: {self.setCNY}") + except Exception as e: + logger.error(f"CurrencyConverter 에서 환율 조회 중 에러발생: {e}") + print(f"CurrencyConverter 에러, forex-python에서 값을 가져옵니다.") + + try: + # forex-python으로 환율 정보 가져오기 + self.setUSD = int(self.currencyRates.get_rate('USD', 'KRW')) + logger.debug(f"forex-python USD to KRW: {self.setUSD}") + + self.setCNY = int(self.currencyRates.get_rate('CNY', 'KRW')) + logger.debug(f"forex-python CNY to KRW: {self.setCNY}") + except Exception as e2: + logger.error(f"forex-python 에서 환율 조회 중 에러발생: {e2}") + print(f"forex-python 에러, 기본값을 사용합니다.") + + # 기본 환율 설정 + self.setUSD = 1350 + self.setCNY = 195 + logger.debug(f"기본 USD: {self.setUSD}, 기본 CNY: {self.setCNY}") + + # 현재 통화를 CNY로 설정 self.currentCurrency = self.setCNY + + def saveSettings(self): """ 설정을 JSON 파일에 저장합니다. """ try: @@ -208,111 +246,35 @@ class DeliveryFeeCalculator(QtWidgets.QWidget): logger.info("기본 설정이 생성되었습니다.") - # def loadSettings_ini(self): - # """ 설정 파일을 불러옵니다. """ - # try: - # if not os.path.exists(self.config_path): - # self.create_default_settings() - # self.config.read(self.config_path) - - # self.maxWeightSet = self.config.getint('Settings', 'maxWeightSet', fallback=25) - # self.maxLengthSet = self.config.getint('Settings', 'maxLengthSet', fallback=100) - # self.maxVolumeSet = self.config.getint('Settings', 'maxVolumeSet', fallback=160) - # self.addFeeInterval = self.config.getint('Settings', 'addFeeInterval', fallback=5) - # self.addFeeSetting = self.config.getint('Settings', 'addFeeSetting', fallback=20) - # self.addFee = self.config.getint('Settings', 'addFee', fallback=1000) - # self.fontSize = self.config.getint('Settings', 'fontSize', fallback=14) - # self.weightInterval = self.config.getfloat('Settings', 'weightInterval', fallback=0.5) - # self.setSaveSetting = self.config.getboolean('Settings', 'setSaveSetting', fallback=False) - # self.favoriteDelv = self.config.get('Settings', 'favoriteDelv', fallback="노빠꾸해운(배송비)") - # self.use_kipris = self.config.getboolean('Kipris', 'use_Kipris', fallback=False) - # self.usage_mode = self.config.get('Kipris', 'usage_mode', fallback="web") - # self.api_key = self.config.get('Kipris', 'api_key', fallback="") - # self.set_status = self.config.get('Kipris', 'set_status', fallback="[등록]") - # # logger.debug(f"use_kipris : {self.use_kipris}, usage_mode : {self.usage_mode}, api_key : {self.api_key}") - # except Exception as e: - # logger.error(f"설정을 불러오는 중 오류가 발생했습니다: {e}", exc_info=True) - - # def saveSettings_ini(self): - # """ 설정을 config.ini 파일에 저장합니다. """ - # try: - # if not self.config.has_section('Settings'): - # self.config.add_section('Settings') - - # self.config.set('Settings', 'maxWeightSet', str(self.maxWeightSet)) - # self.config.set('Settings', 'maxLengthSet', str(self.maxLengthSet)) - # self.config.set('Settings', 'maxVolumeSet', str(self.maxVolumeSet)) - # self.config.set('Settings', 'addFeeInterval', str(self.addFeeInterval)) - # self.config.set('Settings', 'addFeeSetting', str(self.addFeeSetting)) - # self.config.set('Settings', 'addFee', str(self.addFee)) - # self.config.set('Settings', 'fontSize', str(self.fontSize)) - # self.config.set('Settings', 'weightInterval', str(self.weightInterval)) - # self.config.set('Settings', 'setSaveSetting', str(self.setSaveSetting)) - # self.config.set('Settings', 'favoriteDelv', str(self.favoriteDelv)) - - # if not self.config.has_section('Kipris'): - # self.config.add_section('Kipris') - - # self.config.set('Kipris', 'use_kipris', str(self.use_kipris)) - # self.config.set('Kipris', 'usage_mode', str(self.usage_mode)) - # self.config.set('Kipris', 'api_key', str(self.api_key)) - # self.config.set('Kipris', 'set_status', str(self.set_status)) - - # with open(self.config_path, 'w') as configfile: - # self.config.write(configfile) - # except Exception as e: - # logger.error(f"설정을 저장하는 중 오류가 발생했습니다: {e}", exc_info=True) - - - # def create_default_settings_ini(self): - # """ 기본 설정을 생성합니다. """ - # self.config['Settings'] = { - # 'maxWeightSet': '25', - # 'maxLengthSet': '100', - # 'maxVolumeSet': '160', - # 'addFeeInterval': '5', - # 'addFeeSetting': '20', - # 'addFee': '1000', - # 'fontSize': '14', - # 'weightInterval': '0.5', - # 'setSaveSetting': 'False', - # 'favoriteDelv': "노빠꾸해운(배송비)", - # } - # self.config['Kipris'] = { - # 'use_kipris': 'False', - # 'usage_mode': 'web', - # 'api_key': '', - # 'set_status': '[등록]', - # } - - # with open(self.config_path, 'w') as configfile: - # self.config.write(configfile) - - def add_history(self, keyword) : + def add_history(self, keyword): if keyword: - if keyword and keyword not in self.history: # 중복된 검색어가 아니면 추가 - self.history.append(keyword) + current_history = self.history_model.stringList() + if keyword not in current_history: # 중복된 검색어가 아니면 추가 + current_history.append(keyword) + self.history_model.setStringList(current_history) logger.debug(f"검색어 [{keyword}] 히스토리에 추가") def load_history(self): try: with open("search_history.json", "r") as file: - self.history = json.load(file) - logger.debug(f"self.history file loaded{self.history}") + history_list = json.load(file) + self.history_model.setStringList(history_list) + logger.debug(f"self.history file loaded: {history_list}") except (FileNotFoundError, json.JSONDecodeError): - self.history = [] - logger.debug(f"self.history{self.history}") + self.history_model.setStringList([]) + logger.debug(f"self.history: []") def save_history(self): with open("search_history.json", "w") as file: - json.dump(self.history, file) - + json.dump(self.history_model.stringList(), file) + def show_history_menu(self, event): - if self.history: + current_history = self.history_model.stringList() + if current_history: menu = QtWidgets.QMenu(self) - for keyword in self.history: + for keyword in current_history: menu.addAction(keyword, lambda k=keyword: self.kipris_edit.setText(k)) menu.exec_(self.kipris_edit.mapToGlobal(event.pos())) @@ -334,6 +296,16 @@ class DeliveryFeeCalculator(QtWidgets.QWidget): # 이벤트 처리 완료를 알림 event.accept() + # 프로그램 완전히 종료 + QtWidgets.QApplication.quit() # Qt 애플리케이션 종료 + + # 프로세스 강제 종료 (필요 시 사용) + os.kill(os.getpid(), signal.SIGTERM) + + def add_dialog(self, dialog): + """열린 다이얼로그나 창을 리스트에 추가""" + self.dialogs.append(dialog) + def initUI(self): self.resize(300, 600) # 창 크기 조정 self.center() @@ -610,11 +582,28 @@ class DeliveryFeeCalculator(QtWidgets.QWidget): self.kiprisWidget.setLayout(self.kipris_layout) self.kiprisWidget.setVisible(False) self.kipris_label = QtWidgets.QLabel(f"키프리스 검색") + + self.kipris_completer = QtWidgets.QCompleter(self.history_model, self) + self.kipris_completer.setCaseSensitivity(Qt.CaseInsensitive) + self.kipris_completer.setCompletionMode(QtWidgets.QCompleter.PopupCompletion) + self.kipris_edit = QtWidgets.QLineEdit() + self.kipris_edit = LineEditWithHistory(self.kipris_completer, self) + self.kipris_edit.setCompleter(self.kipris_completer) + self.kipris_btn = QtWidgets.QPushButton("검색") self.kipris_btn.clicked.connect(self.kipris_btn_clicked) self.kipris_edit.returnPressed.connect(self.kipris_btn_clicked) - self.kipris_edit.mousePressEvent = self.show_history_menu + + self.spinner = IndeterminateProgressRing(self) + self.spinner.setFixedSize(50, 50) + self.spinner.setVisible(False) + self.kipris_layout.addWidget(self.spinner) + + + + + # self.kipris_edit.mousePressEvent = self.show_history_menu self.kipris_layout.addWidget(self.kipris_label) self.kipris_layout.addWidget(self.kipris_edit) self.kipris_layout.addWidget(self.kipris_btn) @@ -661,9 +650,18 @@ class DeliveryFeeCalculator(QtWidgets.QWidget): self.addInfo3_btn.clicked.connect(self.addInfo3_btn_clicked) self.addInfo_h2layout.addWidget(self.addInfo3_btn) self.addInfo4_btn = QtWidgets.QPushButton("딥러닝번역") - self.addInfo4_btn.setEnabled(False) + self.addInfo4_btn.setEnabled(True) self.addInfo4_btn.clicked.connect(self.addInfo4_btn_clicked) self.addInfo_h2layout.addWidget(self.addInfo4_btn) + + + # 다크 테마 토글 버튼 추가 + self.theme_button = QtWidgets.QPushButton("Dark Theme", self) + self.theme_button.setEnabled(False) + self.theme_button.clicked.connect(self.toggle_theme) + self.addInfo_h2layout.addWidget(self.theme_button, 0, Qt.AlignHCenter) + + # self.addInfo_layout.setStretch(0,3) # self.addInfo_layout.setStretch(1,6) # self.addInfo_layout.setStretch(2,3) @@ -727,25 +725,24 @@ class DeliveryFeeCalculator(QtWidgets.QWidget): self.setWindowTitle('배송비 계산기') - # def initSettings_for_kipris_ori(self): - # if self.kiprisAPI: - # # 현재 객체가 적절한 타입인지 확인 - # current_type = type(self.kiprisAPI) - # target_type = Kipris_API if self.usage_mode == 'api' else Kipris_WEB - - # if current_type is not target_type: - # # 기존 객체가 다른 타입이면 삭제하고 새로 생성 - # logger.debug(f"기존 {self.kiprisAPI} 객체를 삭제하고 새 객체를 생성합니다.") - # self.kiprisAPI.close_Kipris() # 기존객체 리소스 정리 - # del self.kiprisAPI # 기존 객체 참조 제거 - # self.kiprisAPI = target_type(self.api_key) # 새 객체 생성 - # logger.debug(f"{self.usage_mode.upper()} 방식 kiprisAPI 객체 생성: {self.kiprisAPI}") - # else: - # logger.debug(f"기존에 적절한 {self.kiprisAPI} 객체가 이미 존재합니다.") - # else: - # # 객체가 없으면 새로 생성 - # self.kiprisAPI = Kipris_API(self.api_key) if self.usage_mode == 'api' else Kipris_WEB(self.api_key) - # logger.debug(f"{self.usage_mode.upper()} 방식 kiprisAPI 객체 생성: {self.kiprisAPI}") + def toggle_theme(self): + if self.is_dark_theme: + try: + # setTheme(Theme.LIGHT) + toggleTheme() + print("라이트 토글") + self.is_dark_theme = False + except Exception as e: + print(f"라이트 토글 중 에러 : {e}") + else: + try: + # setTheme(Theme.DARK) + toggleTheme() + + print("다크 토글") + self.is_dark_theme = True + except Exception as e: + print(f"다크 토글 중 에러 : {e}") def initSettings_for_kipris(self): if self.kiprisAPI: @@ -788,7 +785,10 @@ class DeliveryFeeCalculator(QtWidgets.QWidget): pass def addInfo4_btn_clicked(self): - pass + # optionTrans 클래스를 사용해 다이얼로그 창을 띄움 + self.trans_dialog = optionTrans(self) + self.trans_dialog.show() + self.add_dialog(self.trans_dialog) # 열린 다이얼로그를 리스트에 추가 def showSettingsDialog(self): @@ -797,6 +797,7 @@ class DeliveryFeeCalculator(QtWidgets.QWidget): self.usage_mode = self.settingDialog.usage_mode self.api_key = self.settingDialog.api_key self.set_status = self.settingDialog.set_status + self.add_dialog(self.settingDialog) # 열린 다이얼로그를 리스트에 추가 self.kipris_Visible() @@ -1142,6 +1143,8 @@ class DeliveryFeeCalculator(QtWidgets.QWidget): # logger.debug(f"result {result}") if self.search_keyword.strip(): # 검색어가 비어있지 않은 경우에만 검색 수행 + self.spinner.setVisible(True) # Show spinner + logger.debug(f"검색 호출방식 : {self.usage_mode}") if self.usage_mode == 'web': self.handle_search_for_web(self.search_keyword) @@ -1163,6 +1166,9 @@ class DeliveryFeeCalculator(QtWidgets.QWidget): # logger.debug(f"result : {result}") searchType = 'web' logger.debug(f"display_results_for_web - currentURL : {self.web_scraper.currentURL}") + self.spinner.setVisible(False) # Hide spinner + self.searchDisplayWidget.clear_results() + self.add_dialog(self.searchDisplayWidget) # 열린 다이얼로그를 리스트에 추가 self.searchDisplayWidget.show_results(result, searchType, elapsed_time, self.web_scraper.currentURL) # self.searchDisplay.display_web_results(result, elapsed_time) @@ -1200,6 +1206,10 @@ class DeliveryFeeCalculator(QtWidgets.QWidget): def display_results_for_api(self, result, elapsed_time): searchType = 'api' logger.debug(f"display_results_for_api result: {result}") + self.spinner.setVisible(False) # Hide spinner + + self.searchDisplayWidget.clear_results() + self.add_dialog(self.searchDisplayWidget) # 열린 다이얼로그를 리스트에 추가 self.searchDisplayWidget.show_results(result, searchType, elapsed_time) message = f"검색 결과 : {result}\n검색에 걸린 시간: {elapsed_time:.1f}초" # QtWidgets.QMessageBox.information(self, "Search Results", message) @@ -1208,6 +1218,7 @@ class DeliveryFeeCalculator(QtWidgets.QWidget): self.lengthInput.setValue(1) self.widthInput.setValue(1) self.heightInput.setValue(1) + self.weightInput.setValue(1) def showHelp(self): # 도움말 내용 표시 @@ -1238,9 +1249,26 @@ class DeliveryFeeCalculator(QtWidgets.QWidget): if __name__ == '__main__': # minimize_console() + # enable dpi scale + QtWidgets.QApplication.setHighDpiScaleFactorRoundingPolicy( + Qt.HighDpiScaleFactorRoundingPolicy.PassThrough) + QtWidgets.QApplication.setAttribute(Qt.AA_EnableHighDpiScaling) + QtWidgets.QApplication.setAttribute(Qt.AA_UseHighDpiPixmaps) + + app = QtWidgets.QApplication(sys.argv) + + # qasync 이벤트 루프를 생성하여 PyQt5의 이벤트 루프와 결합 + loop = QEventLoop(app) + asyncio.set_event_loop(loop) # asyncio의 이벤트 루프를 qasync로 설정 + + app.setStyle('Fusion') logger = setup_logger('default_logger', 'delivery_calc.log', level=logging.DEBUG) ex = DeliveryFeeCalculator(logger) ex.show() + # 이벤트 루프 시작 + with loop: + loop.run_forever() + sys.exit(app.exec_()) diff --git a/requirements.txt b/requirements.txt index 3c3ac2d096ef4ef349880dd42865fcadce224c83..33bc5234cf3122ce539f1027796e9cb607f22d05 100644 GIT binary patch delta 46 xcmX@c{)T