import sys import configparser 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 from src.toggleSwitch import ToggleSwitch # toggleSwitch.py 파일에서 ToggleSwitch 클래스를 임포트 from src.logger_module import setup_logger import ctypes from src.kipris_settingUI import SettingsDialog 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 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(): # """ 콘솔 창을 최소화하는 함수 """ # hwnd = ctypes.windll.kernel32.GetConsoleWindow() # if hwnd != 0: # ctypes.windll.user32.ShowWindow(hwnd, 6) # SW_MINIMIZE class DeliveryFeeCalculator(QtWidgets.QWidget): def __init__(self, logger): super().__init__() self.logger = logger # 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 = "" self.kiprisAPI = None self.searchThread = None # 스레드 객체를 저장할 멤버 변수 추가 self.asyncWorker = None self.search_keyword = None self.set_status =[] 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 self.maxVolumeSet = 160 self.currentMaxLength = 1 self.roundVolume = 1 self.currentWeight = 1 self.currentVolume = 1 self.fontSize = 14 self.weightInterval = 0.5 self.setSaveSetting = True self.addFee = 1000 self.addFeeSetting = 20 self.addFeeInterval = 5 self.setUSD = None self.setCNY = None self.currentCurrency = None # self.searchDisplay = TrademarkSearchDisplay() self.searchDisplayWidget = ResultWidget() self.currencyInfo = CurrencyRates() self.currencyConv = CurrencyConverter() self.favoriteDelv = "" self.cargo_font = QFont() self.cargo_font_size = self.fontSize + 2 self.deliveryFees = {} self.initSettings() self.initUI() self.loadDeliveryFees() self.setDefaultValues() self.kipris_Visible() self.setWindowFlags(self.windowFlags() | Qt.WindowStaysOnTopHint) # self.setAddInterval(self.addFeeInterval) # self.setAddMoneySetting(self.addFee) self.setFontSize(self.fontSize) self.font_size_spinbox.setValue(self.fontSize) self.addMoney1_spinbox.setValue(self.addFeeSetting) self.addMoney2_spinbox.setValue(self.addFeeInterval) self.addMoney3_spinbox.setValue(self.addFee) self.saveSettingSwitch.setChecked(self.setSaveSetting) self.step_interval_spinbox.setValue(self.weightInterval) self.maxVolume_spinbox.setValue(self.maxVolumeSet) self.maxWeight_spinbox.setValue(self.maxWeightSet) self.maxLength_spinbox.setValue(self.maxLengthSet) self.setComboBox() def initSettings(self): # self.settings = QtCore.QSettings('When_Ride_Mycar_Tanya', 'DeliveryFeeCalculator') self.loadSettings() self.load_history() self.user_settings = { 'use_kipris': self.use_kipris, 'usage_mode': self.usage_mode, 'api_key': self.api_key, 'set_status': self.set_status, } self.settingDialog = SettingsDialog(parent=self, initial_settings=self.user_settings) 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: settings = { 'Settings': { 'maxWeightSet': self.maxWeightSet, 'maxLengthSet': self.maxLengthSet, 'maxVolumeSet': self.maxVolumeSet, 'addFeeInterval': self.addFeeInterval, 'addFeeSetting': self.addFeeSetting, 'addFee': self.addFee, 'fontSize': self.fontSize, 'weightInterval': self.weightInterval, 'setSaveSetting': self.setSaveSetting, 'favoriteDelv': self.favoriteDelv, }, 'Kipris': { 'use_kipris': self.use_kipris, 'usage_mode': self.usage_mode, 'api_key': self.api_key, 'set_status': self.set_status, } } with open(self.config_path, 'w') as config_file: json.dump(settings, config_file, indent=4) logger.info("설정이 성공적으로 저장되었습니다.") except Exception as e: logger.error(f"설정을 저장하는 중 오류가 발생했습니다: {e}", exc_info=True) def loadSettings(self): """ 설정 파일을 불러옵니다. """ try: if not os.path.exists(self.config_path): self.create_default_settings() with open(self.config_path, 'r') as config_file: settings = json.load(config_file) s = settings['Settings'] self.maxWeightSet = s['maxWeightSet'] self.maxLengthSet = s['maxLengthSet'] self.maxVolumeSet = s['maxVolumeSet'] self.addFeeInterval = s['addFeeInterval'] self.addFeeSetting = s['addFeeSetting'] self.addFee = s['addFee'] self.fontSize = s['fontSize'] self.weightInterval = s['weightInterval'] self.setSaveSetting = s['setSaveSetting'] self.favoriteDelv = s['favoriteDelv'] k = settings['Kipris'] self.use_kipris = k['use_kipris'] self.usage_mode = k['usage_mode'] self.api_key = k['api_key'] self.set_status = k['set_status'] logger.info("설정이 성공적으로 불러와졌습니다.") except Exception as e: logger.error(f"설정을 불러오는 중 오류가 발생했습니다: {e}", exc_info=True) def create_default_settings(self): """ 기본 설정을 생성합니다. """ settings = { 'Settings': { 'maxWeightSet': 25, 'maxLengthSet': 100, 'maxVolumeSet': 160, 'addFeeInterval': 5, 'addFeeSetting': 20, 'addFee': 1000, 'fontSize': 14, 'weightInterval': 0.5, 'setSaveSetting': False, 'favoriteDelv': "노빠꾸해운(배송비)" }, 'Kipris': { 'use_kipris': False, 'usage_mode': 'web', 'api_key': '', 'set_status': ['등록'], } } with open(self.config_path, 'w') as config_file: json.dump(settings, config_file, indent=4) logger.info("기본 설정이 생성되었습니다.") def add_history(self, keyword): if 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: 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_model.setStringList([]) logger.debug(f"self.history: []") def save_history(self): with open("search_history.json", "w") as file: json.dump(self.history_model.stringList(), file) def show_history_menu(self, event): current_history = self.history_model.stringList() if current_history: menu = QtWidgets.QMenu(self) for keyword in current_history: menu.addAction(keyword, lambda k=keyword: self.kipris_edit.setText(k)) menu.exec_(self.kipris_edit.mapToGlobal(event.pos())) def closeEvent(self, event): # 설정 저장 여부 로그 기록 if self.setSaveSetting: logger.debug("설정값 저장") self.saveSettings() # 설정 저장 # self.saveWindowSettings() # 필요한 경우 윈도우 설정 저장 else: logger.debug("설정값 저장하지 않음") # 검색 히스토리 저장 self.save_history() # 부모 클래스의 종료 이벤트 처리 호출 super().closeEvent(event) # 이벤트 처리 완료를 알림 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() # 메뉴바 생성 menubar = QtWidgets.QMenuBar(self) helpMenu = menubar.addMenu('도움말') kiprisMenu = menubar.addMenu('키프리스') # 도움말 - 도움말 보기 메뉴 아이템 helpnemu_helpAction = QtWidgets.QAction('도움말 보기', self) helpnemu_helpAction.triggered.connect(self.showHelp) helpMenu.addAction(helpnemu_helpAction) # 도움말 - ChangeLog 메뉴 아이템 helpnemu_changelogAction = QtWidgets.QAction('ChangeLog', self) helpnemu_changelogAction.triggered.connect(self.showChangeLog) helpMenu.addAction(helpnemu_changelogAction) # 도움말 - 기본값 설정 메뉴 아이템 helpnemu_defaultAction = QtWidgets.QAction('기본값 설정', self) helpnemu_defaultAction.triggered.connect(self.setttingTosetDefaultValues) helpMenu.addAction(helpnemu_defaultAction) # # '설정창 열기' 메뉴 아이템 openSettingsAction = QtWidgets.QAction('설정창 열기', self) openSettingsAction.triggered.connect(self.showSettingsDialog) kiprisMenu.addAction(openSettingsAction) # # 키프리스 - APIKEY 메뉴 아이템 # kiprismenu_settingAction = QtWidgets.QAction('키프리스 ', self) # kiprismenu_settingAction.triggered.connect(self.showHelp) # kiprisMenu.addAction(kiprismenu_settingAction) # # 도움말 - ChangeLog 메뉴 아이템 # changelogAction = QtWidgets.QAction('ChangeLog', self) # changelogAction.triggered.connect(self.showChangeLog) # kiprisMenu.addAction(changelogAction) # # 도움말 - 기본값 설정 메뉴 아이템 # defaultAction = QtWidgets.QAction('기본값 설정', self) # defaultAction.triggered.connect(self.setttingTosetDefaultValues) # kiprisMenu.addAction(defaultAction) # 레이아웃 전체 설정 self.layout = QtWidgets.QVBoxLayout(self) self.layout.setMenuBar(menubar) # 사용자 인터페이스 프레임 self.user_frame = QtWidgets.QFrame(self) self.user_frame.setFrameShape(QtWidgets.QFrame.StyledPanel) self.user_frame.setFrameShadow(QtWidgets.QFrame.Raised) self.user_layout = QtWidgets.QVBoxLayout(self.user_frame) # 콤보박스 초기화 self.comboBox = QtWidgets.QComboBox() self.comboBox.currentIndexChanged.connect(self.updateComboBox) # 값이 변경될 때 이벤트 연결 self.user_layout.addWidget(self.comboBox) # 무게입력 박스 초기화 self.weightInput = QtWidgets.QDoubleSpinBox() self.weightInput.setMinimum(0.5) self.weightInput.setMaximum(1000) self.weightInput.setSingleStep(self.weightInterval) self.weightInput.setSuffix(" Kg") self.weightInput.valueChanged.connect(self.updateDeliveryFee) # 값이 변경될 때 이벤트 연결 self.user_layout.addWidget(self.weightInput) # 부피 입력 칸: 가로, 세로, 높이 self.dimension_layout = QtWidgets.QHBoxLayout() # 길이 레이아웃 self.lengthInput = QtWidgets.QSpinBox() self.lengthInput.setMinimum(1) self.lengthInput.setMaximum(10000) self.lengthInput.setSuffix(" cm") self.lengthInput.valueChanged.connect(self.updateVolume) self.lengthInput_layout = self.create_label_and_spin_in_QV("가로(cm):", self.lengthInput) self.dimension_layout.addLayout(self.lengthInput_layout) # 넓이 레이아웃 self.widthInput = QtWidgets.QSpinBox() self.widthInput.setMinimum(1) self.widthInput.setMaximum(10000) self.widthInput.setSuffix(" cm") self.widthInput.valueChanged.connect(self.updateVolume) self.widthInput_layout = self.create_label_and_spin_in_QV("세로(cm):", self.widthInput) self.dimension_layout.addLayout(self.widthInput_layout) # 높이 레이아웃 self.heightInput = QtWidgets.QSpinBox() self.heightInput.setMinimum(1) self.heightInput.setMaximum(10000) self.heightInput.setSuffix(" cm") self.heightInput.valueChanged.connect(self.updateVolume) self.heightInput_layout = self.create_label_and_spin_in_QV("높이(cm):", self.heightInput) self.dimension_layout.addLayout(self.heightInput_layout) # 리셋 레이아웃 self.reset_layout = QtWidgets.QVBoxLayout() self.reset_label = QtWidgets.QLabel("리셋") self.reset_layout.addWidget(self.reset_label) self.reset_button = QtWidgets.QPushButton("Reset") self.reset_label.setAlignment(QtCore.Qt.AlignCenter) self.reset_button.clicked.connect(self.reset_action) self.reset_layout.addWidget(self.reset_button) self.dimension_layout.addLayout(self.reset_layout) self.user_layout.addLayout(self.dimension_layout) # 레이아웃 비율 설정 self.dimension_layout.setStretch(0, 3) # 길이 입력 칸 self.dimension_layout.setStretch(1, 3) # 너비 입력 칸 self.dimension_layout.setStretch(2, 3) # 높이 입력 칸 self.dimension_layout.setStretch(3, 1) # 새로 추가된 리셋 레이아웃 # 사용자 정보 프레임 self.user_info_frame = QtWidgets.QFrame(self) self.user_info_frame.setFrameShape(QtWidgets.QFrame.StyledPanel) self.user_info_frame.setFrameShadow(QtWidgets.QFrame.Sunken) self.user_info_layout = QtWidgets.QVBoxLayout(self.user_info_frame) # 배송비 레이이웃 추가 설정 중 self.final_delv_fee_layout = QtWidgets.QHBoxLayout() self.deliveryFeeLabel = QtWidgets.QLabel("배송비: 정보 없음") self.deliveryFeeADDLabel = QtWidgets.QLabel(f"가중치: {self.addFee}원") self.deliveryFeeADDLabel.setVisible(False) self.final_delv_fee_layout.addWidget(self.deliveryFeeLabel) self.final_delv_fee_layout.addWidget(self.deliveryFeeADDLabel) self.user_info_layout.addLayout(self.final_delv_fee_layout) # 부피 라벨 self.volumeLabel = QtWidgets.QLabel("부피무게: 정보 없음") self.user_info_layout.addWidget(self.volumeLabel) # 크기 라벨 self.maxLengthLabel = QtWidgets.QLabel("한 변의 최대길이 : 정보없음") self.maxLengthLabel.setVisible(False) self.user_info_layout.addWidget(self.maxLengthLabel) # 추가운임 정보 라벨 self.additionalFeeTextLabel = QtWidgets.QLabel("화물택배(경동)추가운임 발생. 모든값은 참고치입니다.") self.additionalFeeTextLabel.setVisible(False) self.user_info_layout.addWidget(self.additionalFeeTextLabel) # 추가운임 라벨 self.additionalFeeLabel = QtWidgets.QLabel("화물택배(경동)추가운임") self.additionalFeeLabel.setVisible(False) self.user_info_layout.addWidget(self.additionalFeeLabel) # 설정 프레임 self.setting_frame = QtWidgets.QFrame(self) self.setting_frame.setFrameShape(QtWidgets.QFrame.StyledPanel) self.setting_frame.setFrameShadow(QtWidgets.QFrame.Raised) self.setting_layout = QtWidgets.QVBoxLayout(self.setting_frame) # 폰트 크기 설정 스핀박스 self.font_size_spinbox = QtWidgets.QSpinBox() self.font_size_spinbox.setRange(10, 50) self.font_size_spinbox.setValue(self.fontSize) self.font_size_spinbox.valueChanged.connect(self.setFontSize) self.font_size_spinbox_layout = self.create_label_and_spin("폰트 크기", self.font_size_spinbox) self.setting_layout.addLayout(self.font_size_spinbox_layout) # 스텝 간격 조정 스핀박스 self.step_interval_spinbox = QtWidgets.QDoubleSpinBox() self.step_interval_spinbox.setRange(0.5, 10) self.step_interval_spinbox.setSingleStep(0.5) self.step_interval_spinbox.setValue(0.5) self.step_interval_spinbox.setSuffix(" Kg") self.step_interval_spinbox.valueChanged.connect(self.setStepInterval) self.step_interval_spinbox_layout = self.create_label_and_spin("무게 간격", self.step_interval_spinbox) self.setting_layout.addLayout(self.step_interval_spinbox_layout) # 경동택배 기준설정 self.cargo_Layout = QtWidgets.QHBoxLayout() self.cargoLabel_upper = QtWidgets.QLabel() self.cargoLabel = QtWidgets.QLabel() self.cargoLabel_bottom = QtWidgets.QLabel() self.cargoLabel.setText("경동택배 설정") self.cargoLabel.setAlignment(QtCore.Qt.AlignCenter) self.cargo_font.setPointSize(self.cargo_font_size) # 폰트 크기를 16포인트로 설정 self.cargoLabel.setFont(self.cargo_font) self.cargoLabel.setStyleSheet("background-color: lightgrey;") self.cargo_Layout.addWidget(self.cargoLabel_upper) self.cargo_Layout.addWidget(self.cargoLabel) self.cargo_Layout.addWidget(self.cargoLabel_bottom) self.setting_layout.addLayout(self.cargo_Layout) # 경동택배 길이기준 조정 스핀박스 self.maxLength_spinbox = QtWidgets.QSpinBox() self.maxLength_spinbox.setRange(80, 200) self.maxLength_spinbox.setSingleStep(5) self.maxLength_spinbox.setValue(100) self.maxLength_spinbox.setSuffix(" cm") self.maxLength_spinbox.valueChanged.connect(self.setMaxLength) self.maxLength_spinbox_layout = self.create_label_and_spin("경동한변길이 설정", self.maxLength_spinbox) self.setting_layout.addLayout(self.maxLength_spinbox_layout) # 경동택배 부피기준 조정 스핀박스 self.maxVolume_spinbox = QtWidgets.QSpinBox() self.maxVolume_spinbox.setRange(140, 200) self.maxVolume_spinbox.setSingleStep(5) self.maxVolume_spinbox.setValue(160) self.maxVolume_spinbox.setSuffix(" cm") self.maxVolume_spinbox.valueChanged.connect(self.setMaxVolume) self.maxVolume_spinbox_layout = self.create_label_and_spin("경동(세변합)기준 설정", self.maxVolume_spinbox) self.setting_layout.addLayout(self.maxVolume_spinbox_layout) # 경동택배 무게기준 조정 스핀박스 self.maxWeight_spinbox = QtWidgets.QSpinBox() self.maxWeight_spinbox.setRange(10, 50) self.maxWeight_spinbox.setSingleStep(1) self.maxWeight_spinbox.setValue(25) self.maxWeight_spinbox.setSuffix(" Kg") self.maxWeight_spinbox.valueChanged.connect(self.setMaxWeight) self.maxWeight_spinbox_layout = self.create_label_and_spin("경동무게기준 설정", self.maxWeight_spinbox) self.setting_layout.addLayout(self.maxWeight_spinbox_layout) # 가중치 스핀박스 self.addMoneySetlayout1 = QtWidgets.QHBoxLayout() self.addMoneySetlayout2 = QtWidgets.QHBoxLayout() self.addMoneySetlayout3 = QtWidgets.QHBoxLayout() self.label1 = QtWidgets.QLabel("가중치 기준") self.label2 = QtWidgets.QLabel(" 초과시 ") self.label3 = QtWidgets.QLabel(" 마다 ") self.label4 = QtWidgets.QLabel("추가") self.addMoney1_spinbox = QtWidgets.QSpinBox() self.addMoney1_spinbox.setRange(0, 1000) self.addMoney1_spinbox.setSingleStep(1) self.addMoney1_spinbox.setValue(20) self.addMoney1_spinbox.setSuffix(" Kg") self.addMoney1_spinbox.valueChanged.connect(self.setAddMoneySetting) self.addMoney2_spinbox = QtWidgets.QSpinBox() self.addMoney2_spinbox.setRange(0, 1000) self.addMoney2_spinbox.setSingleStep(1) self.addMoney2_spinbox.setValue(5) self.addMoney2_spinbox.setSuffix(" Kg") self.addMoney2_spinbox.valueChanged.connect(self.setAddInterval) self.addMoney3_spinbox = QtWidgets.QSpinBox() self.addMoney3_spinbox.setRange(0, 100000) self.addMoney3_spinbox.setSingleStep(1000) self.addMoney3_spinbox.setValue(1000) self.addMoney3_spinbox.setSuffix(" 원") self.addMoney3_spinbox.valueChanged.connect(self.setAddMoney) self.addMoneySetlayout1.addWidget(self.label1) self.addMoneySetlayout1.addWidget(self.addMoney1_spinbox) self.addMoneySetlayout2.addWidget(self.label2) self.addMoneySetlayout2.addWidget(self.addMoney2_spinbox) self.addMoneySetlayout3.addWidget(self.label3) self.addMoneySetlayout3.addWidget(self.label4) self.addMoneySetlayout3.addWidget(self.addMoney3_spinbox) self.addMoneySetlayout3.setStretch(0, 6) self.addMoneySetlayout3.setStretch(1, 2) self.addMoneySetlayout3.setStretch(2, 4) self.setting_layout.addLayout(self.addMoneySetlayout1) self.setting_layout.addLayout(self.addMoneySetlayout2) self.setting_layout.addLayout(self.addMoneySetlayout3) # 키프리스 프레임 self.kiprisWidget = QtWidgets.QWidget(self) self.kipris_layout = QtWidgets.QHBoxLayout(self.kiprisWidget) 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.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) self.kipris_layout.setStretch(0,3) self.kipris_layout.setStretch(1,6) self.kipris_layout.setStretch(2,3) # self.setting_layout.addLayout(self.kipris_layout) self.setting_layout.addWidget(self.kiprisWidget) # self.kiprisWidget을 설정 레이아웃에 추가 # 추가정보 프레임 self.addInfoWidget = QtWidgets.QWidget(self) self.addInfo_vlayout = QtWidgets.QVBoxLayout(self.addInfoWidget) self.addInfo_h1layout = QtWidgets.QHBoxLayout() self.addInfo_h2layout = QtWidgets.QHBoxLayout() self.addInfo_vlayout.addLayout(self.addInfo_h2layout) self.addInfo_vlayout.addLayout(self.addInfo_h1layout) self.addInfoWidget.setLayout(self.addInfo_vlayout) self.addInfoWidget.setVisible(True) self.setUSD_label = QtWidgets.QLabel(f"[{self.setUSD}]USD/KRW") setUSD_label_font = QFont() setUSD_label_font.setBold(True) # 굵게 setUSD_label_font.setUnderline(True) # 밑줄 setUSD_label_font.setWeight(12) # 폰트크기 self.setUSD_label.setAlignment(QtCore.Qt.AlignCenter) # 가운데 정렬 self.setUSD_label.setFont(setUSD_label_font) # 폰트 적용 self.addInfo_h1layout.addWidget(self.setUSD_label) self.setCNY_label = QtWidgets.QLabel(f"[{self.setCNY}]CNY/KRW") setCNY_label_font = QFont() setCNY_label_font.setBold(True) # 굵게 setCNY_label_font.setUnderline(True) # 밑줄 setCNY_label_font.setWeight(12) # 폰트크기 self.setCNY_label.setAlignment(QtCore.Qt.AlignCenter) # 가운데 정렬 self.setCNY_label.setFont(setCNY_label_font) # 폰트 적용 self.addInfo_h1layout.addWidget(self.setCNY_label) self.addInfo1_btn = QtWidgets.QPushButton("금지어") self.addInfo1_btn.clicked.connect(self.addInfo1_btn_clicked) self.addInfo_h2layout.addWidget(self.addInfo1_btn) self.addInfo2_btn = QtWidgets.QPushButton("도량형") self.addInfo2_btn.clicked.connect(self.addInfo2_btn_clicked) self.addInfo_h2layout.addWidget(self.addInfo2_btn) self.addInfo3_btn = QtWidgets.QPushButton("타냐어록") self.addInfo3_btn.setEnabled(False) 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(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) # self.setting_layout.addLayout(self.addInfo_layout) self.setting_layout.addWidget(self.addInfoWidget) # self.addInfoWidget 설정 레이아웃에 추가 # 경동택배 무게기준 조정 스핀박스 self.changeCurreny_btn = QtWidgets.QPushButton("CNY/KRW") self.changeCurreny_btn.clicked.connect(self.changeCurreny_btn_clicked) self.calcCurrency_label = QtWidgets.QLabel("") self.calcCurrency_label.setText(" 원") self.calcCurrency_label.setAlignment(QtCore.Qt.AlignCenter) calcCurrency_label_font = QFont() calcCurrency_label_font.setBold(True) # 굵게 calcCurrency_label_font.setUnderline(True) # 밑줄 calcCurrency_label_font.setWeight(16) # 폰트크기 self.calcCurrency_label.setFont(calcCurrency_label_font) self.currency_calc_box = QtWidgets.QSpinBox() self.currency_calc_box.setRange(0, 1000000) self.currency_calc_box.setSingleStep(10) self.currency_calc_box.setValue(100) self.currency_calc_box.setSuffix(" CNY") self.currency_calc_box.setAlignment(QtCore.Qt.AlignRight) # 가운데 정렬 self.currency_calc_box.valueChanged.connect(self.calcCurrency) self.currency_calc_box_layout = self.create_label_and_spin("환율", self.currency_calc_box) self.currency_calc_box_layout.addWidget(self.calcCurrency_label) self.currency_calc_box_layout.addWidget(self.changeCurreny_btn) self.currency_calc_box_layout.setStretch(0,2) self.currency_calc_box_layout.setStretch(1,4) self.currency_calc_box_layout.setStretch(2,4) self.currency_calc_box_layout.setStretch(3,2) self.setting_layout.addLayout(self.currency_calc_box_layout) # 항상 위에 토글 스위치 self.alwaysOnTopSwitch = ToggleSwitch(self.setting_frame) self.alwaysOnTopSwitch.move(10, 10) self.alwaysOnTopSwitch.setChecked(True) # 기본 상태는 ON self.alwaysOnTopSwitch.clicked.connect(self.toggleAlwaysOnTop) self.alwaysOnTopSwitch_layout = self.create_label_and_switch("항상 위에 표시", self.alwaysOnTopSwitch) self.setting_layout.addLayout(self.alwaysOnTopSwitch_layout) # 설정값 저장 토글 스위치 self.saveSettingSwitch = ToggleSwitch(self.setting_frame) self.saveSettingSwitch.move(10, 10) self.saveSettingSwitch.setChecked(False) # 기본 상태는 OFF self.saveSettingSwitch.clicked.connect(self.isSaveSetting) self.saveSettingSwitch_layout = self.create_label_and_switch("설정값 저장", self.saveSettingSwitch) self.setting_layout.addLayout(self.saveSettingSwitch_layout) # 낙인 self.infoLabel4 = QtWidgets.QLabel(" 배송비계산기 by 내차는언제타냐") self.setting_layout.addWidget(self.infoLabel4) # 레이아웃 비율 조정 self.layout.addWidget(self.user_frame, 3) self.layout.addWidget(self.user_info_frame, 3) self.layout.addWidget(self.setting_frame, 4) self.setWindowTitle('배송비 계산기') 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: # 현재 객체가 적절한 타입인지 확인 current_type = type(self.kiprisAPI) target_type = Kipris_API if self.usage_mode == 'api' else AsyncWebSearchWorker if current_type is not target_type: # 기존 객체가 다른 타입이면 삭제하고 새로 생성 logger.debug(f"기존 {self.kiprisAPI} 객체를 삭제하고 새 객체를 생성합니다.") if isinstance(self.kiprisAPI, AsyncWebSearchWorker): self.kiprisAPI.deleteLater() # 비동기 작업자는 Qt 객체로 관리되므로 deleteLater 사용 self.kiprisAPI = None if self.usage_mode == 'api': self.kiprisAPI = Kipris_API(self.api_key) # 새 객체 생성 else: web_scraper = WebScraper() # WebScraper 인스턴스 생성 self.web_scraper = web_scraper self.kiprisAPI = AsyncWebSearchWorker(self.web_scraper, "") # 초기 키워드는 비워두기 logger.debug(f"{self.usage_mode.upper()} 방식 kiprisAPI 객체 생성: {self.kiprisAPI}") else: logger.debug(f"기존에 적절한 {self.kiprisAPI} 객체가 이미 존재합니다.") else: # 객체가 없으면 새로 생성 if self.usage_mode == 'api': self.kiprisAPI = Kipris_API(self.api_key) else: web_scraper = WebScraper() # WebScraper 인스턴스 생성 self.web_scraper = web_scraper self.kiprisAPI = AsyncWebSearchWorker(web_scraper, "") # 초기 키워드는 비워두기 logger.debug(f"{self.usage_mode.upper()} 방식 kiprisAPI 객체 생성: {self.kiprisAPI}") def addInfo1_btn_clicked(self): pass def addInfo2_btn_clicked(self): pass def addInfo3_btn_clicked(self): pass def addInfo4_btn_clicked(self): # optionTrans 클래스를 사용해 다이얼로그 창을 띄움 self.trans_dialog = optionTrans(self) self.trans_dialog.show() self.add_dialog(self.trans_dialog) # 열린 다이얼로그를 리스트에 추가 def showSettingsDialog(self): if self.settingDialog.exec_(): self.use_kipris = self.settingDialog.use_kipris 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() def kipris_Visible(self): if self.use_kipris: self.kiprisWidget.setVisible(True) self.initSettings_for_kipris() self.kipris_label.setText(f"키프리스 검색({self.usage_mode})") else: self.kiprisWidget.setVisible(False) def create_label_and_switch(self, label_text, target_switch): layout = QtWidgets.QHBoxLayout() label = QtWidgets.QLabel(label_text) # label.setAlignment(QtCore.Qt.AlignCenter) layout.addWidget(label) layout.addWidget(target_switch) return layout def create_label_and_spin(self, label_text, spin): layout = QtWidgets.QHBoxLayout() label = QtWidgets.QLabel(label_text) # label.setAlignment(QtCore.Qt.AlignCenter) layout.addWidget(label) layout.addWidget(spin) return layout def create_label_and_spin_in_QV(self, label_text, spin): layout = QtWidgets.QVBoxLayout() label = QtWidgets.QLabel(label_text) label.setAlignment(QtCore.Qt.AlignCenter) layout.addWidget(label) layout.addWidget(spin) return layout def center(self): qr = self.frameGeometry() cp = QtWidgets.QDesktopWidget().availableGeometry().center() qr.moveCenter(cp) self.move(qr.topLeft()) def loadDeliveryFees(self): try: excel_file = pd.ExcelFile('delv.xlsx') sheets = excel_file.sheet_names for sheet in sheets: df = excel_file.parse(sheet) # 시트 내 컬럼 확인 및 데이터 처리 if '무게' in df.columns and '배송비' in df.columns: self.processSheet(df, sheet, '무게') if '부피' in df.columns and '배송비' in df.columns: self.processSheet(df, sheet, '부피') if sheet.endswith('(배송비)'): self.comboBox.addItem(sheet) logger.debug('Excel file loaded successfully.') except Exception as e: logger.error(f"Error loading Excel file: {e}", exc_info=True) QtWidgets.QMessageBox.critical(self, "Error", "Failed to load the Excel file.") def processSheet(self, df, sheet_name, key): records = [] for index, row in df.iterrows(): try: value_str = re.findall(r'\d+[\d,]*', str(row[key]))[0].replace(',', '') fee_str = re.findall(r'\d+[\d,]*', str(row['배송비']))[0].replace(',', '') value = float(value_str) fee = int(fee_str) records.append({key: value, '배송비': fee}) except ValueError as e: logger.error(f"Error converting values in row {index} of sheet {sheet_name}: {e}") continue self.deliveryFees[sheet_name] = records def setDefaultValues(self): self.weightInput.setValue(1) self.widthInput.setValue(1) self.lengthInput.setValue(1) self.heightInput.setValue(1) self.updateDeliveryFee() def updateDeliveryFee(self): try: weight = self.weightInput.value() # logger.debug(f"현재 선택된 무게 : {weight}") selected_sheet = self.comboBox.currentText() # logger.debug(f"현재 선택된 시트 : {selected_sheet}") fees = self.deliveryFees.get(selected_sheet, []) fee = 0 # 가능한 모든 무게를 리스트로 가져오고 정렬 sorted_fees = sorted((float(f['무게']), int(f['배송비'])) for f in fees if '무게' in f and '배송비' in f) # 입력된 무게보다 작거나 같은 최대 무게 찾기 closest_fee = None for w, f in sorted_fees: if weight >= w: closest_fee = f else: break # 배송비 업데이트 if closest_fee is not None: fee = closest_fee # 추가 배송비 계산 if weight > self.addFeeSetting: # 추가될 배송비 횟수 계산 additional_fee_count = (weight - self.addFeeSetting) // self.addFeeInterval if (weight - self.addFeeSetting) % self.addFeeInterval != 0: additional_fee_count += 1 total_add_fee = additional_fee_count * self.addFee fee += total_add_fee self.deliveryFeeLabel.setText(f'배송비: {int(fee): ,}원 (추가 배송비 {int(total_add_fee)} 포함)') else: self.deliveryFeeLabel.setText(f'배송비: {int(fee): ,}원') # logger.debug(f"배송비 deliveryFeeLabel에 업데이트: {int(fee): ,}원") # 폰트와 밑줄 설정 font = QFont() font.setBold(True) # 굵게 font.setUnderline(True) # 밑줄 self.deliveryFeeLabel.setFont(font) self.currentWeight = weight self.additionalFee() except Exception as e: logger.error(f"Error updating delivery fee: {e}", exc_info=True) self.deliveryFeeLabel.setText("배송비 업데이트 중 오류 발생") def updateAdditionalDeliveryFee(self): try: weight = self.weightInput.value() volume = self.currentVolume # 현재 부피 logger.debug(f"현재 선택된 무게 : {weight}") selected_v_sheet = '경동부피' selected_w_sheet = '경동무게' v_fees = self.deliveryFees.get(selected_v_sheet, []) w_fees = self.deliveryFees.get(selected_w_sheet, []) # 가능한 모든 무게를 리스트로 가져오고 정렬 sorted_v_fees = sorted((float(f['부피']), int(f['배송비'])) for f in v_fees if '부피' in f and '배송비' in f) sorted_w_fees = sorted((float(f['무게']), int(f['배송비'])) for f in w_fees if '무게' in f and '배송비' in f) # logger.debug(f"경동부피무게 가격 : {sorted_v_fees}") # logger.debug(f"경동무게당 가격 : {sorted_w_fees}") # 입력된 무게보다 작거나 같은 최대 무게 찾기 closest_v_fee = None closest_w_fee = None price_source = "" # 무게에 따른 최적 배송비 계산 for w_w, w_f in sorted_w_fees: if weight >= w_w: closest_w_fee = w_f else: break # 부피에 따른 최적 배송비 계산 for v_w, v_f in sorted_v_fees: if volume >= v_w: closest_v_fee = v_f else: break # 최종 가격 결정 및 가격 출처 확인 if closest_v_fee is not None and closest_w_fee is not None: if closest_v_fee >= closest_w_fee: closest_final_fee = closest_v_fee price_source = "부피" else: closest_final_fee = closest_w_fee price_source = "무게" elif closest_v_fee is not None: closest_final_fee = closest_v_fee price_source = "부피" elif closest_w_fee is not None: closest_final_fee = closest_w_fee price_source = "무게" else: closest_final_fee = 0 price_source = "데이터 없음" # 폰트와 밑줄 설정 font = QFont() font.setBold(True) # 굵게 font.setUnderline(True) # 밑줄 self.additionalFeeLabel.setFont(font) # 배송비 업데이트 및 라벨 표시 fee = f"{closest_final_fee: ,}원" self.additionalFeeLabel.setText(f'경동 택배비[{price_source}]: {fee}') except Exception as e: logger.error(f"Error updating Additional delivery fee: {e}", exc_info=True) self.additionalFeeLabel.setText("배송비 업데이트 중 오류 발생") def updateComboBox(self): selected_Delv = self.comboBox.currentText() logger.debug(f"선택된 배대지: {selected_Delv}") self.favoriteDelv = selected_Delv self.updateDeliveryFee() def setComboBox(self): logger.debug(f"self.favoriteDelv: {self.favoriteDelv}") if self.favoriteDelv: index = self.comboBox.findText(self.favoriteDelv) logger.debug(f"저장된 배대지가 존재함: {self.favoriteDelv}") if index >= 0: self.comboBox.setCurrentIndex(index) else: logger.debug("저장된 배대지가 엑셀시트에 존재하지 않습니다.") def additionalFee(self): messages = [] exceeded = False if self.currentWeight >= self.maxWeightSet: messages.append(f"무게기준 [{self.maxWeightSet}Kg] 초과") exceeded = True if self.currentMaxLength >= self.maxLengthSet: messages.append(f"길이기준 [{self.maxLengthSet}cm] 초과") exceeded = True if self.roundVolume >= self.maxVolumeSet: logger.debug(f"self.roundVolume : {self.roundVolume}") logger.debug(f"maxVolumeSet : {self.maxVolumeSet}") messages.append(f"세변의 합 기준 [{self.maxVolumeSet}cm] 초과") exceeded = True if exceeded: # 모든 메시지를 연결하여 표시 self.additionalFeeTextLabel.setText(", ".join(messages)) self.additionalFeeLabel.setVisible(True) self.additionalFeeTextLabel.setVisible(True) self.updateAdditionalDeliveryFee() else: self.additionalFeeLabel.setVisible(False) self.additionalFeeTextLabel.setVisible(False) def updateVolume(self): length = self.lengthInput.value() width = self.widthInput.value() height = self.heightInput.value() volume = length * width * height roundVolume = length + width + height self.currentVolume = volume self.roundVolume = roundVolume self.volumeLabel.setText(f"부피: {volume: ,} cm³") self.currentMaxLength = max(length,width,height) if self.currentMaxLength > self.maxLengthSet: self.maxLengthLabel.setText(f"한 변의 최대길이 : {self.currentMaxLength}cm") self.maxLengthLabel.setVisible(True) else: self.maxLengthLabel.setVisible(False) self.additionalFee() def toggleAlwaysOnTop(self, state): if state: self.setWindowFlags(self.windowFlags() | Qt.WindowStaysOnTopHint) else: self.setWindowFlags(self.windowFlags() & ~Qt.WindowStaysOnTopHint) self.show() # 변경된 윈도우 플래그를 적용하기 위해 위젯을 다시 보여줘야 함 def setFontSize(self, value): font = self.font() font.setPointSize(value) self.setFont(font) self.fontSize = value self.cargo_font.setPointSize(self.cargo_font_size) def setStepInterval(self, value): self.weightInput.setSingleStep(value) self.weightInterval = value def setMaxWeight(self, value): self.maxWeightSet = value self.updateDeliveryFee() def setMaxLength(self, value): self.maxLengthSet = value self.updateDeliveryFee() def setMaxVolume(self, value): self.maxVolumeSet = value self.updateDeliveryFee() def setAddMoneySetting(self, value): self.addFeeSetting = value if self.addFeeSetting == 0: self.addFee = 2000 self.updateDeliveryFee() def setAddMoney(self, value): self.addFee = value self.updateDeliveryFee() def setAddInterval(self, value): self.addFeeInterval = value self.updateDeliveryFee() def changeCurreny_btn_clicked(self): selected = self.changeCurreny_btn.text() if selected == 'CNY/KRW': self.currency_calc_box.setSuffix(" USD") self.changeCurreny_btn.setText('USD/KRW') self.currentCurrency = self.setUSD else: self.currency_calc_box.setSuffix(" CNY") self.changeCurreny_btn.setText('CNY/KRW') self.currentCurrency = self.setCNY self.calcCurrency(100) def calcCurrency(self,value): result = value * self.currentCurrency result = round(result,0) result = '{0:,}'.format(result) # logger.debug(f"result{result}") # logger.debug(f"round(result,2){str(round(result,0))}") self.calcCurrency_label.setText(result+' 원') def isSaveSetting(self, state): if state: self.setSaveSetting = True else: self.setSaveSetting = False logger.debug(f"설정값 저장세팅 : {self.setSaveSetting}") self.show() def kipris_btn_clicked(self): self.search_keyword = self.kipris_edit.text() logger.debug(f"키프리스 검색버튼 클릭 : 키워드 = [{self.search_keyword}]") # result = self.kiprisAPI.run(self.search_keyword, self.set_status) # 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) if self.usage_mode == 'api': self.handle_search_for_api(self.search_keyword) def handle_search_for_web(self, keyword): self.add_history(keyword) # 검색어 히스토리 추가 if self.asyncWorker: # 기존에 비동기 작업자가 존재한다면 self.asyncWorker.thread.quit() # 기존 스레드 종료 logger.debug(f"키프리스 검색버튼 클릭 : 키워드 = [{keyword}]") self.asyncWorker = AsyncWebSearchWorker(keyword, self.set_status) # 새 비동기 작업자 생성 self.asyncWorker.finished.connect(self.display_results_for_web) # 완료 시그널을 결과 표시 함수에 연결 self.asyncWorker.start() # 비동기 작업 시작 logger.debug("비동기 검색 시작") def display_results_for_web(self, result, elapsed_time): # 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) # self.searchDisplay.show() message = f"검색 결과 : {result}\n검색에 걸린 시간: {elapsed_time:.1f}초" # QtWidgets.QMessageBox.information(self, "Search Results", message) self.asyncWorker = None # 작업 완료 후 객체 참조 해제 def handle_search_for_api(self, keyword): self.add_history(keyword) if self.searchThread is not None and self.searchThread.isRunning(): self.searchThread.quit() # 이전 스레드가 실행 중이라면 안전하게 종료 logger.debug("기존 쓰레드가 존재하므로 기존 쓰레드 종료") logger.debug(f"키프리스 검색버튼 클릭 : 키워드 = [{keyword}]") worker = APISearchWorker(self.kiprisAPI, keyword, self.set_status) # worker = SearchWorker(self.kiprisAPI, keyword, self.set_status) logger.debug("워커 생성") self.searchThread = SearchThread(worker) logger.debug("쓰레드 생성") worker.finished.connect(self.display_results_for_api) self.searchThread.finished.connect(self.clear_thread_reference) self.searchThread.start_search() logger.debug("검색 시작") def clear_thread_reference(self): # 스레드 종료 후 참조를 제거하여 다음 검색을 위해 준비 self.searchThread = None 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) def reset_action(self): self.lengthInput.setValue(1) self.widthInput.setValue(1) self.heightInput.setValue(1) self.weightInput.setValue(1) def showHelp(self): # 도움말 내용 표시 helpText = "안녕하세요 내차는 언제타냐 입니다. \n - 모든 입력칸에는 마우스 휠로 입력가능하고, \n - 컨트롤+휠 동작시 (기본값x10) 값으로 변경가능합니다.\n - 배대지를 추가하려면 첨부된 엑셀파일 delv.xlsx를 참조하세요 \n - 배대지 순서를 정하려면 시트이름에 번호를 붙이세요." QtWidgets.QMessageBox.information(self, '도움말', helpText) def showChangeLog(self): # ChangeLog 내용 표시 QtWidgets.QMessageBox.information(self, 'ChangeLog', "Version 1.0 \n Inintial Launch\n\nVersion 1.0.1 \n Dimension에 Reset버튼 추가") def setttingTosetDefaultValues(self): # 기본값 설정 로직 QtWidgets.QMessageBox.information(self, '기본값 설정', "기본값으로 설정합니다.") self.font_size_spinbox.setValue(14) # self.setFontSize self.addMoney1_spinbox.setValue(20) self.addMoney2_spinbox.setValue(5) self.addMoney3_spinbox.setValue(5000) self.saveSettingSwitch.setChecked(False) self.step_interval_spinbox.setValue(0.5) self.maxVolume_spinbox.setValue(160) self.maxWeight_spinbox.setValue(25) self.maxLength_spinbox.setValue(100) self.favoriteDelv = None self.setComboBox() 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_())