diff --git a/.claude/settings.local.json b/.claude/settings.local.json index 7e1c1b0..4bea94e 100644 --- a/.claude/settings.local.json +++ b/.claude/settings.local.json @@ -6,7 +6,8 @@ "Bash(venv/Scripts/python.exe -c ' *)", "Bash(venv/Scripts/python.exe -c \"import py_compile; py_compile.compile\\('taskForm.py', doraise=True\\)\")", "Bash(venv/Scripts/pip list *)", - "Bash(venv/Scripts/pip install *)" + "Bash(venv/Scripts/pip install *)", + "Bash(git checkout *)" ] } } diff --git a/devModelForm.py b/devModelForm.py index 885b658..31ce535 100644 --- a/devModelForm.py +++ b/devModelForm.py @@ -63,8 +63,10 @@ class DevModelForm(QWidget): self.ui.tableViewInterFaceType.setModel(self.interFaceTypeModel) self.ui.tableViewProperty.setModel(self.propertyModel) self.ui.tableViewDmGroup.setModel(self.dmGroupModel) - self.current_groupId = None + self.current_groupId = None self.topWidget = None + self._dmSortCol = 2 + self._dmSortOrder = Qt.SortOrder.AscendingOrder self.interfaceTypes = [] self.createInstructionDlg.createFinished.connect(self.handleDevModelSelection) self.createInstructionDlg.editFinished.connect(self.handleDevModelSelection) @@ -102,6 +104,9 @@ class DevModelForm(QWidget): self.interFaceTypeModel.itemChanged.connect(self.updateProperty) self.propertyModel.itemChanged.connect(self.updateProperty) self.batchSetItemDelegate() + self.ui.tableViewModel.horizontalHeader().sortIndicatorChanged.connect( + lambda col, order: setattr(self, '_dmSortCol', col) or setattr(self, '_dmSortOrder', order) + ) self.setSplitterStretchFactor() self.loadInterFaceTypes() @@ -128,6 +133,7 @@ class DevModelForm(QWidget): self.ui.tableViewModel.verticalHeader().setDefaultAlignment(Qt.AlignmentFlag.AlignHCenter|Qt.AlignmentFlag.AlignVCenter) self.ui.tableViewCmd.verticalHeader().setDefaultAlignment(Qt.AlignmentFlag.AlignHCenter|Qt.AlignmentFlag.AlignVCenter) self.ui.tableViewModel.horizontalHeader().setDefaultAlignment(Qt.AlignmentFlag.AlignLeft|Qt.AlignmentFlag.AlignVCenter) + self.ui.tableViewModel.horizontalHeader().setSortIndicatorShown(True) self.ui.tableViewCmd.horizontalHeader().setDefaultAlignment(Qt.AlignmentFlag.AlignLeft|Qt.AlignmentFlag.AlignVCenter) self.ui.tableViewInterFaceType.horizontalHeader().setDefaultAlignment(Qt.AlignmentFlag.AlignLeft|Qt.AlignmentFlag.AlignVCenter) self.ui.tableViewProperty.horizontalHeader().setDefaultAlignment(Qt.AlignmentFlag.AlignLeft|Qt.AlignmentFlag.AlignVCenter) @@ -136,6 +142,7 @@ class DevModelForm(QWidget): self.ui.tableViewProperty.setItemDelegate(AlignDelegate(self.ui.tableViewProperty)) self.ui.tableViewCmd.setItemDelegate(AlignNoDelegate(self.ui.tableViewCmd)) self.ui.tableViewDmGroup.setItemDelegate(AlignDelegate(self.ui.tableViewDmGroup)) + self.ui.tableViewModel.horizontalHeader().setSortIndicator(2, Qt.SortOrder.AscendingOrder) def dmGroupDropEvent(self, event: QDropEvent): if event.source() != self: @@ -723,6 +730,7 @@ class DevModelForm(QWidget): self.ui.textEditDescription.clear() if len(devModels) > 0: self.devModelModel.blockSignals(True) + self.ui.tableViewModel.setSortingEnabled(False) self.ui.tableViewModel.setUpdatesEnabled(False) for data in devModels: index = self.devModelModel.rowCount() @@ -732,7 +740,9 @@ class DevModelForm(QWidget): self.devModelModel.setItem(index, 3, QStandardItem(data["category"])) self.devModelModel.blockSignals(False) self.ui.tableViewModel.setUpdatesEnabled(True) - self.ui.tableViewModel.sortByColumn(2, Qt.SortOrder.AscendingOrder) + self.devModelModel.sort(self._dmSortCol, self._dmSortOrder) + self.ui.tableViewModel.setSortingEnabled(True) + self.ui.tableViewModel.horizontalHeader().setSortIndicator(self._dmSortCol, self._dmSortOrder) self.batchOperation() # 更新属性 diff --git a/deviceForm.py b/deviceForm.py index a2bf082..287b56f 100644 --- a/deviceForm.py +++ b/deviceForm.py @@ -83,6 +83,8 @@ class DeviceForm(QWidget): self.selectedDeviceModelId = None self.devGroupModelBlockSignals = False self.current_groupId = None + self._devSortCol = 3 + self._devSortOrder = Qt.SortOrder.AscendingOrder self.interfaceTypes = [] self.confInterfaces = [] self.realInterfaces = {} @@ -118,6 +120,9 @@ class DeviceForm(QWidget): self.ui.pbDeleteDevGroup.clicked.connect(self.deleteDevGroup) self.setSplitterStretchFactor() self.batchSetItemDelegate() + self.ui.tableViewDevice.horizontalHeader().sortIndicatorChanged.connect( + lambda col, order: setattr(self, '_devSortCol', col) or setattr(self, '_devSortOrder', order) + ) taskActuatorManager.updateInstructProgress.connect(self._onUpdateInstructProgress) def showCreateDevDlg(self): @@ -128,6 +133,7 @@ class DeviceForm(QWidget): self.ui.tableViewDevice.verticalHeader().setDefaultAlignment(Qt.AlignmentFlag.AlignHCenter|Qt.AlignmentFlag.AlignVCenter) self.ui.tableViewDevCmd.verticalHeader().setDefaultAlignment(Qt.AlignmentFlag.AlignHCenter|Qt.AlignmentFlag.AlignVCenter) self.ui.tableViewDevice.horizontalHeader().setDefaultAlignment(Qt.AlignmentFlag.AlignLeft|Qt.AlignmentFlag.AlignVCenter) + self.ui.tableViewDevice.horizontalHeader().setSortIndicatorShown(True) self.ui.tableViewDevCmd.horizontalHeader().setDefaultAlignment(Qt.AlignmentFlag.AlignLeft|Qt.AlignmentFlag.AlignVCenter) self.ui.tableViewInterFace.horizontalHeader().setDefaultAlignment(Qt.AlignmentFlag.AlignLeft|Qt.AlignmentFlag.AlignVCenter) self.ui.tableViewProperty.horizontalHeader().setDefaultAlignment(Qt.AlignmentFlag.AlignLeft|Qt.AlignmentFlag.AlignVCenter) @@ -136,6 +142,7 @@ class DeviceForm(QWidget): self.ui.tableViewDevice.setItemDelegate(AlignNoDelegate(self.ui.tableViewDevice,2)) self.ui.tableViewDevCmd.setItemDelegate(AlignNoDelegate(self.ui.tableViewDevCmd)) self.ui.tableViewDevGroup.setItemDelegate(AlignDelegate(self.ui.tableViewDevGroup)) + self.ui.tableViewDevice.horizontalHeader().setSortIndicator(3, Qt.SortOrder.AscendingOrder) def devGroupDropEvent(self, event: QDropEvent): if event.source() != self: @@ -429,6 +436,7 @@ class DeviceForm(QWidget): self.ui.textEditDescription.clear() if len(devices) > 0: self.deviceModel.blockSignals(True) + self.ui.tableViewDevice.setSortingEnabled(False) self.ui.tableViewDevice.setUpdatesEnabled(False) for device in devices: index = self.deviceModel.rowCount() @@ -441,7 +449,9 @@ class DeviceForm(QWidget): self.deviceModel.setItem(index, 4, QxStandardItem(devModel["name"], max_length=8)) self.deviceModel.blockSignals(False) self.ui.tableViewDevice.setUpdatesEnabled(True) - self.ui.tableViewDevice.sortByColumn(3, Qt.SortOrder.AscendingOrder) + self.deviceModel.sort(self._devSortCol, self._devSortOrder) + self.ui.tableViewDevice.setSortingEnabled(True) + self.ui.tableViewDevice.horizontalHeader().setSortIndicator(self._devSortCol, self._devSortOrder) self.batchOperation() # 任务分组选中 diff --git a/insertInstructionDlg.py b/insertInstructionDlg.py index d500231..b41d41b 100644 --- a/insertInstructionDlg.py +++ b/insertInstructionDlg.py @@ -23,6 +23,7 @@ class InsertInstructionDlg(QDialog): self.supportedTypes = instructionManager.getSupportedType() self.targetType = "instruction" self.instructionPosition = -1 + self.replaceIds = [] self.interface_index = 0 self.deviceModel = QStandardItemModel() self.devGroupModel = QStandardItemModel() @@ -59,13 +60,44 @@ class InsertInstructionDlg(QDialog): self.ui.pbCancel.clicked.connect(self.reject) def handleSave(self): - for row in range(self.instructionModel.rowCount()): - target_id = self.instructionModel.item(row, 0).text() - device_id = self.instructionModel.item(row, 1).text() - interface_index = self.instructionModel.item(row, 4).text() - level = self.instructionPosition + row - - param = { + if self.replaceIds: + for rid in self.replaceIds: + taskInstructionManager.delete(rid) + # re-number remaining instructions to fill the gap + remaining = taskInstructionManager.getTaskInstructions(self.taskId) + remaining.sort(key=lambda x: x["level"]) + for i, inst in enumerate(remaining): + taskInstructionManager.update(inst["id"], {"level": i}) + # insert new instructions at position, shifting others up + count = self.instructionModel.rowCount() + remaining2 = taskInstructionManager.getTaskInstructions(self.taskId) + remaining2.sort(key=lambda x: x["level"]) + for inst in remaining2: + if inst["level"] >= self.instructionPosition: + taskInstructionManager.update(inst["id"], {"level": inst["level"] + count}) + for row in range(count): + target_id = self.instructionModel.item(row, 0).text() + device_id = self.instructionModel.item(row, 1).text() + interface_index = self.instructionModel.item(row, 4).text() + param = { + 'task_id': self.taskId, + 'device_id': device_id, + 'loop': 1, + 'delay': 0, + 'target_type': self.targetType, + 'target_id': target_id, + 'interface_index': interface_index, + 'level': self.instructionPosition + row + } + if taskInstructionManager.create(param) == "": + print("insert error") + else: + for row in range(self.instructionModel.rowCount()): + target_id = self.instructionModel.item(row, 0).text() + device_id = self.instructionModel.item(row, 1).text() + interface_index = self.instructionModel.item(row, 4).text() + level = self.instructionPosition + row + param = { 'task_id': self.taskId, 'device_id': device_id, 'loop': 1, @@ -74,15 +106,15 @@ class InsertInstructionDlg(QDialog): 'target_id': target_id, 'interface_index': interface_index, 'level': level - } - id = taskInstructionManager.create(param) - if id == "": - print("insert error") - self.accept() - + } + if taskInstructionManager.create(param) == "": + print("insert error") + self.accept() + def showDlg(self, taskId, position): self.taskId = taskId self.instructionPosition = position + self.replaceIds = [] self.setWindowTitle('插入指令') self.deviceModel.clear() self.devInstructionModel.clear() @@ -90,6 +122,17 @@ class InsertInstructionDlg(QDialog): self.loadDevGroup() self.exec() + def showReplaceDlg(self, taskId, position, replaceIds): + self.taskId = taskId + self.instructionPosition = position + self.replaceIds = replaceIds + self.setWindowTitle('替换指令') + self.deviceModel.clear() + self.devInstructionModel.clear() + self.instructionModel.clear() + self.loadDevGroup() + self.exec() + def batchOperation(self): self.setAllColumnWidth() self.hideAllColumn() diff --git a/mainWindow.py b/mainWindow.py index ee0733b..b04d821 100644 --- a/mainWindow.py +++ b/mainWindow.py @@ -104,7 +104,7 @@ class MainWindow(QMainWindow): self.ui = Ui_MainWindow() self.ui.setupUi(self) self.ui.tbDefault.setVisible(False) - self.isDebugQML = True #DEBUG + self.isDebugQML = False #DEBUG self.setWindowTitle("TG-TestingPlatform "+app_version.data["version"]) self.ui.lbtitle.setText("TG-TestingPlatform "+app_version.data["version"]) self.ui.logWidget.setVisible(True) diff --git a/models.py b/models.py index 3a1f052..208ea89 100644 --- a/models.py +++ b/models.py @@ -2,7 +2,7 @@ # -*- coding:utf-8 -*- from sqlalchemy import Column, Integer, String, create_engine -from sqlalchemy.orm import sessionmaker, declarative_base +from sqlalchemy.orm import sessionmaker, scoped_session, declarative_base from concurrent.futures import ThreadPoolExecutor import os import json @@ -13,7 +13,7 @@ from logs import log dataDB = os.path.join(os.path.dirname(__file__),'data.db') engine = create_engine(f'sqlite:///{dataDB}') -SessionMaker = sessionmaker(bind=engine)() +SessionMaker = scoped_session(sessionmaker(bind=engine)) platform_path1 = config.data["project"]["platform_path1"] platform_path2 = config.data["project"]["platform_path2"] @@ -305,7 +305,7 @@ class Session(): log.error(e) return False, None finally: - SessionMaker.close() + SessionMaker.remove() def addByClassFromGit(self, cls, _data): try: @@ -325,7 +325,7 @@ class Session(): log.error(e) return False, None finally: - SessionMaker.close() + SessionMaker.remove() def queryTaskByTargetType(self, cls, _target_type): try: @@ -530,7 +530,7 @@ class Session(): log.error(e) return False, None finally: - SessionMaker.close() + SessionMaker.remove() def deleteById(self, cls, _id): try: @@ -548,7 +548,7 @@ class Session(): log.error(e) return False, None finally: - SessionMaker.close() + SessionMaker.remove() def deleteByIds(self, cls, ids): try: @@ -567,7 +567,7 @@ class Session(): log.error(e) return False, None finally: - SessionMaker.close() + SessionMaker.remove() def deleteByName(self, cls, _name): try: @@ -585,7 +585,7 @@ class Session(): log.error(e) return False, None finally: - SessionMaker.close() + SessionMaker.remove() def deleteAllTable(self): try: @@ -609,6 +609,6 @@ class Session(): log.error(e) return False finally: - SessionMaker.close() + SessionMaker.remove() Session = Session() diff --git a/taskForm.py b/taskForm.py index e6d4d39..cb03d61 100644 --- a/taskForm.py +++ b/taskForm.py @@ -52,18 +52,17 @@ class ProgressBarDelegate(QStyledItemDelegate): # 没有有效进度值时不绘制 if value < 0 or maximum < 1: return - progress_rect = option.rect # 进度条的矩形边界 - progress_width = int((value / maximum) * progress_rect.width()) # 计算进度条的宽度 + if value >= maximum: + value = 0 + progress_rect = option.rect + progress_width = int((value / maximum) * progress_rect.width()) progress_rect.adjust(2, 2, -2, -2) - # 绘制进度条背景 painter.fillRect(progress_rect, QColor("#F8FAFF")) - # 绘制实际数值文本 text = f"{value}/{maximum}" text_rect = QRect(option.rect) pen = painter.pen() pen.setColor(Qt.GlobalColor.black) painter.setPen(pen) - # 绘制实际进度 progress_rect.setWidth(progress_width) painter.fillRect(progress_rect, QColor("#007EFF")) painter.drawText(text_rect, Qt.AlignmentFlag.AlignCenter, text) @@ -90,6 +89,8 @@ class TaskForm(QWidget): self.insertTaskDlg = InsertTaskDlg() self.current_groupId = None self.topWidget = None + self._taskSortCol = 2 + self._taskSortOrder = Qt.SortOrder.AscendingOrder self.taskModel = QStandardItemModel() self.taskGroupModel = QStandardItemModel() self.taskDetailModel = QStandardItemModel() @@ -115,7 +116,11 @@ class TaskForm(QWidget): self.ui.pbCopyTask.clicked.connect(self.copyTask) self.ui.pbExportTask.clicked.connect(self.exportTask) self.ui.tableViewTaskDetail.setModel(self.taskDetailModel) + self.ui.tableViewTaskDetail.setSelectionMode(QAbstractItemView.SelectionMode.ExtendedSelection) self.ui.tableViewTaskDetail.doubleClicked.connect(self.editTaskDetail) + self.ui.tableViewTaskDetail.dropEvent = self.taskDetailDropEvent + self._sortModeActive = False + self.ui.tableViewTaskDetail.keyPressEvent = self._taskDetailKeyPress self.ui.tableViewTaskDetail.selectionModel().selectionChanged.connect(self.handleTaskDetailSelection) self.ui.pbCreateGroup.clicked.connect(self.createGroup) self.ui.pbDeleteGroup.clicked.connect(self.deleteGroup) @@ -136,12 +141,16 @@ class TaskForm(QWidget): self.ui.tableViewTask.selectionModel().selectionChanged.connect(self.handleTaskSelection) self.setSplitterStretchFactor() self.batchSetItemDelegate() + self.ui.tableViewTask.horizontalHeader().sortIndicatorChanged.connect( + lambda col, order: setattr(self, '_taskSortCol', col) or setattr(self, '_taskSortOrder', order) + ) taskActuatorManager.updateProgress.connect(self._onUpdateProgress) taskActuatorManager.taskStop.connect(self._onTaskStop) taskActuatorManager.taskStart.connect(self._onTaskStart) def batchSetItemDelegate(self): self.ui.tableViewTask.horizontalHeader().setDefaultAlignment(Qt.AlignmentFlag.AlignLeft|Qt.AlignmentFlag.AlignVCenter) + self.ui.tableViewTask.horizontalHeader().setSortIndicatorShown(True) self.ui.tableViewTaskGroup.horizontalHeader().setDefaultAlignment(Qt.AlignmentFlag.AlignLeft|Qt.AlignmentFlag.AlignVCenter) self.ui.tableViewTaskDetail.horizontalHeader().setDefaultAlignment(Qt.AlignmentFlag.AlignLeft|Qt.AlignmentFlag.AlignVCenter) self.ui.tableViewTask.setItemDelegate(AlignTaskNoDelegate(self.ui.tableViewTask)) @@ -163,7 +172,9 @@ class TaskForm(QWidget): # 双击编辑任务功能 def editTaskDetail(self, index): rows = self.ui.tableViewTaskDetail.selectionModel().selectedRows() - if len(rows) == 1: + if index.column() == 4 and len(rows) >= 1: + self.replaceInstruction() + elif len(rows) == 1: row = rows[0].row() if index.column() == 3: row_id_index = self.taskDetailModel.index(row, 0, QModelIndex()) @@ -422,6 +433,10 @@ class TaskForm(QWidget): self.ui.tableViewTaskDetail.setColumnHidden(8, True) self.ui.tableViewTaskDetail.setColumnHidden(7, True) self.ui.tableViewTaskDetail.setColumnHidden(6, True) + self.ui.tableViewTaskDetail.setDragEnabled(False) + self.ui.tableViewTaskDetail.setAcceptDrops(False) + self.ui.tableViewTaskDetail.setDragDropMode(QAbstractItemView.DragDropMode.NoDragDrop) + self._sortModeActive = True self.setAllColumnWidth() def hideSortBtn(self): @@ -438,8 +453,21 @@ class TaskForm(QWidget): self.ui.tableViewTaskDetail.setColumnHidden(8, False) self.ui.tableViewTaskDetail.setColumnHidden(7, False) self.ui.tableViewTaskDetail.setColumnHidden(6, False) - self.setAllColumnWidth() - + self.ui.tableViewTaskDetail.setDragEnabled(False) + self.ui.tableViewTaskDetail.setAcceptDrops(False) + self.ui.tableViewTaskDetail.setDragDropMode(QAbstractItemView.DragDropMode.NoDragDrop) + self._sortModeActive = False + + def _taskDetailKeyPress(self, event): + if self._sortModeActive: + if event.key() == Qt.Key.Key_Up: + self.handleUpClick() + return + elif event.key() == Qt.Key.Key_Down: + self.handleDownClick() + return + QTableView.keyPressEvent(self.ui.tableViewTaskDetail, event) + def insertTask(self): if len(self.ui.tableViewTask.selectionModel().selectedRows())== 1: row = self.ui.tableViewTask.selectionModel().selectedRows()[0].row() @@ -454,6 +482,22 @@ class TaskForm(QWidget): position = self.taskDetailModel.rowCount() self.insertInstructionDlg.showDlg(taskId, position) + def replaceInstruction(self): + if len(self.ui.tableViewTask.selectionModel().selectedRows()) != 1: + return + taskRow = self.ui.tableViewTask.selectionModel().selectedRows()[0].row() + taskId = self.taskModel.item(taskRow, 0).text() + selectedRows = sorted(self.ui.tableViewTaskDetail.selectionModel().selectedRows(), key=lambda x: x.row()) + if not selectedRows: + return + position = selectedRows[0].row() + replaceIds = [] + for r in selectedRows: + row = r.row() + tid = self.taskDetailModel.index(row, 0, QModelIndex()) + replaceIds.append(self.taskDetailModel.data(tid, Qt.ItemDataRole.DisplayRole)) + self.insertInstructionDlg.showReplaceDlg(taskId, position, replaceIds) + def createTaskFinished(self): self.loadTask() if self.taskModel.rowCount() > 0: @@ -524,23 +568,56 @@ class TaskForm(QWidget): self.ui.textEditDescription.clear() self.clearTreeModel() + def taskDetailDropEvent(self, event): + target_index = self.ui.tableViewTaskDetail.indexAt(event.position().toPoint()) + target_row = target_index.row() if target_index.isValid() else self.taskDetailModel.rowCount() + selected_rows = sorted( + [r.row() for r in self.ui.tableViewTaskDetail.selectionModel().selectedRows()] + ) + if not selected_rows or target_row in selected_rows: + event.ignore() + return + rows_data = [self.taskDetailModel.takeRow(r) for r in selected_rows] + # adjust target after removal + removed_before = sum(1 for r in selected_rows if r < target_row) + insert_at = target_row - removed_before + for i, row_data in enumerate(rows_data): + self.taskDetailModel.insertRow(insert_at + i, row_data) + self.ui.tableViewTaskDetail.clearSelection() + for i in range(len(rows_data)): + self.ui.tableViewTaskDetail.selectionModel().select( + self.taskDetailModel.index(insert_at + i, 0), + QItemSelectionModel.SelectionFlag.Select | QItemSelectionModel.SelectionFlag.Rows + ) + event.accept() + def handleUpClick(self): - selectRows = self.ui.tableViewTaskDetail.selectionModel().selectedRows() - if len(selectRows) == 1: - row = selectRows[0].row() - if row > 0: - item = self.taskDetailModel.takeRow(row) - self.taskDetailModel.insertRow(row - 1, item) - self.ui.tableViewTaskDetail.selectRow(row - 1) - + rows = sorted([r.row() for r in self.ui.tableViewTaskDetail.selectionModel().selectedRows()]) + if not rows or rows[0] == 0: + return + for row in rows: + item = self.taskDetailModel.takeRow(row) + self.taskDetailModel.insertRow(row - 1, item) + self.ui.tableViewTaskDetail.clearSelection() + for row in rows: + self.ui.tableViewTaskDetail.selectionModel().select( + self.taskDetailModel.index(row - 1, 0), + QItemSelectionModel.SelectionFlag.Select | QItemSelectionModel.SelectionFlag.Rows + ) + def handleDownClick(self): - selectRows = self.ui.tableViewTaskDetail.selectionModel().selectedRows() - if len(selectRows) == 1: - row = selectRows[0].row() - if row < self.taskDetailModel.rowCount() - 1: - item = self.taskDetailModel.takeRow(row) - self.taskDetailModel.insertRow(row + 1, item) - self.ui.tableViewTaskDetail.selectRow(row + 1) + rows = sorted([r.row() for r in self.ui.tableViewTaskDetail.selectionModel().selectedRows()], reverse=True) + if not rows or rows[0] == self.taskDetailModel.rowCount() - 1: + return + for row in rows: + item = self.taskDetailModel.takeRow(row) + self.taskDetailModel.insertRow(row + 1, item) + self.ui.tableViewTaskDetail.clearSelection() + for row in rows: + self.ui.tableViewTaskDetail.selectionModel().select( + self.taskDetailModel.index(row + 1, 0), + QItemSelectionModel.SelectionFlag.Select | QItemSelectionModel.SelectionFlag.Rows + ) def refreshSelect(self): selectedRows = self.ui.tableViewTaskGroup.selectionModel().selectedRows() @@ -910,6 +987,7 @@ class TaskForm(QWidget): tasks = taskManager.getGroupTask(self.current_groupId) self.taskModelBlockSignals = True self.taskModel.blockSignals(True) + self.ui.tableViewTask.setSortingEnabled(False) self.ui.tableViewTask.setUpdatesEnabled(False) if len(tasks) > 0: self.ui.tableViewTask.setItemDelegateForColumn(6, ProgressBarDelegate()) @@ -938,6 +1016,9 @@ class TaskForm(QWidget): self.taskModel.blockSignals(False) self.ui.tableViewTask.setUpdatesEnabled(True) self.taskModelBlockSignals = False + self.taskModel.sort(self._taskSortCol, self._taskSortOrder) + self.ui.tableViewTask.setSortingEnabled(True) + self.ui.tableViewTask.horizontalHeader().setSortIndicator(self._taskSortCol, self._taskSortOrder) self.batchOperation() def _onUpdateProgress(self, taskId, value, maxValue): diff --git a/taskListForm.py b/taskListForm.py index 1690afa..8cd4d0b 100644 --- a/taskListForm.py +++ b/taskListForm.py @@ -26,6 +26,8 @@ class ProgressBarDelegate(QStyledItemDelegate): # 没有有效进度值时不绘制 if value < 0 or maximum < 1: return + if value >= maximum: + value = 0 rect = option.rect # 缩小一圈(与任务列表一致) rect.adjust(4, 4, -4, -4) @@ -220,9 +222,6 @@ class TaskListForm(QWidget): taskId = str(taskId) # 更新缓存 self.progressCache[taskId] = {'value': value, 'maximum': maxValue} - # 完成时清理缓存 - if value >= maxValue and maxValue > 0: - self.progressCache.pop(taskId, None) # 优先从索引查找(O(1)) progressItem = self.progressItemMap.get(taskId) if progressItem is not None: diff --git a/taskModel/taskActuator.py b/taskModel/taskActuator.py index 084c55c..1260b09 100644 --- a/taskModel/taskActuator.py +++ b/taskModel/taskActuator.py @@ -152,7 +152,8 @@ class TaskActuator(QThread): common.getTaskDetails(taskInstructions) self.subTaskActuator.updateDetails.connect(self.onUpdateDetails, type=Qt.ConnectionType.DirectConnection) self.subTaskActuator.execute(taskInstructions, taskInfo) - self.subTaskActuator.wait() + while self.subTaskActuator.isRunning() and self.running: + self.subTaskActuator.wait(50) self.currentTask.callBack(6) time.sleep(target_delay) @@ -169,6 +170,11 @@ class TaskActuator(QThread): else: self.updateDetails.emit(self.id, int( self.currentIndex + int(taskIndex*instructionListLength)), total) self.updateProgress.emit(self.id, int( self.currentIndex + int(taskIndex*instructionListLength)), total) + else: + if self.running: + progress_val = self.currentIndex % instructionListLength + self.updateProgress.emit(self.id, progress_val, instructionListLength) + self.updateDetails.emit(self.id, progress_val, instructionListLength) taskIndex += 1 self.currentTask.next() @@ -204,8 +210,9 @@ class TaskActuator(QThread): taskInfo = taskManager.getInfo(target_id) taskInstructions = taskInstructionManager.getInfo(target_id) common.getTaskDetails(taskInstructions) - self.subTaskActuator.execute(taskInstructions, taskInfo) - self.subTaskActuator.wait() + self.subTaskActuator.execute(taskInstructions, taskInfo) + while self.subTaskActuator.isRunning() and self.running: + self.subTaskActuator.wait(50) time.sleep(target_delay) # 子任务执行完毕 self.currentIndex += 1 @@ -344,21 +351,21 @@ class TaskActuator(QThread): self.running_lock.lock() self.running = False self.running_lock.unlock() - # 停止子任务 + if self.currentTask and hasattr(self.currentTask, 'isFinished'): + self.currentTask.isFinished = True if self.subTaskActuator and self.subTaskActuator.isRunning(): - self.subTaskActuator.stopSub() - self.updateDetails.emit(str(self.parentId) , -1, -1) - + self.subTaskActuator.stopSub() + self.updateDetails.emit(str(self.parentId), -1, -1) self.quit() - def stop(self): self.running_lock.lock() self.running = False self.running_lock.unlock() - # 停止子任务 + if self.currentTask and hasattr(self.currentTask, 'isFinished'): + self.currentTask.isFinished = True if self.subTaskActuator and self.subTaskActuator.isRunning(): - self.subTaskActuator.stopSub() + self.subTaskActuator.stopSub() self.quit() def forceStop(self): diff --git a/taskModel/taskActuatorManager.py b/taskModel/taskActuatorManager.py index cc0b333..9c17086 100644 --- a/taskModel/taskActuatorManager.py +++ b/taskModel/taskActuatorManager.py @@ -22,18 +22,24 @@ class _KillThread(QThread): def run(self): a = self.actuator if not a.wait(500): - for item in a.instructionList: - try: - iface = item.get("interface") - if iface: - from interfaceSession.interfaceManager import interfaceManager - interfaceManager.getSession(iface).unlock() - except Exception: - pass - a.terminate() - a.wait(200) + self._unlock_and_terminate(a) self.done.emit(a) + @staticmethod + def _unlock_and_terminate(a): + from interfaceSession.interfaceManager import interfaceManager + for item in a.instructionList: + try: + iface = item.get("interface") + if iface: + interfaceManager.getSession(iface).unlock() + except Exception: + pass + if a.subTaskActuator and a.subTaskActuator.isRunning(): + _KillThread._unlock_and_terminate(a.subTaskActuator) + a.terminate() + a.wait(200) + class TaskActuatorManager(QObject): logMsg = pyqtSignal(dict) @@ -134,6 +140,9 @@ class TaskActuatorManager(QObject): a.subTaskActuator.running_lock.lock() a.subTaskActuator.running = False a.subTaskActuator.running_lock.unlock() + if a.subTaskActuator.currentTask and hasattr(a.subTaskActuator.currentTask, 'isFinished'): + a.subTaskActuator.currentTask.isFinished = True + a.subTaskActuator.quit() a.quit() kt = _KillThread(a) kt.done.connect(self._onKillDone)