You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

718 lines
30 KiB
Python

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

import sys
import os
from PyQt5.QtCore import Qt, QTimer, QModelIndex, QSize, pyqtSignal, QFile, QTextStream
from PyQt5.QtGui import QBrush, QColor, QStandardItemModel, QStandardItem
from PyQt5.QtWidgets import (QTableView, QPushButton, QVBoxLayout, QWidget, QHBoxLayout,
QLabel, QMenu, QFileDialog, QDialog, QLineEdit,
QDialogButtonBox, QMessageBox, QHeaderView, QSplitter)
import qtawesome as qta
from datetime import datetime
from utils.DBModels.ProcedureModel import DatabaseManager
from UI.ProcedureManager.StepExecutor import StepExecutor
class HistoryViewerWidget(QWidget):
def __init__(self, dbManager, parent=None):
super().__init__(parent)
self.dbManager = dbManager
self.initUi()
self.loadStylesheet() # 加载样式表
self.loadHistory()
def loadStylesheet(self):
"""加载历史查看器样式表"""
try:
qssPath = "Static/HistoryViewer.qss"
qssFile = QFile(qssPath)
if qssFile.exists():
qssFile.open(QFile.ReadOnly | QFile.Text)
stream = QTextStream(qssFile)
stream.setCodec("UTF-8")
qss_content = stream.readAll()
qssFile.close()
# 应用样式表到当前widget
self.setStyleSheet(qss_content)
# 确保按钮样式生效 - 直接设置按钮样式
self.applyButtonStyles()
print(f"✅ HistoryViewer成功加载样式表: {qssPath}")
else:
print(f"⚠️ HistoryViewer样式表文件不存在: {qssPath}")
except Exception as e:
print(f"❌ HistoryViewer加载样式表失败: {str(e)}")
def applyButtonStyles(self):
"""直接应用按钮样式"""
# 删除按钮样式
delete_style = """
QPushButton#deleteHistoryButton {
color: white;
background-color: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,
stop: 0 #F87171, stop: 1 #DC2626);
border: 2px solid #DC2626;
font-weight: bold;
border-radius: 8px;
font-size: 14px;
padding: 10px 20px;
min-height: 40px;
min-width: 120px;
}
QPushButton#deleteHistoryButton:hover {
background-color: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,
stop: 0 #FCA5A5, stop: 1 #EF4444);
border: 2px solid #F87171;
}
"""
# 导出按钮样式
export_style = """
QPushButton#exportReportButton {
color: white;
background-color: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,
stop: 0 #34D399, stop: 1 #059669);
border: 2px solid #10B981;
font-weight: bold;
border-radius: 8px;
font-size: 14px;
padding: 10px 20px;
min-height: 40px;
min-width: 120px;
}
QPushButton#exportReportButton:hover {
background-color: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,
stop: 0 #6EE7B7, stop: 1 #10B981);
border: 2px solid #34D399;
}
"""
# 应用样式到按钮
if hasattr(self, 'deleteButton'):
self.deleteButton.setStyleSheet(delete_style)
if hasattr(self, 'exportButton'):
self.exportButton.setStyleSheet(export_style)
def initUi(self):
layout = QVBoxLayout()
layout.setContentsMargins(1, 1, 1, 1) # 极小边距
layout.setSpacing(1) # 极小间距
# 搜索栏 - 极度紧凑布局,固定高度
searchLayout = QHBoxLayout()
searchLayout.setContentsMargins(0, 0, 0, 0)
searchLayout.setSpacing(2)
self.searchEdit = QLineEdit()
self.searchEdit.setPlaceholderText("搜索规程...")
self.searchEdit.setMaximumHeight(20) # 限制搜索框高度
self.searchEdit.textChanged.connect(self.loadHistory)
searchLabel = QLabel("搜索:")
searchLabel.setMaximumHeight(20) # 限制标签高度
searchLayout.addWidget(searchLabel)
searchLayout.addWidget(self.searchEdit)
layout.addLayout(searchLayout, 0) # 拉伸因子为0不占用额外空间
# 历史记录表格 - 设置对象名称用于样式识别
self.table = QTableView()
self.table.setObjectName("historyTable") # 重要:设置对象名称
self.table.setEditTriggers(QTableView.NoEditTriggers)
self.model = QStandardItemModel()
self.model.setHorizontalHeaderLabels(["ID", "规程全名", "类型", "执行时间", "报告路径"])
self.table.setModel(self.model)
self.table.doubleClicked.connect(self.openReportOrDetails)
self.table.setSelectionBehavior(QTableView.SelectRows)
self.table.setContextMenuPolicy(Qt.CustomContextMenu)
self.table.customContextMenuRequested.connect(self.showHistoryContextMenu)
self.table.verticalHeader().hide()
self.setupTableDisplay(self.table)
# 步骤详情表格
self.stepTable = QTableView()
self.stepTable.setEditTriggers(QTableView.NoEditTriggers)
self.stepModel = QStandardItemModel()
self.stepModel.setHorizontalHeaderLabels(["步骤ID", "步骤描述", "执行时间", "执行状态", "详细结果", "实际/预期对比"])
self.stepTable.setModel(self.stepModel)
self.stepTable.doubleClicked.connect(self.showStepDetailDialog)
self.stepTable.verticalHeader().hide()
self.setupTableDisplay(self.stepTable)
# 使用分割器 - 表格占据绝大部分空间
splitter = QSplitter(Qt.Vertical)
splitter.setContentsMargins(0, 0, 0, 0)
splitter.addWidget(self.table)
splitter.addWidget(self.stepTable)
# 设置比例上方历史记录表格占40%下方步骤详情表格占60% (2:3比例)
splitter.setSizes([2, 3]) # 直接使用比例值
splitter.setStretchFactor(0, 2) # 历史记录表格拉伸因子为2
splitter.setStretchFactor(1, 3) # 步骤详情表格拉伸因子为3
splitter.setChildrenCollapsible(False) # 防止子窗口被完全折叠
layout.addWidget(splitter, 1) # 拉伸因子为1占据主要空间
# 操作按钮 - 极度紧凑布局,固定高度
buttonLayout = QHBoxLayout()
buttonLayout.setContentsMargins(0, 0, 0, 0)
buttonLayout.setSpacing(2)
self.deleteButton = QPushButton("删除历史记录")
self.deleteButton.setObjectName("deleteHistoryButton") # 设置对象名称
self.deleteButton.setIcon(qta.icon('fa5s.trash', color='#FFFFFF')) # 白色图标
self.deleteButton.clicked.connect(self.deleteSelectedHistory)
buttonLayout.addWidget(self.deleteButton)
self.exportButton = QPushButton("导出报告")
self.exportButton.setObjectName("exportReportButton") # 设置对象名称
self.exportButton.setIcon(qta.icon('fa5s.file-export', color='#FFFFFF')) # 白色图标
self.exportButton.clicked.connect(self.exportReport)
buttonLayout.addWidget(self.exportButton)
buttonLayout.addStretch()
layout.addLayout(buttonLayout, 0) # 拉伸因子为0不占用额外空间
self.setLayout(layout)
# 在UI创建完成后应用按钮样式
QTimer.singleShot(0, self.applyButtonStyles)
def setupTableDisplay(self, table):
"""设置表格显示属性 - 极度紧凑版"""
table.setWordWrap(False) # 禁用自动换行以节省空间
table.setAlternatingRowColors(True) # 启用交替行颜色
table.setSortingEnabled(True)
# 水平表头设置
header = table.horizontalHeader()
if header:
header.setStretchLastSection(True)
header.setSectionResizeMode(QHeaderView.Interactive)
header.setDefaultAlignment(Qt.AlignLeft)
header.setMinimumSectionSize(50) # 设置最小列宽
header.setDefaultSectionSize(80) # 设置默认列宽
# 垂直表头设置 - 极度紧凑
verticalHeader = table.verticalHeader()
if verticalHeader:
verticalHeader.setVisible(False) # 隐藏行号以节省空间
verticalHeader.setSectionResizeMode(QHeaderView.Fixed)
if table.objectName() == "historyTable":
verticalHeader.setDefaultSectionSize(20) # 历史表格适中行高适应2:3比例
else:
verticalHeader.setDefaultSectionSize(18) # 步骤表格稍大行高
if table == self.table:
table.setSelectionMode(QTableView.ExtendedSelection)
else:
table.setSelectionMode(QTableView.SingleSelection)
table.setSelectionBehavior(QTableView.SelectRows)
def loadHistory(self):
"""加载历史记录"""
self.model.removeRows(0, self.model.rowCount())
filterText = self.searchEdit.text().strip()
history = self.dbManager.getExecutionHistory(filterText)
for record in history:
rowItems = []
for i, value in enumerate(record):
item = QStandardItem(str(value) if value is not None else "")
item.setTextAlignment(Qt.AlignTop | Qt.AlignLeft)
if i in [1, 4]: # 规程全名和报告路径列
item.setToolTip(str(value) if value is not None else "")
rowItems.append(item)
self.model.appendRow(rowItems)
self.adjustTableColumns(self.table, self.model)
def openReportOrDetails(self, index):
"""打开报告或详情"""
executionId = self.model.item(index.row(), 0).text()
stepResults = self.dbManager.getStepResults(executionId)
self.showStepDetails(stepResults)
self.saveOperationHistory(executionId, "查看步骤详情", "")
def saveOperationHistory(self, executionId, operationType, operationDetail):
"""保存操作历史"""
self.dbManager.saveOperationHistory(
executionId,
operationType,
operationDetail,
datetime.now().strftime("%Y-%m-%d %H:%M:%S")
)
def showStepDetails(self, stepResults):
"""显示步骤详情"""
self.stepModel.removeRows(0, self.stepModel.rowCount())
if not stepResults:
return
for step in stepResults:
rowItems = []
# 步骤ID
stepIdItem = QStandardItem(step.get('step_id', ''))
stepIdItem.setTextAlignment(Qt.AlignCenter)
rowItems.append(stepIdItem)
# 步骤描述
descItem = QStandardItem(step.get('step_description', ''))
descItem.setTextAlignment(Qt.AlignTop | Qt.AlignLeft)
descItem.setToolTip(step.get('step_description', ''))
rowItems.append(descItem)
# 执行时间
timeItem = QStandardItem(step.get('execution_time', ''))
timeItem.setTextAlignment(Qt.AlignCenter)
rowItems.append(timeItem)
# 解析执行结果
resultInfo = self.parseStepResult(step.get('result', ''))
# 执行状态
statusItem = QStandardItem(resultInfo['statusText'])
statusItem.setTextAlignment(Qt.AlignCenter)
statusItem.setBackground(QBrush(resultInfo['statusColor']))
if resultInfo['status'] == 'success':
statusItem.setText("✓ 成功")
elif resultInfo['status'] == 'failed':
statusItem.setText("✗ 失败")
elif resultInfo['status'] == 'partial':
statusItem.setText("⚠ 部分成功")
else:
statusItem.setText("? 未知")
rowItems.append(statusItem)
# 详细结果
detailItem = QStandardItem(resultInfo['details'])
detailItem.setTextAlignment(Qt.AlignTop | Qt.AlignLeft)
detailItem.setToolTip(resultInfo['details'])
rowItems.append(detailItem)
# 实际/预期对比
comparisonItem = QStandardItem(resultInfo['comparison'])
comparisonItem.setTextAlignment(Qt.AlignCenter)
comparisonItem.setBackground(QBrush(resultInfo['typeColor']))
comparisonItem.setToolTip(resultInfo['comparisonDetail'])
rowItems.append(comparisonItem)
self.stepModel.appendRow(rowItems)
self.adjustTableColumns(self.stepTable, self.stepModel)
def parseStepResult(self, result):
"""解析步骤执行结果"""
if not result or result == 'None':
return {
'status': 'failed',
'statusText': '失败',
'statusColor': QColor(255, 200, 200),
'details': '无执行结果',
'comparison': '无对比',
'comparisonDetail': '步骤未执行或执行失败',
'typeColor': QColor(220, 220, 220)
}
result_str = str(result)
# 设置操作结果解析
if "=" in result_str:
# 提取设置的变量和值
import re
matches = re.findall(r'([^\s=]+)\s*=\s*([0-9]+(?:\.[0-9]+)?)', result_str)
failedMatches = re.findall(r'([^\s=]+)强制失败', result_str)
if matches or failedMatches:
successCount = len(matches)
failCount = len(failedMatches)
totalCount = successCount + failCount
if failCount > 0:
status = 'partial' if successCount > 0 else 'failed'
statusColor = QColor(255, 255, 200) if status == 'partial' else QColor(255, 200, 200)
statusText = '部分成功' if status == 'partial' else '失败'
comparison = f"设置 {successCount}/{totalCount} 成功"
comparisonDetail = f"成功设置: {', '.join([f'{var}={val}' for var, val in matches])}"
if failedMatches:
comparisonDetail += f"; 失败变量: {', '.join(failedMatches)}"
else:
status = 'success'
statusColor = QColor(200, 255, 200)
statusText = '成功'
comparison = f"设置 {successCount} 个变量"
comparisonDetail = f"成功设置: {', '.join([f'{var}={val}' for var, val in matches])}"
return {
'status': status,
'statusText': statusText,
'statusColor': statusColor,
'details': result_str,
'comparison': comparison,
'comparisonDetail': comparisonDetail,
'typeColor': QColor(173, 216, 230)
}
elif "成功" in result_str or "" in result_str:
# 包含等号但没有匹配到具体变量,但有成功标识
return {
'status': 'success',
'statusText': '成功',
'statusColor': QColor(200, 255, 200),
'details': result_str,
'comparison': "设置成功",
'comparisonDetail': "变量设置操作执行成功",
'typeColor': QColor(173, 216, 230)
}
# 检查操作结果解析
if any(op in result_str for op in ['>', '<', '>=', '<=', '==', '!=']):
# 分析检查结果
successCount = result_str.count('')
failCount = result_str.count('')
totalChecks = successCount + failCount
if failCount > 0:
status = 'partial' if successCount > 0 else 'failed'
statusColor = QColor(255, 255, 200) if status == 'partial' else QColor(255, 200, 200)
statusText = '部分成功' if status == 'partial' else '失败'
comparison = f"{successCount}/{totalChecks} 通过"
comparisonDetail = f"检查结果: {successCount}个成功, {failCount}个失败"
else:
status = 'success'
statusColor = QColor(200, 255, 200)
statusText = '成功'
comparison = f"{totalChecks}/{totalChecks} 通过"
comparisonDetail = f"所有 {totalChecks} 个检查项均通过"
return {
'status': status,
'statusText': statusText,
'statusColor': statusColor,
'details': result_str,
'comparison': comparison,
'comparisonDetail': comparisonDetail,
'typeColor': QColor(255, 218, 185)
}
# 等待操作结果解析
if "等待" in result_str or "wait" in result_str.lower():
# 提取等待时间
import re
timeMatch = re.search(r'([0-9]+(?:\.[0-9]+)?)', result_str)
if timeMatch:
waitTime = timeMatch.group(1)
comparison = f"等待 {waitTime}s"
comparisonDetail = f"按预期等待了 {waitTime}"
else:
comparison = "等待完成"
comparisonDetail = "等待操作按预期完成"
return {
'status': 'success',
'statusText': '成功',
'statusColor': QColor(200, 255, 200),
'details': result_str,
'comparison': comparison,
'comparisonDetail': comparisonDetail,
'typeColor': QColor(221, 160, 221)
}
# 接收操作结果解析
if "t1=" in result_str or "deltaT" in result_str:
# 计算接收到的数据点数量
import re
dataPoints = re.findall(r't\d+=[\d.-]+', result_str)
comparison = f"接收 {len(dataPoints)} 个数据"
comparisonDetail = f"成功接收数据: {result_str}"
return {
'status': 'success',
'statusText': '成功',
'statusColor': QColor(200, 255, 200),
'details': result_str,
'comparison': comparison,
'comparisonDetail': comparisonDetail,
'typeColor': QColor(144, 238, 144)
}
# 错误情况
if "失败" in result_str or "error" in result_str.lower() or "错误" in result_str:
return {
'status': 'failed',
'statusText': '失败',
'statusColor': QColor(255, 200, 200),
'details': result_str,
'comparison': '执行失败',
'comparisonDetail': f"执行过程中出现错误: {result_str}",
'typeColor': QColor(255, 182, 193)
}
# 成功情况
if "成功" in result_str or "执行成功" in result_str:
return {
'status': 'success',
'statusText': '成功',
'statusColor': QColor(200, 255, 200),
'details': result_str,
'comparison': '执行成功',
'comparisonDetail': '操作按预期成功执行',
'typeColor': QColor(220, 220, 220)
}
# 默认情况
return {
'status': 'unknown',
'statusText': '未知',
'statusColor': QColor(240, 240, 240),
'details': result_str,
'comparison': '结果未知',
'comparisonDetail': f'无法解析的执行结果: {result_str}',
'typeColor': QColor(220, 220, 220)
}
def adjustTableColumns(self, table, model):
"""调整表格列宽"""
header = table.horizontalHeader()
if not header:
return
if model == self.model: # 历史记录表格
for col in range(model.columnCount()):
if col == 0: # ID列
header.setSectionResizeMode(col, QHeaderView.ResizeToContents)
elif col == 1: # 规程全名列
header.setSectionResizeMode(col, QHeaderView.Stretch)
elif col == 2: # 类型列
header.setSectionResizeMode(col, QHeaderView.ResizeToContents)
elif col == 3: # 执行时间列
header.setSectionResizeMode(col, QHeaderView.ResizeToContents)
elif col == 4: # 报告路径列
header.setSectionResizeMode(col, QHeaderView.Stretch)
else: # 步骤详情表格
for col in range(model.columnCount()):
if col == 0: # 步骤ID列
header.setSectionResizeMode(col, QHeaderView.ResizeToContents)
elif col == 1: # 步骤描述列
header.setSectionResizeMode(col, QHeaderView.Stretch)
elif col == 2: # 执行时间列
header.setSectionResizeMode(col, QHeaderView.ResizeToContents)
elif col == 3: # 执行状态列
header.setSectionResizeMode(col, QHeaderView.ResizeToContents)
elif col == 4: # 详细结果列
header.setSectionResizeMode(col, QHeaderView.Stretch)
elif col == 5: # 操作类型列
header.setSectionResizeMode(col, QHeaderView.ResizeToContents)
table.resizeRowsToContents()
def showStepDetailDialog(self, index):
"""显示步骤详情对话框"""
if not index.isValid():
return
row = index.row()
stepId = self.stepModel.item(row, 0).text()
stepDesc = self.stepModel.item(row, 1).text()
execTime = self.stepModel.item(row, 2).text()
execStatus = self.stepModel.item(row, 3).text()
detailResult = self.stepModel.item(row, 4).text()
operationType = self.stepModel.item(row, 5).text()
# 创建详情对话框
dialog = QDialog(self)
dialog.setWindowTitle(f"步骤详情 - {stepId}")
dialog.setMinimumSize(600, 400)
dialog.setModal(True)
layout = QVBoxLayout()
# 基本信息区域
infoLayout = QVBoxLayout()
infoGroup = QWidget()
infoGroup.setObjectName("stepDetailInfoGroup")
infoGroupLayout = QVBoxLayout()
infoGroupLayout.addWidget(QLabel(f"<b>步骤ID:</b> {stepId}"))
infoGroupLayout.addWidget(QLabel(f"<b>实际/预期对比:</b> {operationType}"))
infoGroupLayout.addWidget(QLabel(f"<b>执行时间:</b> {execTime}"))
infoGroupLayout.addWidget(QLabel(f"<b>执行状态:</b> {execStatus}"))
infoGroup.setLayout(infoGroupLayout)
layout.addWidget(QLabel("<b>基本信息</b>"))
layout.addWidget(infoGroup)
# 步骤描述区域
layout.addWidget(QLabel("<b>步骤描述</b>"))
descTextEdit = QLineEdit()
descTextEdit.setText(stepDesc)
descTextEdit.setReadOnly(True)
descTextEdit.setObjectName("stepDescriptionText")
layout.addWidget(descTextEdit)
# 详细结果区域
layout.addWidget(QLabel("<b>执行结果详情</b>"))
resultTextEdit = QLineEdit()
resultTextEdit.setText(detailResult)
resultTextEdit.setReadOnly(True)
# 根据执行状态设置结果显示样式
if "成功" in execStatus:
resultTextEdit.setObjectName("stepResultText")
resultTextEdit.setProperty("status", "success")
elif "失败" in execStatus:
resultTextEdit.setObjectName("stepResultText")
resultTextEdit.setProperty("status", "error")
else:
resultTextEdit.setObjectName("stepResultText")
resultTextEdit.setProperty("status", "default")
layout.addWidget(resultTextEdit)
# 按钮区域
buttonBox = QDialogButtonBox(QDialogButtonBox.Ok)
buttonBox.accepted.connect(dialog.accept)
layout.addWidget(buttonBox)
dialog.setLayout(layout)
dialog.exec_()
def deleteSelectedHistory(self):
"""删除选中的历史记录"""
selectedIndexes = self.table.selectionModel().selectedRows()
if not selectedIndexes:
QMessageBox.warning(self, "未选择", "请先选择要删除的历史记录")
return
executionIds = []
for index in selectedIndexes:
executionId = self.model.item(index.row(), 0).text()
executionIds.append(executionId)
reply = QMessageBox.question(
self,
"确认删除",
f"确定要删除选中的 {len(executionIds)} 条历史记录吗?\n此操作不可恢复!",
QMessageBox.Yes | QMessageBox.No
)
if reply == QMessageBox.Yes:
success = self.dbManager.deleteExecutionHistory(executionIds)
if success:
QMessageBox.information(self, "删除成功", "已成功删除选中的历史记录")
self.loadHistory()
else:
QMessageBox.warning(self, "删除失败", "删除历史记录时发生错误")
def exportReport(self):
"""导出报告"""
selectedIndexes = self.table.selectionModel().selectedRows()
if not selectedIndexes:
QMessageBox.warning(self, "未选择", "请先选择要导出的历史记录")
return
if len(selectedIndexes) > 1:
QMessageBox.warning(self, "选择过多", "一次只能导出一个历史记录的报告")
return
index = selectedIndexes[0]
executionId = self.model.item(index.row(), 0).text()
executionData = self.dbManager.getExecutionDetails(executionId)
if not executionData:
QMessageBox.warning(self, "数据错误", "无法获取执行详情数据")
return
try:
executor = StepExecutor(executionData['procedure_content'],
executionData['procedure_id'],
self.dbManager)
executor.stepResults = executionData['step_results']
for step in executor.tableModel.stepData:
stepResult = next((s for s in executionData['step_results']
if s['step_id'] == step['stepId']), None)
if stepResult:
step['executed'] = True
step['result'] = stepResult['result']
step['time'] = datetime.strptime(stepResult['execution_time'], "%Y-%m-%d %H:%M:%S")
resultPath = executor.generateReport()
if resultPath:
return
else:
QMessageBox.information(self, "导出取消", "用户取消了报告导出")
except Exception as e:
QMessageBox.critical(self, "导出错误", f"生成报告时出错:\n{str(e)}")
import traceback
print(f"导出报告详细错误: {traceback.format_exc()}")
def showHistoryContextMenu(self, pos):
"""显示右键菜单"""
index = self.table.indexAt(pos)
menu = QMenu()
if index.isValid():
deleteAction = menu.addAction(qta.icon('fa5s.trash', color='red'), "删除历史记录")
deleteAction.triggered.connect(self.deleteSelectedHistory)
menu.addSeparator()
exportAction = menu.addAction(qta.icon('fa5s.file-export', color='green'), "导出报告")
exportAction.triggered.connect(lambda: self.exportReportFromContextMenu(index))
menu.addSeparator()
selectAllAction = menu.addAction("全选")
selectAllAction.triggered.connect(self.selectAllHistory)
deselectAllAction = menu.addAction("取消全选")
deselectAllAction.triggered.connect(self.deselectAllHistory)
if index.isValid():
menu.exec_(self.table.viewport().mapToGlobal(pos))
else:
menu.exec_(self.table.mapToGlobal(pos))
def showEvent(self, event):
"""窗口显示事件"""
super().showEvent(event)
QTimer.singleShot(100, self.adjustTablesAfterShow)
QTimer.singleShot(500, self.forceSplitterRatio) # 延迟强制设置比例
def adjustTablesAfterShow(self):
"""窗口显示后调整表格"""
self.adjustTableColumns(self.table, self.model)
self.adjustTableColumns(self.stepTable, self.stepModel)
def forceSplitterRatio(self):
"""强制设置分割器比例为2:3"""
splitter = self.findChild(QSplitter)
if splitter:
total_height = splitter.height()
if total_height > 0:
# 计算2:3比例的实际像素值
history_height = int(total_height * 0.4) # 40%
step_height = int(total_height * 0.6) # 60%
# 设置表格的固定高度以确保比例
self.table.setFixedHeight(history_height)
self.stepTable.setMinimumHeight(step_height)
# 设置分割器尺寸
splitter.setSizes([history_height, step_height])
def selectAllHistory(self):
"""全选历史记录"""
self.table.selectAll()
def deselectAllHistory(self):
"""取消全选历史记录"""
self.table.clearSelection()
def exportReportFromContextMenu(self, index):
"""从右键菜单导出报告"""
self.table.selectRow(index.row())
self.exportReport()