Files
JITToolBox/ui/pyui/defense_ui.py
2025-05-20 02:59:58 +08:00

244 lines
9.1 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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