完善提问模块
This commit is contained in:
@@ -1,3 +1,4 @@
|
|||||||
|
import random
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
|
||||||
from openpyxl.reader.excel import load_workbook
|
from openpyxl.reader.excel import load_workbook
|
||||||
@@ -8,8 +9,9 @@ from openpyxl.worksheet.worksheet import Worksheet
|
|||||||
class PickerStudent:
|
class PickerStudent:
|
||||||
total_time: int = 0
|
total_time: int = 0
|
||||||
|
|
||||||
def __init__(self, name: str, position: int, scores: list[int]):
|
def __init__(self, name: str, so: str, position: int, scores: list[int]):
|
||||||
self._name = name
|
self._name = name
|
||||||
|
self._so = so
|
||||||
self._position = position
|
self._position = position
|
||||||
self._scores = scores
|
self._scores = scores
|
||||||
self._modify = False
|
self._modify = False
|
||||||
@@ -43,6 +45,24 @@ class PickerStudent:
|
|||||||
self._scores[index] = new_score
|
self._scores[index] = new_score
|
||||||
self.modified()
|
self.modified()
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def pick(student: list['PickerStudent']) -> Optional['PickerStudent']:
|
||||||
|
filtered = [item for item in student if item.weight != 100 and item.weight > 0]
|
||||||
|
if not filtered:
|
||||||
|
return None
|
||||||
|
|
||||||
|
# 计算倒数权重
|
||||||
|
weights = [1 / item.weight for item in filtered]
|
||||||
|
total = sum(weights)
|
||||||
|
r = random.uniform(0, total)
|
||||||
|
|
||||||
|
cumulative = 0
|
||||||
|
for item, w in zip(filtered, weights):
|
||||||
|
cumulative += w
|
||||||
|
if r <= cumulative:
|
||||||
|
return item
|
||||||
|
return None
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def set_total_time(cls, total_time: int):
|
def set_total_time(cls, total_time: int):
|
||||||
cls.total_time = total_time
|
cls.total_time = total_time
|
||||||
@@ -63,6 +83,14 @@ class PickerStudent:
|
|||||||
def weight(self) -> int:
|
def weight(self) -> int:
|
||||||
return int(sum(1 for x in self._scores if x != 0) / self.total_time * 100)
|
return int(sum(1 for x in self._scores if x != 0) / self.total_time * 100)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def name(self) -> str:
|
||||||
|
return self._name
|
||||||
|
|
||||||
|
@property
|
||||||
|
def so(self) -> str:
|
||||||
|
return self._so
|
||||||
|
|
||||||
def saved(self):
|
def saved(self):
|
||||||
self._modify = False
|
self._modify = False
|
||||||
|
|
||||||
@@ -80,7 +108,8 @@ class PickerExcel:
|
|||||||
wb: Optional[Workbook]
|
wb: Optional[Workbook]
|
||||||
ws: Optional[Worksheet]
|
ws: Optional[Worksheet]
|
||||||
path: str = ''
|
path: str = ''
|
||||||
max_time_position = 'L1'
|
max_time_position = 'M1'
|
||||||
|
start_row = 5
|
||||||
|
|
||||||
def __init__(self, path: str):
|
def __init__(self, path: str):
|
||||||
self.open(path)
|
self.open(path)
|
||||||
@@ -88,7 +117,7 @@ class PickerExcel:
|
|||||||
@classmethod
|
@classmethod
|
||||||
def open(cls, path: str):
|
def open(cls, path: str):
|
||||||
cls.path = path
|
cls.path = path
|
||||||
cls.wb = load_workbook(path)
|
cls.wb = load_workbook(path, keep_vba=True)
|
||||||
cls.ws = cls.wb.active
|
cls.ws = cls.wb.active
|
||||||
PickerStudent.set_total_time(cls.ws[cls.max_time_position].value)
|
PickerStudent.set_total_time(cls.ws[cls.max_time_position].value)
|
||||||
|
|
||||||
@@ -99,13 +128,40 @@ class PickerExcel:
|
|||||||
|
|
||||||
if cls.wb and cls.ws:
|
if cls.wb and cls.ws:
|
||||||
ret = []
|
ret = []
|
||||||
for row in cls.ws.iter_rows(min_row=4, max_col=4 + cls.ws[cls.max_time_position].value, values_only=True):
|
for index, row in enumerate(cls.ws.iter_rows(
|
||||||
|
min_row=cls.start_row,
|
||||||
|
max_col=4 + cls.ws[cls.max_time_position].value,
|
||||||
|
values_only=True)
|
||||||
|
):
|
||||||
if (name := row[2]) is None:
|
if (name := row[2]) is None:
|
||||||
break
|
break
|
||||||
ret.append(PickerStudent(name, int(row[0]) + 3, row[4:]))
|
ret.append(PickerStudent(name, row[1], cls.start_row + index, row[4:]))
|
||||||
return ret
|
return ret
|
||||||
else:
|
raise Exception('No Workbook or Worksheet')
|
||||||
raise Exception('No Workbook or Worksheet')
|
|
||||||
|
@classmethod
|
||||||
|
def read_total_time(cls, path: Optional[str] = None) -> int:
|
||||||
|
if path:
|
||||||
|
cls.open(path)
|
||||||
|
|
||||||
|
if cls.wb and cls.ws:
|
||||||
|
val = cls.ws[cls.max_time_position].value
|
||||||
|
if isinstance(val, int):
|
||||||
|
return val
|
||||||
|
raise Exception(f'总次数读取错误,期待类型 {type(1)} 但实际为 {type(val)}\n'
|
||||||
|
f'可能的解决方法:\n'
|
||||||
|
f'1、确保总次数位于 \'{cls.max_time_position}\' 单元格;\n'
|
||||||
|
f'2、确保选择了正确的 Excel 文件。')
|
||||||
|
raise Exception('No Workbook or Worksheet')
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def save_total_time(cls, path: Optional[str] = None, value: Optional[int] = None) -> None:
|
||||||
|
if path:
|
||||||
|
cls.open(path)
|
||||||
|
|
||||||
|
if cls.wb and cls.ws and value:
|
||||||
|
cls.ws[cls.max_time_position].value = value
|
||||||
|
cls.save()
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def write_back(cls, student: PickerStudent):
|
def write_back(cls, student: PickerStudent):
|
||||||
@@ -116,6 +172,7 @@ class PickerExcel:
|
|||||||
cls.ws.cell(row=row, column=start_col + i, value=val if val != 0 else '')
|
cls.ws.cell(row=row, column=start_col + i, value=val if val != 0 else '')
|
||||||
|
|
||||||
student.saved()
|
student.saved()
|
||||||
|
cls.save()
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def write_all(cls, students: list[PickerStudent]):
|
def write_all(cls, students: list[PickerStudent]):
|
||||||
|
|||||||
0
ui/components/__init__.py
Normal file
0
ui/components/__init__.py
Normal file
@@ -1,4 +1,11 @@
|
|||||||
from PySide6.QtWidgets import QFrame
|
from PySide6.QtWidgets import QApplication, QWidget, QLabel, QPushButton, QVBoxLayout, QFrame
|
||||||
|
from PySide6.QtCore import QTimer, Qt, Signal
|
||||||
|
import sys
|
||||||
|
import random
|
||||||
|
|
||||||
|
from qfluentwidgets import DisplayLabel
|
||||||
|
|
||||||
|
from module.picker.schema import PickerStudent
|
||||||
|
|
||||||
|
|
||||||
class Widget(QFrame):
|
class Widget(QFrame):
|
||||||
@@ -7,3 +14,44 @@ class Widget(QFrame):
|
|||||||
super().__init__(parent=parent)
|
super().__init__(parent=parent)
|
||||||
# 必须给子界面设置全局唯一的对象名
|
# 必须给子界面设置全局唯一的对象名
|
||||||
self.setObjectName(key.replace(' ', '-'))
|
self.setObjectName(key.replace(' ', '-'))
|
||||||
|
|
||||||
|
|
||||||
|
class RollingTextWidget(QWidget):
|
||||||
|
finishSignal = Signal()
|
||||||
|
|
||||||
|
def __init__(self, parent=None):
|
||||||
|
super().__init__(parent)
|
||||||
|
self.current_index = 0
|
||||||
|
self.items = []
|
||||||
|
|
||||||
|
self.label = DisplayLabel("", self)
|
||||||
|
self.label.setAlignment(Qt.AlignCenter)
|
||||||
|
|
||||||
|
self.layout = QVBoxLayout()
|
||||||
|
self.layout.addWidget(self.label)
|
||||||
|
self.setLayout(self.layout)
|
||||||
|
|
||||||
|
self.rolling_timer = QTimer(self)
|
||||||
|
self.rolling_timer.setInterval(50) # 滚动速度(毫秒)
|
||||||
|
self.rolling_timer.timeout.connect(self.update_text)
|
||||||
|
|
||||||
|
self.stop_timer = QTimer(self)
|
||||||
|
self.stop_timer.setSingleShot(True)
|
||||||
|
self.stop_timer.timeout.connect(self.stop_rolling)
|
||||||
|
|
||||||
|
def update_text(self):
|
||||||
|
# 每次显示下一个字符
|
||||||
|
self.current_index = (self.current_index + 1) % len(self.items)
|
||||||
|
self.label.setText(self.items[self.current_index].name)
|
||||||
|
|
||||||
|
def start_rolling(self):
|
||||||
|
if not self.rolling_timer.isActive():
|
||||||
|
self.rolling_timer.start()
|
||||||
|
self.stop_timer.start(2000) # 2秒后停止滚动
|
||||||
|
|
||||||
|
def stop_rolling(self):
|
||||||
|
self.rolling_timer.stop()
|
||||||
|
self.finishSignal.emit()
|
||||||
|
|
||||||
|
def set_items(self, items: list[PickerStudent]):
|
||||||
|
self.items = items
|
||||||
|
|||||||
16
ui/components/window.py
Normal file
16
ui/components/window.py
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
from PySide6.QtWidgets import QHBoxLayout
|
||||||
|
from qfluentwidgets import FluentTitleBar
|
||||||
|
from qfluentwidgets.window.fluent_window import FluentWindowBase
|
||||||
|
|
||||||
|
|
||||||
|
class MyWindow(FluentWindowBase):
|
||||||
|
def __init__(self, parent=None):
|
||||||
|
super().__init__(parent)
|
||||||
|
self.setTitleBar(FluentTitleBar(self))
|
||||||
|
|
||||||
|
self.widgetLayout = QHBoxLayout(self)
|
||||||
|
self.widgetLayout.setContentsMargins(0, 48, 0, 0)
|
||||||
|
self.hBoxLayout.addLayout(self.widgetLayout)
|
||||||
|
|
||||||
|
self.titleBar.raise_()
|
||||||
|
self.showMaximized()
|
||||||
12
ui/main.py
12
ui/main.py
@@ -20,21 +20,22 @@ class MainWindow(MSFluentWindow):
|
|||||||
self.achievementInterface = AchievementWidget('Achievement Interface', self)
|
self.achievementInterface = AchievementWidget('Achievement Interface', self)
|
||||||
self.defenseInterface = DefenseWidget('Defense Interface', self)
|
self.defenseInterface = DefenseWidget('Defense Interface', self)
|
||||||
self.aboutInterface = AboutWidget('About Interface', self)
|
self.aboutInterface = AboutWidget('About Interface', self)
|
||||||
|
self.pickerInterface = PickerWidget('Picker Interface', self)
|
||||||
if not DEVELOPMENT_ENV:
|
if not DEVELOPMENT_ENV:
|
||||||
self.pickerInterface = PickerWidget('Picker Interface', self)
|
|
||||||
self.testInterface = TestWidget('Test Interface', self)
|
self.testInterface = TestWidget('Test Interface', self)
|
||||||
|
|
||||||
self.achievementInterface.error.connect(self.showError)
|
self.achievementInterface.error.connect(self.showError)
|
||||||
self.defenseInterface.errorSignal.connect(self.showError)
|
self.defenseInterface.errorSignal.connect(self.showError)
|
||||||
|
self.pickerInterface.errorSignal.connect(self.showError)
|
||||||
|
|
||||||
self.initNavigation()
|
self.initNavigation()
|
||||||
self.initWindow()
|
self.initWindow()
|
||||||
|
|
||||||
def initNavigation(self):
|
def initNavigation(self):
|
||||||
self.addSubInterface(self.achievementInterface, FluentIcon.SPEED_HIGH, '达成度')
|
self.addSubInterface(self.achievementInterface, FluentIcon.SPEED_HIGH, '达成度')
|
||||||
self.addSubInterface(self.defenseInterface, FluentIcon.FEEDBACK, '答辩')
|
self.addSubInterface(self.defenseInterface, FluentIcon.FEEDBACK, '答辩题目')
|
||||||
|
self.addSubInterface(self.pickerInterface, FluentIcon.PEOPLE, '提问')
|
||||||
if not DEVELOPMENT_ENV:
|
if not DEVELOPMENT_ENV:
|
||||||
self.addSubInterface(self.pickerInterface, FluentIcon.PEOPLE, '抽答')
|
|
||||||
self.addSubInterface(self.testInterface, FluentIcon.VIEW, '测试')
|
self.addSubInterface(self.testInterface, FluentIcon.VIEW, '测试')
|
||||||
|
|
||||||
self.addSubInterface(self.aboutInterface, FluentIcon.INFO, '关于', position=NavigationItemPosition.BOTTOM)
|
self.addSubInterface(self.aboutInterface, FluentIcon.INFO, '关于', position=NavigationItemPosition.BOTTOM)
|
||||||
@@ -45,7 +46,10 @@ class MainWindow(MSFluentWindow):
|
|||||||
self.setWindowIcon(QIcon(':/images/logo.png'))
|
self.setWindowIcon(QIcon(':/images/logo.png'))
|
||||||
|
|
||||||
def showError(self, title: str, message: str):
|
def showError(self, title: str, message: str):
|
||||||
MessageBox(title, message, self).exec()
|
box = MessageBox(title, message, self)
|
||||||
|
box.yesButton.setText("关闭")
|
||||||
|
box.cancelButton.hide()
|
||||||
|
box.exec()
|
||||||
|
|
||||||
def showEvent(self, event: QShowEvent):
|
def showEvent(self, event: QShowEvent):
|
||||||
super().showEvent(event)
|
super().showEvent(event)
|
||||||
|
|||||||
@@ -1,27 +1,132 @@
|
|||||||
from PySide6.QtCore import Qt
|
from PySide6.QtCore import Qt, Signal, QTimer
|
||||||
from PySide6.QtWidgets import QVBoxLayout, QHBoxLayout
|
from PySide6.QtWidgets import QVBoxLayout, QHBoxLayout, QWidget, QStackedWidget, QGridLayout, QFileDialog
|
||||||
from qfluentwidgets import GroupHeaderCardWidget, PushButton, FluentIcon, PrimaryPushButton, IconWidget, BodyLabel
|
from qfluentwidgets import GroupHeaderCardWidget, PushButton, FluentIcon, PrimaryPushButton, IconWidget, BodyLabel, \
|
||||||
|
SegmentedWidget, SpinBox, LargeTitleLabel, DisplayLabel, SubtitleLabel
|
||||||
|
|
||||||
|
from module.picker.schema import PickerExcel, PickerStudent
|
||||||
|
from ui.components.widget import RollingTextWidget
|
||||||
from ui import MAIN_THEME_COLOR
|
from ui import MAIN_THEME_COLOR
|
||||||
from ui.components.widget import Widget
|
from ui.components.widget import Widget
|
||||||
|
from ui.components.window import MyWindow
|
||||||
|
|
||||||
|
|
||||||
class PickerWidget(Widget):
|
class PSMMain(MyWindow):
|
||||||
def __init__(self, key: str, parent=None):
|
finishSignal = Signal()
|
||||||
super().__init__(key, parent)
|
|
||||||
|
def __init__(self, student: PickerStudent, parent=None):
|
||||||
|
super().__init__(parent)
|
||||||
|
|
||||||
|
self.student = student
|
||||||
|
self.grade_edit = SpinBox(self)
|
||||||
|
self.init_layout()
|
||||||
|
|
||||||
|
def init_layout(self):
|
||||||
|
main_layout = QVBoxLayout()
|
||||||
|
|
||||||
|
hLayout = QHBoxLayout()
|
||||||
|
name_layout = QVBoxLayout()
|
||||||
|
date_layout = QVBoxLayout()
|
||||||
|
hLayout.addStretch()
|
||||||
|
hLayout.addLayout(name_layout)
|
||||||
|
hLayout.addLayout(date_layout)
|
||||||
|
hLayout.addStretch()
|
||||||
|
hLayout.setSpacing(20)
|
||||||
|
|
||||||
|
so = LargeTitleLabel(f"{self.student.so}", self)
|
||||||
|
so.setAlignment(Qt.AlignCenter)
|
||||||
|
|
||||||
|
sname = DisplayLabel(
|
||||||
|
f"{self.student.name[0] + ' ' + self.student.name[1] if len(self.student.name) == 2 else self.student.name}",
|
||||||
|
self)
|
||||||
|
sname.setAlignment(Qt.AlignCenter)
|
||||||
|
|
||||||
|
name_layout.addWidget(so)
|
||||||
|
name_layout.addWidget(sname)
|
||||||
|
|
||||||
|
self.grade_edit.setFixedWidth(260)
|
||||||
|
self.grade_edit.setRange(0, 100)
|
||||||
|
grade_layout = QHBoxLayout()
|
||||||
|
grade_layout.setContentsMargins(0, 0, 0, 48)
|
||||||
|
grade_layout.setSpacing(20)
|
||||||
|
submit_button = PrimaryPushButton("确定", self)
|
||||||
|
cancel_button = PushButton("重置", self)
|
||||||
|
submit_button.clicked.connect(self.close_modal)
|
||||||
|
cancel_button.clicked.connect(lambda: self.grade_edit.clear())
|
||||||
|
submit_button.setFixedWidth(120)
|
||||||
|
cancel_button.setFixedWidth(120)
|
||||||
|
grade_layout.addWidget(submit_button)
|
||||||
|
grade_layout.addWidget(cancel_button)
|
||||||
|
date_layout.addWidget(self.grade_edit)
|
||||||
|
date_layout.addLayout(grade_layout)
|
||||||
|
|
||||||
|
main_layout.addStretch()
|
||||||
|
main_layout.addLayout(hLayout)
|
||||||
|
main_layout.addStretch()
|
||||||
|
|
||||||
|
# 快速打分
|
||||||
|
quick_grade_layout = QVBoxLayout()
|
||||||
|
quick_grade_layout.setContentsMargins(0, 0, 0, 0)
|
||||||
|
quick_grade_layout.setSpacing(20)
|
||||||
|
|
||||||
|
quick_grade_title = SubtitleLabel("快速打分", self)
|
||||||
|
quick_grade_title.setAlignment(Qt.AlignCenter)
|
||||||
|
|
||||||
|
quick_grade_layout.addWidget(quick_grade_title)
|
||||||
|
|
||||||
|
grid_wrapper_layout = QHBoxLayout()
|
||||||
|
grid_layout = QGridLayout()
|
||||||
|
buttons = [0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100]
|
||||||
|
|
||||||
|
for i, num in enumerate(buttons):
|
||||||
|
row = i // 3
|
||||||
|
col = i % 3
|
||||||
|
btn = PushButton(str(num))
|
||||||
|
btn.setFixedSize(80, 80)
|
||||||
|
# 使用lambda绑定事件
|
||||||
|
btn.clicked.connect(lambda _, n=num: self.grade_edit.setValue(n))
|
||||||
|
grid_layout.addWidget(btn, row, col)
|
||||||
|
|
||||||
|
grid_wrapper_layout.addStretch()
|
||||||
|
grid_wrapper_layout.addLayout(grid_layout)
|
||||||
|
grid_wrapper_layout.addStretch()
|
||||||
|
|
||||||
|
quick_grade_layout.addLayout(grid_layout)
|
||||||
|
quick_grade_layout.addLayout(grid_wrapper_layout)
|
||||||
|
|
||||||
|
main_layout.addLayout(quick_grade_layout)
|
||||||
|
self.widgetLayout.addLayout(main_layout)
|
||||||
|
|
||||||
|
def close_modal(self):
|
||||||
|
self.student.append_score(self.grade_edit.value())
|
||||||
|
self.finishSignal.emit()
|
||||||
|
self.close()
|
||||||
|
|
||||||
|
|
||||||
|
class PickStudentMode(QWidget):
|
||||||
|
errorSignal = Signal(str)
|
||||||
|
|
||||||
|
def __init__(self, parent=None):
|
||||||
|
super().__init__(parent)
|
||||||
|
|
||||||
self.card = GroupHeaderCardWidget(self)
|
self.card = GroupHeaderCardWidget(self)
|
||||||
self.vbox = QVBoxLayout(self)
|
self.vbox = QVBoxLayout(self)
|
||||||
|
self.vbox.setContentsMargins(0, 0, 0, 0)
|
||||||
|
|
||||||
self.chooseBtn = PushButton("打开")
|
self.chooseBtn = PushButton("打开")
|
||||||
self.startButton = PrimaryPushButton(FluentIcon.PLAY_SOLID, "抽签")
|
self.startButton = PrimaryPushButton(FluentIcon.PLAY_SOLID, "开始")
|
||||||
self.bottomLayout = QHBoxLayout()
|
self.bottomLayout = QHBoxLayout()
|
||||||
self.hintIcon = IconWidget(FluentIcon.INFO.icon(color=MAIN_THEME_COLOR))
|
self.hintIcon = IconWidget(FluentIcon.INFO.icon(color=MAIN_THEME_COLOR))
|
||||||
self.hintLabel = BodyLabel("点击抽签按钮以开始抽签 👉")
|
self.hintLabel = BodyLabel("点击开始按钮以开始抽签 👉")
|
||||||
|
self.spinbox = SpinBox()
|
||||||
|
self.rollingText = RollingTextWidget(self)
|
||||||
|
|
||||||
self.card.setTitle("输入选项")
|
self.card.setTitle("输入选项")
|
||||||
self.chooseBtn.setFixedWidth(120)
|
self.chooseBtn.setFixedWidth(120)
|
||||||
self.startButton.setFixedWidth(120)
|
self.startButton.setFixedWidth(120)
|
||||||
self.startButton.setEnabled(False)
|
self.startButton.setEnabled(False)
|
||||||
|
self.spinbox.setRange(0, 6)
|
||||||
|
self.spinbox.setFixedWidth(120)
|
||||||
|
self.spinbox.setEnabled(False)
|
||||||
|
|
||||||
self.hintIcon.setFixedSize(16, 16)
|
self.hintIcon.setFixedSize(16, 16)
|
||||||
self.hintIcon.autoFillBackground()
|
self.hintIcon.autoFillBackground()
|
||||||
@@ -33,9 +138,111 @@ class PickerWidget(Widget):
|
|||||||
self.bottomLayout.addWidget(self.startButton, 0, Qt.AlignRight)
|
self.bottomLayout.addWidget(self.startButton, 0, Qt.AlignRight)
|
||||||
self.bottomLayout.setAlignment(Qt.AlignVCenter)
|
self.bottomLayout.setAlignment(Qt.AlignVCenter)
|
||||||
|
|
||||||
self.group = self.card.addGroup(FluentIcon.DOCUMENT, "抽答名单", "选择抽答名单", self.chooseBtn)
|
self.group = self.card.addGroup(FluentIcon.DOCUMENT, "提问名单", "选择提问名单", self.chooseBtn)
|
||||||
self.group.setSeparatorVisible(True)
|
self.spinGroup = self.card.addGroup(FluentIcon.SETTING, "提问次数", "设置提问的最大次数", self.spinbox)
|
||||||
|
self.spinGroup.setSeparatorVisible(True)
|
||||||
self.card.vBoxLayout.addLayout(self.bottomLayout)
|
self.card.vBoxLayout.addLayout(self.bottomLayout)
|
||||||
|
|
||||||
self.vbox.addWidget(self.card)
|
self.vbox.addWidget(self.card)
|
||||||
|
self.vbox.addWidget(self.rollingText)
|
||||||
self.vbox.addStretch(1)
|
self.vbox.addStretch(1)
|
||||||
|
|
||||||
|
# ==============================
|
||||||
|
self.chooseBtn.clicked.connect(self.choose_file)
|
||||||
|
self.spinbox.valueChanged.connect(lambda: PickerExcel.save_total_time(value=self.spinbox.value()))
|
||||||
|
self.startButton.clicked.connect(self.start_rolling)
|
||||||
|
self.rollingText.finishSignal.connect(self.finish_rolling)
|
||||||
|
# ==============================
|
||||||
|
self.filepath = ""
|
||||||
|
self.students = []
|
||||||
|
|
||||||
|
def choose_file(self):
|
||||||
|
file_path, _ = QFileDialog.getOpenFileName(self, "选择文件", "", "Excel 文件 (*.xlsm);")
|
||||||
|
if file_path:
|
||||||
|
self.group.setContent("已选择文件:" + file_path)
|
||||||
|
self.filepath = file_path
|
||||||
|
self.startButton.setEnabled(True)
|
||||||
|
self.init_spinbox_value()
|
||||||
|
|
||||||
|
def init_spinbox_value(self):
|
||||||
|
if not self.filepath:
|
||||||
|
return
|
||||||
|
|
||||||
|
try:
|
||||||
|
PickerExcel.open(self.filepath)
|
||||||
|
self.spinbox.setValue(PickerExcel.read_total_time())
|
||||||
|
self.spinbox.setEnabled(True)
|
||||||
|
except Exception as e:
|
||||||
|
self.errorSignal.emit(str(e))
|
||||||
|
self.spinbox.setEnabled(False)
|
||||||
|
self.startButton.setEnabled(False)
|
||||||
|
|
||||||
|
def start_rolling(self):
|
||||||
|
self.students = PickerExcel.read_student()
|
||||||
|
self.rollingText.set_items(self.students)
|
||||||
|
self.rollingText.start_rolling()
|
||||||
|
self.startButton.setEnabled(False)
|
||||||
|
|
||||||
|
def finish_rolling(self):
|
||||||
|
stu = PickerStudent.pick(self.students)
|
||||||
|
if not (stu.so and stu.name):
|
||||||
|
self.errorSignal.emit("学生信息读取失败")
|
||||||
|
self.rollingText.label.setText(stu.name)
|
||||||
|
|
||||||
|
timer = QTimer(self)
|
||||||
|
timer.setSingleShot(True)
|
||||||
|
timer.timeout.connect(lambda: self.show_screen(stu))
|
||||||
|
timer.timeout.connect(lambda: self.startButton.setEnabled(True))
|
||||||
|
timer.start(1000)
|
||||||
|
|
||||||
|
def show_screen(self, stu: PickerStudent):
|
||||||
|
screen = PSMMain(stu)
|
||||||
|
screen.finishSignal.connect(lambda: PickerExcel.write_back(stu))
|
||||||
|
screen.finishSignal.connect(lambda: self.rollingText.label.clear())
|
||||||
|
|
||||||
|
|
||||||
|
class PickQuestionMode(QWidget):
|
||||||
|
def __init__(self, parent=None):
|
||||||
|
super().__init__(parent)
|
||||||
|
|
||||||
|
lable = DisplayLabel('🚧', self)
|
||||||
|
lable.setAlignment(Qt.AlignCenter)
|
||||||
|
self.layout = QHBoxLayout(self)
|
||||||
|
self.layout.addStretch()
|
||||||
|
self.layout.addWidget(lable)
|
||||||
|
self.layout.addStretch()
|
||||||
|
|
||||||
|
|
||||||
|
class PickerWidget(Widget):
|
||||||
|
errorSignal = Signal(str, str)
|
||||||
|
|
||||||
|
def __init__(self, key: str, parent=None):
|
||||||
|
super().__init__(key, parent)
|
||||||
|
|
||||||
|
self.vbox = QVBoxLayout(self)
|
||||||
|
self.menu = SegmentedWidget(self)
|
||||||
|
self.stack = QStackedWidget(self)
|
||||||
|
|
||||||
|
self.psm = PickStudentMode(self)
|
||||||
|
self.pqm = PickQuestionMode(self)
|
||||||
|
|
||||||
|
self.add_sub_interface(self.psm, "pickStudentMode", "选人模式")
|
||||||
|
self.add_sub_interface(self.pqm, "pickQuestionMode", "选题模式")
|
||||||
|
self.menu.setCurrentItem("pickStudentMode")
|
||||||
|
|
||||||
|
self.vbox.addWidget(self.menu)
|
||||||
|
self.vbox.addWidget(self.stack)
|
||||||
|
self.vbox.addStretch(1)
|
||||||
|
|
||||||
|
# ===========================
|
||||||
|
self.stack.currentChanged.connect(self.on_stack_index_changed)
|
||||||
|
self.psm.errorSignal.connect(lambda n: self.errorSignal.emit("😢 不好出错了", n))
|
||||||
|
|
||||||
|
def add_sub_interface(self, widget: QWidget, obj_name: str, text: str):
|
||||||
|
widget.setObjectName(obj_name)
|
||||||
|
self.stack.addWidget(widget)
|
||||||
|
self.menu.addItem(routeKey=obj_name, text=text, onClick=lambda: self.stack.setCurrentWidget(widget))
|
||||||
|
|
||||||
|
def on_stack_index_changed(self, index: int):
|
||||||
|
widget = self.stack.widget(index)
|
||||||
|
self.stack.setCurrentWidget(widget)
|
||||||
|
|||||||
Reference in New Issue
Block a user