diff --git a/images/splash.png b/images/splash.png new file mode 100644 index 0000000..bf5632d Binary files /dev/null and b/images/splash.png differ diff --git a/main.py b/main.py index 8fbabdb..f357c6b 100644 --- a/main.py +++ b/main.py @@ -1,26 +1,19 @@ -import os -import shutil import sys -from pathlib import Path from PySide6.QtWidgets import QApplication from ui.main import MainWindow -from utils.function import resource_path - -appdata_dir = Path(os.environ["APPDATA"]) -dtg_dir = appdata_dir / "dtg" -target_csv = dtg_dir / "questions.csv" - -if not target_csv.exists(): - dtg_dir.mkdir(parents=True, exist_ok=True) - source_csv = Path(resource_path("template/questions.csv")) - if not source_csv.exists(): - raise FileNotFoundError(f"源文件不存在:{source_csv.resolve()}") - shutil.copy(source_csv, target_csv) if __name__ == '__main__': app = QApplication(sys.argv) window = MainWindow() - window.show() + try: + import pyi_splash + + pyi_splash.close() + except ImportError: + pass + finally: + window.show() + sys.exit(app.exec()) diff --git a/main.spec b/main.spec index 2791bbb..a7a3725 100644 --- a/main.spec +++ b/main.spec @@ -16,11 +16,24 @@ a = Analysis( ) pyz = PYZ(a.pure) +splash = Splash( + 'images\\splash.png', + binaries=a.binaries, + datas=a.datas, + text_pos=(5,298), + text_size=12, + text_color='black', + minify_script=True, + always_on_top=True, +) + exe = EXE( pyz, a.scripts, a.binaries, a.datas, + splash, + splash.binaries, [], debug=False, bootloader_ignore_signals=False, diff --git a/module/schema.py b/module/schema.py index 022e789..bf47e06 100644 --- a/module/schema.py +++ b/module/schema.py @@ -22,6 +22,17 @@ class Question: questions.append(Question(*line.strip('\n').split(','))) return questions + @staticmethod + def load_from_xls(path: str) -> list['Question']: + questions = [] + wb = load_workbook(path, read_only=True) + ws = wb.active + for row in ws.iter_rows(min_col=2, max_col=3, min_row=2, values_only=True): + if row[0] is None and row[1] is None: + break + questions.append(Question(*row)) + return questions + @property def no(self) -> str: return self._no @@ -112,4 +123,4 @@ class Course: if __name__ == '__main__': - ... \ No newline at end of file + ... diff --git a/module/worker.py b/module/worker.py new file mode 100644 index 0000000..f5e8b1c --- /dev/null +++ b/module/worker.py @@ -0,0 +1,44 @@ +import os +from pathlib import Path + +from PySide6.QtCore import QObject, Signal + +from module.doc import DocPaper +from module.schema import Course, Student, Question +from utils.function import resource_path + + +class DTGWorker(QObject): + progress = Signal(int) + finished = Signal() + + def __init__( + self, + input_student_filepath: str, + input_question_filepath: str, + output_filepath: str, + output_filename: str + ): + super().__init__() + self.input_filepath = input_student_filepath + self.input_question_filepath = input_question_filepath + self.output_filepath = output_filepath + self.output_filename = output_filename + + def run(self): + course = Course.load_from_xls(self.input_filepath) + students = Student.load_from_xls(self.input_filepath) + questions = Question.load_from_xls(self.input_question_filepath) + + d = DocPaper(self.output_filename, template_path=resource_path("template/template.docx")) + for index, student in enumerate(students): + if (p := int((index + 1) / len(students) * 100)) != 100: + self.progress.emit(p) + else: + self.progress.emit(99) + student.pick_question(questions) + d.add_paper(course, student) + d.save(self.output_filepath) + self.progress.emit(100) + os.startfile(Path(self.output_filepath) / f"{self.output_filename}.docx") + self.finished.emit() diff --git a/requirements.txt b/requirements.txt index e2a3b9b..5c1d6ea 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,3 +1,4 @@ openpyxl pyside6 python-docx +PySide6-Fluent-Widgets[full] \ No newline at end of file diff --git a/template/questions.csv b/template/questions.csv deleted file mode 100644 index 396f8b6..0000000 --- a/template/questions.csv +++ /dev/null @@ -1,90 +0,0 @@ -0.0.01,γƵĻݡ -0.0.03,γƵĻ衣 -0.0.05,γƲõҪЩ -1.1.04,½ĿĿ֣ -1.1.15,˵ɡ -1.1.18,˵ij -1.1.22,˵۵㺬塣 -2.0.06,;һļ֣ԵҪʲô -2.1.06,ʩк -2.2.04,ʡƼ۶еġۺϵۡļ֣ôģ -2.2.07,Ļ㷽һļ֣˵ -2.2.08,ʲôDzϵԤ۸ -2.2.22,ϵԤ۸Щɲ֣ -3.0.08,ʲôƸ㣿һ˭ƣ -3.1.06,ʩͼԤһ˭ƣҪЩ -3.1.15,õͶЩ -3.2.12,ʲôǡԱȡ˭ɣк壿 -3.3.04,˭ɣҪЩ -3.3.08,ҪЩ -4.1.02,ʲôǹ嵥 -4.1.05,ʲôб깤嵥ʲôѱ۹嵥 -4.1.09,嵥ࣿ -4.1.09,ʲôбƼۣ˭ƣ -4.1.11,嵥Ŀȷ -4.1.13,嵥еĿƸȷ -4.2.05,ʲôۺϵۣ -4.2.12,ۺϵ۰Щɲ֣ɲμõ -4.2.14,ۺϵγɣ -4.3.22,ļ㾫кҪ -5.0.02,ͳ﷨ᵽġһ桱ָʲô -5.0.12,ͨĵ㽨μ㽨 -5.0.15,ݶμ㽨 -5.0.16,̨μ㽨 -5.0.19,¥ݸμ㽨 -5.0.24,μ㽨 -5.0.28,Ʈ㽨ʲô -5.01.01,һļࣿ -5.01.04,ڻʱοǹͷ£ -5.01.05,ȸȷ -5.01.08,ʱɡʪλ֣ -5.01.18,ڹڻк -5.01.37,ƽصʲôμ㹤 -5.01.57,жȱ˻ˣ -5.03.05,ԤƸֽ׮μ㹤 -5.03.08,ʲô׮μ㹤 -5.03.16,׹ע׮һӦЩĹ -5.03.24,׹ע׮һӦЩĹ -5.03.39,׮μ㹤 -5.04.08,שǽλ֣ -5.04.11,שǽʱǽ߸ȡ -5.04.15,ͬȵı׼שǽļȷֱǶ١ -5.04.19,שǽʱӦ۳Щݣ -5.04.21,שŽŸμ㹤 -5.04.33,ש̨׸μ㹤 -5.05.04,ʲôǸֽεõ -5.05.05,ֽмּ㷽ѡã -5.06.04,µĻ㣬кԼ -5.06.04,ǽμ㹤 -5.06.08,ֽμ㹤λμ㹤׶ -5.06.12,߸ȷ -5.06.18,μ㹤 -5.06.34,ֽȸȡ -5.06.46,ֱμ㹤 -5.06.55,ǽ㹤ʱЩӦ۳ -5.06.73,ֱֽ¥ݸμ㹤 -5.06.78,ֽ̨Ϊשμ㹤 -5.06.82,ֽμ㹤 -5.10.05,ķˮμ㹤 -5.10.09,Էˮμ㹤 -5.13.07,Ϳ湤ļк -5.13.23,¥¥ݿ㹤ļк -5.14.05,ǽĨҸμ㹤 -5.14.11,ǽĨҸμ㹤 -5.15.05,УǺ͸к -5.15.15,ĨҸμ㹤 -5.19.03,ʱӦ㳬߷ѣ -5.20.05,ۺϽּܺ͵ֱּܷʲôʱã -5.21.03,ģ幤мּ㷽ѡã -6.1.03,嵥Ƽ£۰ļ󲿷֣ -6.1.14,еѰЩɲ֣ -6.1.23,۴ʩѺܼ۴ʩк -6.1.32,ʲôнδ֧꣬ʣн˭У -6.1.33,ʲôн˭ȷ -6.1.37,ʲôDzݹۣڽɽ㣿 -6.1.42,Щǵļʲô -6.1.65,ЩΪɾã -6.2.04,ȷ -6.3.11,˹ѵʵ֣ -6.3.23,ܳаѸμȡ -7.0.05,жϱijЩ diff --git a/ui/components/widget.py b/ui/components/widget.py new file mode 100644 index 0000000..745e11e --- /dev/null +++ b/ui/components/widget.py @@ -0,0 +1,9 @@ +from PySide6.QtWidgets import QFrame + + +class Widget(QFrame): + + def __init__(self, key: str, parent=None): + super().__init__(parent=parent) + # 必须给子界面设置全局唯一的对象名 + self.setObjectName(key.replace(' ', '-')) diff --git a/ui/main.py b/ui/main.py index af260ba..8b03f78 100644 --- a/ui/main.py +++ b/ui/main.py @@ -1,102 +1,23 @@ -import os -import platform -import subprocess -from pathlib import Path +from qfluentwidgets import FluentIcon, MSFluentWindow, NavigationItemPosition -from PySide6.QtCore import QObject, QThread, Signal -from PySide6.QtWidgets import QMainWindow, QFileDialog - -from module.doc import DocPaper -from module.schema import Course, Student, Question -from ui.pyui.main import Ui_MainWindow -from utils.function import resource_path +from ui.pyui.about_ui import AboutWidget +from ui.pyui.defense_ui import DefenseWidget -class Worker(QObject): - progress = Signal(str) - finished = Signal() - - def __init__(self, input_filepath: str, output_filepath: str, output_filename: str): - super().__init__() - self.input_filepath = input_filepath - self.output_filepath = output_filepath - self.output_filename = output_filename - - def run(self): - self.progress.emit("第一步:正在读取课程信息...") - course = Course.load_from_xls(self.input_filepath) - self.progress.emit("第二步:正在读取学生信息...") - students = Student.load_from_xls(self.input_filepath) - self.progress.emit("第三步:正在读取题目信息...") - questions = Question.load_from_csv(str(Path(os.environ["APPDATA"]) / "dtg" / "questions.csv")) - - d = DocPaper(self.output_filename, template_path=resource_path("template/template.docx")) - for student in students: - self.progress.emit(f"第四步:({student.no}/{len(students)})正在处理学生:{student.name},学号:{student.so}") - student.pick_question(questions) - d.add_paper(course, student) - self.progress.emit("第五步:正在保存文件...") - d.save(self.output_filepath) - self.progress.emit("第六步:文件保存成功!") - os.startfile(Path(self.output_filepath) / f"{self.output_filename}.docx") - - -class MainWindow(QMainWindow, Ui_MainWindow): +class MainWindow(MSFluentWindow): def __init__(self): super().__init__() - self.setupUi(self) - self.setWindowTitle("答辩题目生成器") - self.select_student_list.clicked.connect(self.choose_student_list) - self.select_output_dir.clicked.connect(self.choose_output_dir) - self.edit_topics.clicked.connect(self.edit_questions) - self.start.clicked.connect(self.start_generate) + self.homeInterface = DefenseWidget('Defense Interface', self) + self.aboutInterface = AboutWidget('About Interface', self) - def on_button_clicked(self): - self.statusBar().showMessage("这是状态栏信息") + self.initNavigation() + self.initWindow() - def choose_student_list(self): - file_path, _ = QFileDialog.getOpenFileName(self, "选择文件", "", "Excel 文件 (*.xlsx);") - if file_path: - self.student_list_path.setText(file_path) + def initNavigation(self): + self.addSubInterface(self.homeInterface, FluentIcon.HOME, '首页') + self.addSubInterface(self.aboutInterface, FluentIcon.INFO, '关于', position=NavigationItemPosition.BOTTOM) - input_dir_path = file_path[:file_path.rfind('/')] - default_output_filename = file_path[file_path.rfind('/') + 1:file_path.rfind('-点名册')] - - self.output_path.setText(input_dir_path) - self.output_filename.setText(default_output_filename) - - def choose_output_dir(self): - dir_path = QFileDialog.getExistingDirectory(self, "选择文件夹", "") - if dir_path: - self.output_path.setText(dir_path) - - def edit_questions(self): - csv_path = Path(os.environ["APPDATA"]) / "dtg" / "questions.csv" - - if platform.system() == "Windows": - os.startfile(csv_path.resolve()) - elif platform.system() == "Darwin": # macOS - subprocess.run(["open", csv_path.resolve()]) - else: # Linux - subprocess.run(["xdg-open", csv_path.resolve()]) - - self.update_statusbar("已打开题目文件,请在外部程序编辑后保存。") - - def start_generate(self): - self.thread = QThread() - self.worker = Worker(self.student_list_path.text(), self.output_path.text(), self.output_filename.text()) - self.worker.moveToThread(self.thread) - - # 线程启动与信号连接 - self.thread.started.connect(self.worker.run) - self.worker.progress.connect(self.update_statusbar) - self.worker.finished.connect(self.thread.quit) - self.worker.finished.connect(self.worker.deleteLater) - self.thread.finished.connect(self.thread.deleteLater) - - # 启动线程 - self.thread.start() - - def update_statusbar(self, message): - self.statusBar().showMessage(message) + def initWindow(self): + self.resize(900, 700) + self.setWindowTitle('答辩题目生成器') diff --git a/ui/main.ui b/ui/main.ui deleted file mode 100644 index 32ab679..0000000 --- a/ui/main.ui +++ /dev/null @@ -1,159 +0,0 @@ - - - MainWindow - - - Qt::WindowModality::ApplicationModal - - - - 0 - 0 - 500 - 200 - - - - - 500 - 200 - - - - - 500 - 200 - - - - MainWindow - - - - - - - - - 学生名单 - - - - - - - - - - 选择 - - - - - - - - - 导出设置 - - - - - - - - - 40 - 0 - - - - - 40 - 16777215 - - - - 目 录 - - - - - - - - - - 选择 - - - - - - - - - - - - 40 - 0 - - - - - 40 - 16777215 - - - - 文件名 - - - - - - - - - - - - - - - - - Qt::Orientation::Horizontal - - - - 40 - 20 - - - - - - - - 编辑题库 - - - - - - - 导出 - - - - - - - - - - - - diff --git a/ui/pyui/about_ui.py b/ui/pyui/about_ui.py new file mode 100644 index 0000000..177a989 --- /dev/null +++ b/ui/pyui/about_ui.py @@ -0,0 +1,49 @@ +from PySide6.QtGui import QDesktopServices +from PySide6.QtWidgets import QVBoxLayout +from qfluentwidgets import PrimaryPushSettingCard, FluentIcon, GroupHeaderCardWidget, PushButton + +from ui.components.widget import Widget + + +class AboutWidget(Widget): + def __init__(self, key: str, parent=None): + super().__init__(key, parent) + + self.version_card = PrimaryPushSettingCard( + text="获取源码", + icon=FluentIcon.INFO, + title="关于", + content="作者:许方杰。当前版本:1.0.0\n使用 GPLv3 开源协议,作者不对使用本软件造成的任何损失负责。" + ) + self.button_list = [ + PushButton("访问网站"), + PushButton("访问网站"), + PushButton("访问网站"), + PushButton("访问网站"), + ] + self.url_list = [ + "https://qt.io", + "https://qfluentwidgets.com", + "https://openpyxl.readthedocs.io/en/stable", + "https://github.com/python-openxml/python-docx" + ] + self.group_card = GroupHeaderCardWidget(self) + self.group_card.setTitle("第三方框架") + self.vbox = QVBoxLayout(self) + + self.vbox.addWidget(self.version_card) + self.vbox.addWidget(self.group_card) + self.vbox.addStretch(1) + + self.group_card.addGroup("", "PySide6", self.url_list[0], self.button_list[0]) + self.group_card.addGroup("", "QFluentWidgets", self.url_list[1], self.button_list[1]) + self.group_card.addGroup("", "openpyxl", self.url_list[2], self.button_list[2]) + self.group_card.addGroup("", "python-docx", self.url_list[3], self.button_list[3]) + + self.version_card.clicked.connect( + lambda: QDesktopServices.openUrl("https://cantyonion.site/git/cantyonion/DefenseTopicGenerator") + ) + self.button_list[0].clicked.connect(lambda: QDesktopServices.openUrl(self.url_list[0])) + self.button_list[1].clicked.connect(lambda: QDesktopServices.openUrl(self.url_list[1])) + self.button_list[2].clicked.connect(lambda: QDesktopServices.openUrl(self.url_list[2])) + self.button_list[3].clicked.connect(lambda: QDesktopServices.openUrl(self.url_list[3])) diff --git a/ui/pyui/defense_ui.py b/ui/pyui/defense_ui.py new file mode 100644 index 0000000..9a07783 --- /dev/null +++ b/ui/pyui/defense_ui.py @@ -0,0 +1,243 @@ +from typing import Literal, Callable +from functools import wraps + +from PySide6.QtCore import Qt, Signal, QThread +from PySide6.QtWidgets import QHBoxLayout, QVBoxLayout, QFileDialog +from qfluentwidgets import GroupHeaderCardWidget, PushButton, IconWidget, InfoBarIcon, \ + BodyLabel, PrimaryPushButton, FluentIcon, LineEdit, InfoBar, InfoBarPosition, ProgressBar + +from module.worker import DTGWorker +from ui.components.widget import Widget + + +class InitSettingCard(GroupHeaderCardWidget): + chooseSignal = Signal(str, str) + + def __init__(self, parent=None): + super().__init__(parent) + + self.setTitle("初始化") + self.setBorderRadius(8) + + self.chooseStudentButton = PushButton("打开") + self.chooseQuestionButton = PushButton("打开") + + self.chooseStudentButton.setFixedWidth(120) + self.chooseQuestionButton.setFixedWidth(120) + + self.stuGroup = self.addGroup(FluentIcon.DOCUMENT, "学生名单", "选择学生名单文件", self.chooseStudentButton) + self.QueGroup = self.addGroup(FluentIcon.DOCUMENT, "题库", "选择题库文件", self.chooseQuestionButton) + + self.chooseStudentButton.clicked.connect( + lambda: self.choose_file(self.stuGroup.setContent, "已选择文件:", lambda x: self.chooseSignal.emit('s', x))) + self.chooseQuestionButton.clicked.connect( + lambda: self.choose_file(self.QueGroup.setContent, "已选择文件:", lambda x: self.chooseSignal.emit('q', x))) + + def choose_file( + self, + set_value: Callable[[str], None] = None, + prefix: str = "", + cb: Callable[[str], None] = None + ) -> None: + file_path, _ = QFileDialog.getOpenFileName(self, "选择文件", "", "Excel 文件 (*.xlsx *.xlsm);") + if file_path and set_value: + set_value(prefix + file_path) + if cb: + cb(file_path) + + +class ExportSettingsCard(GroupHeaderCardWidget): + startSignal = Signal() + updateSignal = Signal(str, str) + + def __init__(self, parent=None): + super().__init__(parent) + + self.setTitle("导出") + self.setBorderRadius(8) + + self.chooseExportDirectoryButton = PushButton("选择") + self.exportFileNameLineEdit = LineEdit() + self.startButton = PrimaryPushButton(FluentIcon.PLAY_SOLID, "开始") + + self.hintIcon = IconWidget(InfoBarIcon.INFORMATION) + self.hintLabel = BodyLabel("点击导出按钮以开始生成 👉") + self.chooseExportDirectoryButton.setFixedWidth(120) + self.startButton.setFixedWidth(120) + self.exportFileNameLineEdit.setFixedWidth(360) + self.exportFileNameLineEdit.setPlaceholderText("输入导出文件名,例如:21工程管理(1)答辩题目") + self.bottomLayout = QHBoxLayout() + self.startButton.setEnabled(False) + + # 设置底部工具栏布局 + self.hintIcon.setFixedSize(16, 16) + self.bottomLayout.setSpacing(10) + self.bottomLayout.setContentsMargins(24, 15, 24, 20) + self.bottomLayout.addWidget(self.hintIcon, 0, Qt.AlignLeft) + self.bottomLayout.addWidget(self.hintLabel, 0, Qt.AlignLeft) + self.bottomLayout.addStretch(1) + self.bottomLayout.addWidget(self.startButton, 0, Qt.AlignRight) + self.bottomLayout.setAlignment(Qt.AlignVCenter) + + self.dirGroup = self.addGroup(FluentIcon.FOLDER, "导出目录", "选择导出文件的目录", + self.chooseExportDirectoryButton) + self.fnGroup = self.addGroup(FluentIcon.DOCUMENT, "导出文件名", "输入导出文件的名称", + self.exportFileNameLineEdit) + self.fnGroup.setSeparatorVisible(True) + + self.vBoxLayout.addLayout(self.bottomLayout) + + # ============== + self.chooseExportDirectoryButton.clicked.connect(self.choose_dir) + self.startButton.clicked.connect(self.startSignal.emit) + self.exportFileNameLineEdit.textChanged.connect(lambda x: self.updateSignal.emit('n', x)) + + def choose_dir(self) -> None: + dir_path = QFileDialog.getExistingDirectory(self, "选择文件夹", "") + if dir_path: + self.dirGroup.setContent(f"当前保存的文件目录:{dir_path}") + self.updateSignal.emit('d', dir_path) + + def update_export_setting_by_signal(self, path: str) -> None: + f_dir = path[:path.rfind('/')] + f_name = path[path.rfind('/') + 1:path.rfind('.')] + self.dirGroup.setContent(f"当前保存的文件目录:{f_dir}") + self.updateSignal.emit('d', f_dir) + self.exportFileNameLineEdit.setText(f"{f_name}-答辩题目") + self.updateSignal.emit('n', f_name) + + +class DefenseWidget(Widget): + def __init__(self, key: str, parent=None): + super().__init__(key, parent) + + self.initCard = InitSettingCard(self) + self.exportCard = ExportSettingsCard(self) + self.vbox = QVBoxLayout(self) + + self.vbox.addWidget(self.initCard) + self.vbox.addWidget(self.exportCard) + self.vbox.addStretch(1) + + self.infoBar = None + self.pb = None + + self.thread = None + self.worker = None + + # =================================== + + self.input_student_filepath = None + self.input_question_filepath = None + self.output_filepath = None + self.output_filename = None + + # ==================================== + self.initCard.chooseSignal.connect(self.input_signal_receive) + self.exportCard.updateSignal.connect(self.export_update_signal_receive) + self.exportCard.startSignal.connect(self.start_generate) + + def show_info_bar(self): + self.infoBar = InfoBar( + icon=InfoBarIcon.INFORMATION, + title='请稍后', + content="", + orient=Qt.Horizontal, + isClosable=False, + position=InfoBarPosition.BOTTOM, + duration=-1, + parent=self + ) + self.pb = ProgressBar(self.infoBar) + self.infoBar.addWidget(self.pb) + self.infoBar.show() + + def set_pb_value(self, value: int) -> None: + if self.pb: + self.pb.setValue(value) + if value == 100: + self.infoBar.close() + self.infoBar = InfoBar.success( + title='成功!', + content="正在打开文件...", + orient=Qt.Horizontal, + isClosable=True, + position=InfoBarPosition.BOTTOM, + duration=5000, + parent=self + ) + self.pb = None + self.exportCard.startButton.setEnabled(True) + + def enable_start_check(func: Callable): + @wraps(func) + def wrapper(self, *args, **kwargs): + result = func(self, *args, **kwargs) + + fields = [ + self.input_student_filepath, + self.input_question_filepath, + self.output_filepath, + self.output_filename + ] + if all(fields): + self.exportCard.startButton.setEnabled(True) + else: + self.exportCard.startButton.setEnabled(False) + return result + + return wrapper + + @enable_start_check + def set_value(self, key: str, value: str) -> None: + if key == "input_student_filepath": + self.input_student_filepath = value + elif key == "input_question_filepath": + self.input_question_filepath = value + elif key == "output_filepath": + self.output_filepath = value + elif key == "output_filename": + self.output_filename = value + setattr(self, key, value) + + def input_signal_receive(self, s_type: Literal['s', 'q'], value: str): + if s_type == "s": + self.set_value("input_student_filepath", value) + self.exportCard.update_export_setting_by_signal(value) + elif s_type == "q": + self.set_value("input_question_filepath", value) + + def export_update_signal_receive(self, s_type: Literal['d', 'n'], value: str): + if s_type == "d": + self.set_value("output_filepath", value) + elif s_type == "n": + self.set_value("output_filename", value) + + def start_generate(self): + self.thread = QThread() + self.worker = DTGWorker( + self.input_student_filepath, + self.input_question_filepath, + self.output_filepath, + self.output_filename + ) + self.worker.moveToThread(self.thread) + + self.show_info_bar() + self.exportCard.startButton.setEnabled(False) + + # 线程启动与信号连接 + self.thread.started.connect(self.worker.run) + self.worker.progress.connect(self.set_pb_value) + + self.worker.finished.connect(self.thread.quit) + self.worker.finished.connect(self.worker.deleteLater) + self.thread.finished.connect(self.thread.deleteLater) + self.thread.finished.connect(self.clear_thread_worker_refs) + + # 启动线程 + self.thread.start() + + def clear_thread_worker_refs(self): + self.thread = None + self.worker = None diff --git a/ui/pyui/main.py b/ui/pyui/main.py deleted file mode 100644 index 36e4443..0000000 --- a/ui/pyui/main.py +++ /dev/null @@ -1,140 +0,0 @@ -# -*- coding: utf-8 -*- - -################################################################################ -## Form generated from reading UI file 'main.ui' -## -## Created by: Qt User Interface Compiler version 6.9.0 -## -## WARNING! All changes made in this file will be lost when recompiling UI file! -################################################################################ - -from PySide6.QtCore import (QCoreApplication, QDate, QDateTime, QLocale, - QMetaObject, QObject, QPoint, QRect, - QSize, QTime, QUrl, Qt) -from PySide6.QtGui import (QBrush, QColor, QConicalGradient, QCursor, - QFont, QFontDatabase, QGradient, QIcon, - QImage, QKeySequence, QLinearGradient, QPainter, - QPalette, QPixmap, QRadialGradient, QTransform) -from PySide6.QtWidgets import (QApplication, QGridLayout, QGroupBox, QHBoxLayout, - QLabel, QLineEdit, QMainWindow, QPushButton, - QSizePolicy, QSpacerItem, QStatusBar, QWidget) - -class Ui_MainWindow(object): - def setupUi(self, MainWindow): - if not MainWindow.objectName(): - MainWindow.setObjectName(u"MainWindow") - MainWindow.setWindowModality(Qt.WindowModality.ApplicationModal) - MainWindow.resize(500, 200) - MainWindow.setMinimumSize(QSize(500, 200)) - MainWindow.setMaximumSize(QSize(500, 200)) - self.centralwidget = QWidget(MainWindow) - self.centralwidget.setObjectName(u"centralwidget") - self.gridLayout_2 = QGridLayout(self.centralwidget) - self.gridLayout_2.setObjectName(u"gridLayout_2") - self.horizontalLayout_3 = QHBoxLayout() - self.horizontalLayout_3.setObjectName(u"horizontalLayout_3") - self.label = QLabel(self.centralwidget) - self.label.setObjectName(u"label") - - self.horizontalLayout_3.addWidget(self.label) - - self.student_list_path = QLineEdit(self.centralwidget) - self.student_list_path.setObjectName(u"student_list_path") - - self.horizontalLayout_3.addWidget(self.student_list_path) - - self.select_student_list = QPushButton(self.centralwidget) - self.select_student_list.setObjectName(u"select_student_list") - - self.horizontalLayout_3.addWidget(self.select_student_list) - - - self.gridLayout_2.addLayout(self.horizontalLayout_3, 0, 0, 1, 1) - - self.groupBox = QGroupBox(self.centralwidget) - self.groupBox.setObjectName(u"groupBox") - self.gridLayout = QGridLayout(self.groupBox) - self.gridLayout.setObjectName(u"gridLayout") - self.horizontalLayout = QHBoxLayout() - self.horizontalLayout.setObjectName(u"horizontalLayout") - self.label_2 = QLabel(self.groupBox) - self.label_2.setObjectName(u"label_2") - self.label_2.setMinimumSize(QSize(40, 0)) - self.label_2.setMaximumSize(QSize(40, 16777215)) - - self.horizontalLayout.addWidget(self.label_2) - - self.output_path = QLineEdit(self.groupBox) - self.output_path.setObjectName(u"output_path") - - self.horizontalLayout.addWidget(self.output_path) - - self.select_output_dir = QPushButton(self.groupBox) - self.select_output_dir.setObjectName(u"select_output_dir") - - self.horizontalLayout.addWidget(self.select_output_dir) - - - self.gridLayout.addLayout(self.horizontalLayout, 0, 0, 1, 1) - - self.horizontalLayout_2 = QHBoxLayout() - self.horizontalLayout_2.setObjectName(u"horizontalLayout_2") - self.label_3 = QLabel(self.groupBox) - self.label_3.setObjectName(u"label_3") - self.label_3.setMinimumSize(QSize(40, 0)) - self.label_3.setMaximumSize(QSize(40, 16777215)) - - self.horizontalLayout_2.addWidget(self.label_3) - - self.output_filename = QLineEdit(self.groupBox) - self.output_filename.setObjectName(u"output_filename") - - self.horizontalLayout_2.addWidget(self.output_filename) - - - self.gridLayout.addLayout(self.horizontalLayout_2, 1, 0, 1, 1) - - - self.gridLayout_2.addWidget(self.groupBox, 1, 0, 1, 1) - - self.horizontalLayout_4 = QHBoxLayout() - self.horizontalLayout_4.setObjectName(u"horizontalLayout_4") - self.horizontalSpacer = QSpacerItem(40, 20, QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Minimum) - - self.horizontalLayout_4.addItem(self.horizontalSpacer) - - self.edit_topics = QPushButton(self.centralwidget) - self.edit_topics.setObjectName(u"edit_topics") - - self.horizontalLayout_4.addWidget(self.edit_topics) - - self.start = QPushButton(self.centralwidget) - self.start.setObjectName(u"start") - - self.horizontalLayout_4.addWidget(self.start) - - - self.gridLayout_2.addLayout(self.horizontalLayout_4, 2, 0, 1, 1) - - MainWindow.setCentralWidget(self.centralwidget) - self.statusbar = QStatusBar(MainWindow) - self.statusbar.setObjectName(u"statusbar") - MainWindow.setStatusBar(self.statusbar) - - self.retranslateUi(MainWindow) - - QMetaObject.connectSlotsByName(MainWindow) - # setupUi - - def retranslateUi(self, MainWindow): - MainWindow.setWindowTitle(QCoreApplication.translate("MainWindow", u"MainWindow", None)) - self.label.setText(QCoreApplication.translate("MainWindow", u"\u5b66\u751f\u540d\u5355", None)) - self.select_student_list.setText(QCoreApplication.translate("MainWindow", u"\u9009\u62e9", None)) - self.groupBox.setTitle(QCoreApplication.translate("MainWindow", u"\u5bfc\u51fa\u8bbe\u7f6e", None)) - self.label_2.setText(QCoreApplication.translate("MainWindow", u"\u76ee \u5f55", None)) - self.select_output_dir.setText(QCoreApplication.translate("MainWindow", u"\u9009\u62e9", None)) - self.label_3.setText(QCoreApplication.translate("MainWindow", u"\u6587\u4ef6\u540d", None)) - self.edit_topics.setText(QCoreApplication.translate("MainWindow", u"\u7f16\u8f91\u9898\u5e93", None)) - self.start.setText(QCoreApplication.translate("MainWindow", u"\u5bfc\u51fa", None)) - # retranslateUi -