from pathlib import Path from traceback import format_exc from PySide6.QtCore import Qt from PySide6.QtWidgets import QMainWindow, QMessageBox, QFileDialog, QApplication, QWidget from PySide6.QtGui import QGuiApplication from matplotlib import use from yaml import dump, load, FullLoader from func.utils.PublicFunc import PublicFunc from ui.MainWindow.MainWindow_menu import Ui_Signal_Label from func.Module_approximately_align import MainWindow_approximately_align from func.Module_preprocess import MainWindow_preprocess from func.Module_detect_Jpeak import MainWindow_detect_Jpeak from func.Module_detect_Rpeak import MainWindow_detect_Rpeak from func.Module_label_check import MainWindow_label_check from func.Module_precisely_align import MainWindow_precisely_align from func.Module_cut_PSG import MainWindow_cut_PSG from func.Module_artifact_label import MainWindow_artifact_label from func.Module_bcg_quality_label import MainWindow_bcg_quality_label from func.Module_resp_quality_label import MainWindow_resp_quality_label from func.Module_SA_label import MainWindow_SA_label from func.utils.ConfigParams import Filename, Params from func.utils.Constants import Constants use("QtAgg") # style.use('dark_background') # rcParams.update({ # 'figure.facecolor': '#f5f5dc', # 'axes.facecolor': '#f5f5dc' # }) Config = { } ButtonState = { "Default": { "pushButton_open": True, "pushButton_approximately_align": True, "pushButton_preprocess_BCG": True, "pushButton_preprocess_ECG": True, "pushButton_detect_Jpeak": True, "pushButton_detect_Rpeak": True, "pushButton_label_check_BCG": True, "pushButton_label_check_ECG": True, "pushButton_precisely_align": True, "pushButton_cut_PSG": True, "pushButton_artifact_label": True, "pushButton_bcg_quality_label": True, "pushButton_resp_quality_label": True, "pushButton_SA_label": True }, "Current": { "pushButton_open": True, "pushButton_approximately_align": True, "pushButton_preprocess_BCG": True, "pushButton_preprocess_ECG": True, "pushButton_detect_Jpeak": True, "pushButton_detect_Rpeak": True, "pushButton_label_check_BCG": True, "pushButton_label_check_ECG": True, "pushButton_precisely_align": True, "pushButton_cut_PSG": True, "pushButton_artifact_label": True, "pushButton_bcg_quality_label": True, "pushButton_resp_quality_label": True, "pushButton_SA_label": True } } class MainWindow(QMainWindow, Ui_Signal_Label): def __init__(self): super(MainWindow, self).__init__() self.ui = Ui_Signal_Label() self.ui.setupUi(self) # self.setFixedSize(720, 1080) # 设置固定大小,禁止缩放 # 获得屏幕分辨率,以3:4比例设置窗口大小, screen = QGuiApplication.primaryScreen() size = screen.availableGeometry() screen_height = size.height() window_height = int(screen_height * 0.75) window_width = int(window_height * 1 / 2) self.resize(window_width, window_height) # 消息弹窗初始化 self.msgBox = QMessageBox() self.msgBox.setWindowTitle(Constants.MAINWINDOW_MSGBOX_TITLE) self.__read_config__() self.ui.plainTextEdit_root_path.setPlainText(Config["Path"]["Root"]) self.seek_sampID(Path(Config["Path"]["Root"]) / Path(Filename.PATH_ORGBCG_TEXT)) self.approximately_align = None self.preprocess = None self.detect_Jpeak = None self.detect_Rpeak = None self.label_check = None self.precisely_align = None self.cut_PSG = None self.artifact_label = None self.bcg_quality_label = None self.resp_quality_label = None self.SA_label = None PublicFunc.__styleAllButton__(self, ButtonState) try: if QApplication.styleHints().colorScheme() == Qt.ColorScheme.Dark: self.ui.checkBox_darkmode.setChecked(True) else: self.ui.checkBox_darkmode.setChecked(False) except Exception as e: PublicFunc.msgbox_output(self, Constants.MAINWINDOW_GET_DARKMODE_FAILURE + "。" + format_exc(), Constants.TIPS_TYPE_ERROR) # 绑定槽函数 self.ui.checkBox_darkmode.stateChanged.connect(self.set_dark_mode_status) self.ui.pushButton_open.clicked.connect(self.__slot_btn_open__) self.ui.pushButton_approximately_align.clicked.connect(self.__slot_btn_approximately_align__) self.ui.pushButton_preprocess_BCG.clicked.connect(self.__slot_btn_preprocess__) self.ui.pushButton_preprocess_ECG.clicked.connect(self.__slot_btn_preprocess__) self.ui.pushButton_detect_Jpeak.clicked.connect(self.__slot_btn_detect_Jpeak__) self.ui.pushButton_detect_Rpeak.clicked.connect(self.__slot_btn_detect_Rpeak__) self.ui.pushButton_label_check_BCG.clicked.connect(self.__slot_btn_label_check__) self.ui.pushButton_label_check_ECG.clicked.connect(self.__slot_btn_label_check__) self.ui.pushButton_precisely_align.clicked.connect(self.__slot_btn_precisely_align__) self.ui.pushButton_cut_PSG.clicked.connect(self.__slot_btn_cut_PSG__) self.ui.pushButton_artifact_label.clicked.connect(self.__slot_btn_artifact_label__) self.ui.pushButton_bcg_quality_label.clicked.connect(self.__slot_btn_bcg_quality_label__) self.ui.pushButton_resp_quality_label.clicked.connect(self.__slot_btn_resp_quality_label__) self.ui.pushButton_SA_label.clicked.connect(self.__slot_btn_SA_label__) @staticmethod def __read_config__(): if not Path(Params.PUBLIC_CONFIG_FILE_PATH).exists(): Path(Params.PUBLIC_CONFIG_FILE_PATH).parent.mkdir(parents=True, exist_ok=True) with open(Params.PUBLIC_CONFIG_FILE_PATH, "w") as f: dump(Params.PUBLIC_CONFIG_NEW_CONTENT, f) with open(Params.PUBLIC_CONFIG_FILE_PATH, "r") as f: file_config = load(f.read(), Loader=FullLoader) Config.update(file_config) @staticmethod def __write_config__(): with open(Path(Params.PUBLIC_CONFIG_FILE_PATH), "w") as f: dump(Config, f) def __slot_btn_open__(self): file_dialog = QFileDialog() file_dialog.setFileMode(QFileDialog.Directory) file_dialog.setOption(QFileDialog.ShowDirsOnly, True) if file_dialog.exec_() == QFileDialog.Accepted: self.seek_sampID(Path(file_dialog.selectedFiles()[0]) / Filename.PATH_ORGBCG_TEXT) self.ui.plainTextEdit_root_path.setPlainText(file_dialog.selectedFiles()[0]) # 修改配置 Config["Path"]["Root"] = str(file_dialog.selectedFiles()[0]) self.__write_config__() else: PublicFunc.msgbox_output(self, Constants.OPERATION_CANCELED, Constants.MSGBOX_TYPE_INFO) def __slot_btn_approximately_align__(self): self.approximately_align = MainWindow_approximately_align() root_path = self.ui.plainTextEdit_root_path.toPlainText() sampID = self.ui.comboBox_sampID.currentText() if not self.check_root_path(): return if not self.check_sampID(): return self.approximately_align.show(root_path, int(sampID)) # 默认最大化显示而非固定分辨率 self.approximately_align.showMaximized() self.check_save_path_and_mkdir(root_path, sampID) def __slot_btn_preprocess__(self): self.preprocess = MainWindow_preprocess() sender = self.sender() root_path = self.ui.plainTextEdit_root_path.toPlainText() sampID = self.ui.comboBox_sampID.currentText() if sender == self.ui.pushButton_preprocess_BCG: mode = "BCG" elif sender == self.ui.pushButton_preprocess_ECG: mode = "ECG" else: raise ValueError("模式不存在") if not self.check_root_path(): return if not self.check_sampID(): return self.preprocess.show(mode, root_path, int(sampID)) # 默认最大化显示而非固定分辨率 self.preprocess.showMaximized() self.check_save_path_and_mkdir(root_path, sampID) def __slot_btn_detect_Jpeak__(self): self.detect_Jpeak = MainWindow_detect_Jpeak() root_path = self.ui.plainTextEdit_root_path.toPlainText() sampID = self.ui.comboBox_sampID.currentText() if not self.check_root_path(): return if not self.check_sampID(): return self.detect_Jpeak.show(root_path, int(sampID)) # 默认最大化显示而非固定分辨率 self.detect_Jpeak.showMaximized() self.check_save_path_and_mkdir(root_path, sampID) def __slot_btn_detect_Rpeak__(self): self.detect_Rpeak = MainWindow_detect_Rpeak() root_path = self.ui.plainTextEdit_root_path.toPlainText() sampID = self.ui.comboBox_sampID.currentText() if not self.check_root_path(): return if not self.check_sampID(): return self.detect_Rpeak.show(root_path, int(sampID)) # 默认最大化显示而非固定分辨率 self.detect_Rpeak.showMaximized() self.check_save_path_and_mkdir(root_path, sampID) def __slot_btn_label_check__(self): self.label_check = MainWindow_label_check() sender = self.sender() root_path = self.ui.plainTextEdit_root_path.toPlainText() sampID = self.ui.comboBox_sampID.currentText() if not self.check_root_path(): return if not self.check_sampID(): return if sender == self.ui.pushButton_label_check_BCG: mode = "BCG" elif sender == self.ui.pushButton_label_check_ECG: mode = "ECG" else: raise ValueError("模式不存在") self.label_check.show(mode, root_path, int(sampID)) # 默认最大化显示而非固定分辨率 self.label_check.showMaximized() self.check_save_path_and_mkdir(root_path, sampID) def __slot_btn_precisely_align__(self): self.precisely_align = MainWindow_precisely_align() root_path = self.ui.plainTextEdit_root_path.toPlainText() sampID = self.ui.comboBox_sampID.currentText() if not self.check_root_path(): return if not self.check_sampID(): return self.precisely_align.show(root_path, int(sampID)) # 默认最大化显示而非固定分辨率 self.precisely_align.showMaximized() self.check_save_path_and_mkdir(root_path, sampID) def __slot_btn_cut_PSG__(self): self.cut_PSG = MainWindow_cut_PSG() root_path = self.ui.plainTextEdit_root_path.toPlainText() sampID = self.ui.comboBox_sampID.currentText() if not self.check_root_path(): return if not self.check_sampID(): return self.cut_PSG.show(root_path, int(sampID)) self.check_save_path_and_mkdir(root_path, sampID) def __slot_btn_artifact_label__(self): self.artifact_label = MainWindow_artifact_label() root_path = self.ui.plainTextEdit_root_path.toPlainText() sampID = self.ui.comboBox_sampID.currentText() if not self.check_root_path(): return if not self.check_sampID(): return self.artifact_label.show(root_path, int(sampID)) # 默认最大化显示而非固定分辨率 self.artifact_label.showMaximized() self.check_save_path_and_mkdir(root_path, sampID) def __slot_btn_bcg_quality_label__(self): self.bcg_quality_label = MainWindow_bcg_quality_label() root_path = self.ui.plainTextEdit_root_path.toPlainText() sampID = self.ui.comboBox_sampID.currentText() if not self.check_root_path(): return if not self.check_sampID(): return self.bcg_quality_label.show(root_path, int(sampID)) # 默认最大化显示而非固定分辨率 self.bcg_quality_label.showMaximized() self.check_save_path_and_mkdir(root_path, sampID) def __slot_btn_resp_quality_label__(self): self.resp_quality_label = MainWindow_resp_quality_label() root_path = self.ui.plainTextEdit_root_path.toPlainText() sampID = self.ui.comboBox_sampID.currentText() if not self.check_root_path(): return if not self.check_sampID(): return self.resp_quality_label.show(root_path, int(sampID)) # 默认最大化显示而非固定分辨率 self.resp_quality_label.showMaximized() self.check_save_path_and_mkdir(root_path, sampID) def __slot_btn_SA_label__(self): self.SA_label = MainWindow_SA_label() root_path = self.ui.plainTextEdit_root_path.toPlainText() sampID = self.ui.comboBox_sampID.currentText() if not self.check_root_path(): return if not self.check_sampID(): return self.SA_label.show(root_path, int(sampID)) # 默认最大化显示而非固定分辨率 self.SA_label.showMaximized() self.check_save_path_and_mkdir(root_path, sampID) def seek_sampID(self, path): if not Path(path).exists(): PublicFunc.msgbox_output(self, Constants.MAINWINDOW_ROOT_PATH_NOT_EXIST, Constants.MSGBOX_TYPE_ERROR) self.ui.comboBox_sampID.clear() return sub_folders = [item.name for item in Path(path).iterdir() if item.is_dir()] self.ui.comboBox_sampID.clear() self.ui.comboBox_sampID.addItems(sub_folders) self.ui.comboBox_sampID.setCurrentIndex(0) def check_root_path(self): if self.ui.plainTextEdit_root_path.toPlainText() == Constants.STRING_IS_EMPTY: PublicFunc.msgbox_output(self, Constants.MAINWINDOW_ROOT_PATH_NOT_EXIST, Constants.MSGBOX_TYPE_ERROR) return False return True def check_sampID(self): if self.ui.comboBox_sampID.currentText() == Constants.STRING_IS_EMPTY: PublicFunc.msgbox_output(self, Constants.MAINWINDOW_SAMPID_EMPTY, Constants.MSGBOX_TYPE_ERROR) return False return True def check_save_path_and_mkdir(self, root_path, sampID): path_Label = Path(root_path) / Path(Filename.PATH_LABEL) / Path(str(sampID)) path_OrgBCG_Aligned = Path(root_path) / Path(Filename.PATH_ORGBCG_ALIGNED) / Path(str(sampID)) path_PSG_Aligned = Path(root_path) / Path(Filename.PATH_PSG_ALIGNED) / Path(str(sampID)) path_OrgBCG_Text = Path(root_path) / Path(Filename.PATH_ORGBCG_TEXT) / Path(str(sampID)) path_PSG_Text = Path(root_path) / Path(Filename.PATH_PSG_TEXT) / Path(str(sampID)) path_list = [path_Label, path_OrgBCG_Aligned, path_PSG_Aligned, path_OrgBCG_Text, path_PSG_Text] for path in path_list: if not path.exists(): path.mkdir(parents=True, exist_ok=True) def set_dark_mode_status(self): try: if self.ui.checkBox_darkmode.isChecked(): QApplication.styleHints().setColorScheme(Qt.ColorScheme.Dark) else: QApplication.styleHints().setColorScheme(Qt.ColorScheme.Light) except Exception as e: PublicFunc.msgbox_output(self, Constants.MAINWINDOW_DARKMODE_FAILURE + "。" + format_exc(), Constants.MSGBOX_TYPE_ERROR) return try: MainWindow.update_widget_style(self) except RuntimeError: pass try: if self.approximately_align is not None: MainWindow.update_widget_style(self.approximately_align) except RuntimeError: pass try: if self.preprocess is not None: MainWindow.update_widget_style(self.preprocess) except RuntimeError: pass try: if self.detect_Jpeak is not None: MainWindow.update_widget_style(self.detect_Jpeak) except RuntimeError: pass try: if self.detect_Rpeak is not None: MainWindow.update_widget_style(self.detect_Rpeak) except RuntimeError: pass try: if self.label_check is not None: MainWindow.update_widget_style(self.label_check) except RuntimeError: pass try: if self.precisely_align is not None: MainWindow.update_widget_style(self.precisely_align) except RuntimeError: pass try: if self.cut_PSG is not None: MainWindow.update_widget_style(self.cut_PSG) except RuntimeError: pass try: if self.artifact_label is not None: MainWindow.update_widget_style(self.artifact_label) except RuntimeError: pass try: if self.bcg_quality_label is not None: MainWindow.update_widget_style(self.bcg_quality_label) except RuntimeError: pass try: if self.resp_quality_label is not None: MainWindow.update_widget_style(self.resp_quality_label) except RuntimeError: pass try: if self.SA_label is not None: MainWindow.update_widget_style(self.SA_label) except RuntimeError: pass @staticmethod def update_widget_style(mainWindow): all_widgets = mainWindow.centralWidget().findChildren(QWidget) # 迭代所有部件 for widget in all_widgets: try: widget.style().unpolish(widget) widget.style().polish(widget) widget.update() except TypeError: pass