from PyQt5.QtCore import Qt, QAbstractTableModel, QVariant, QTimer, QModelIndex, QEvent, QSize from PyQt5.QtGui import QColor from PyQt5.QtWidgets import QMessageBox, QPushButton, QItemDelegate, QStyleOptionButton, QStyle, QWidget, QInputDialog, QHBoxLayout from utils import Globals import qtawesome class RpcVarModel(QAbstractTableModel): def __init__(self, header, parent=None): # 新顺序:当前值、强制值、变量名、类型、下限、上限、客户端、强制按钮 self.header = ['当前值', '强制值', '变量名', '类型', '下限', '上限', '客户端', '操作'] super().__init__(parent) self.datas = [] self.valueCache = {} self.inputValues = {} # 行号->输入值 self.refreshTimer = QTimer() self.refreshTimer.timeout.connect(self.refreshData) self.refreshTimer.start(500) # 每秒刷新一次 self.table = parent def refreshData(self): """刷新所有远程变量数据,并按类型排序""" protocolManage = Globals.getValue('protocolManage') if protocolManage and protocolManage.RpcServer: allVars = protocolManage.RpcServer.broadcastRead() temp = [] # print(allVars) for client in allVars: clientName = client.get('client', '') variables = client.get('variables', {}) for varName, varInfo in variables.items(): row = [ varInfo.get('value', ''), # 当前值 self.inputValues.get(len(temp), ''),# 强制值(输入缓存) varName, # 变量名 varInfo.get('type', ''), # 类型 varInfo.get('min', ''), # 下限 varInfo.get('max', ''), # 上限 clientName, # 客户端(倒数第二列) '', # 强制按钮(最后一列) ] temp.append(row) # 按类型排序 temp.sort(key=lambda x: x[3]) self.datas = temp self.table.proxy.invalidate() def rowCount(self, parent=None): return len(self.datas) def columnCount(self, parent=None): return len(self.header) def data(self, index, role=Qt.DisplayRole): if not index.isValid(): return QVariant() row = index.row() col = index.column() if role == Qt.DisplayRole: # 强制值输入列显示缓存值 if col == 1: return self.inputValues.get(row, '') return self.datas[row][col] if role == Qt.TextAlignmentRole: return Qt.AlignCenter if role == Qt.BackgroundRole: if row % 2 == 0: return QColor('#EFEFEF') return QVariant() def setData(self, index, value, role=Qt.EditRole): if index.isValid() and index.column() == 1: self.inputValues[index.row()] = value self.dataChanged.emit(index, index) return True return False def headerData(self, section, orientation, role=Qt.DisplayRole): if role == Qt.DisplayRole and orientation == Qt.Horizontal: return self.header[section] return QVariant() def flags(self, index): if not index.isValid(): return Qt.ItemIsEnabled if index.column() == 1: return Qt.ItemIsEnabled | Qt.ItemIsEditable if index.column() == 7: return Qt.ItemIsEnabled # 按钮列不可编辑 return Qt.ItemIsEnabled from PyQt5.QtWidgets import QStyledItemDelegate, QPushButton, QStyleOptionButton, QStyle, QApplication from UI.VarManages.BaseButtonDelegate import BaseButtonDelegate class RpcVarButtonDelegate(BaseButtonDelegate): def __init__(self, parent=None): super(RpcVarButtonDelegate, self).__init__(parent) def paint(self, painter, option, index): if not self.parent().indexWidget(index) and index.column() == 7: button = QPushButton( qtawesome.icon('fa.play', color='#1fbb6f'), '', self.parent() ) button.setIconSize(QSize(15, 15)) button.setStyleSheet('border:none;') button.index = [index.row(), index.column()] button.clicked.connect(lambda: self.force_action(button)) h_box_layout = QHBoxLayout() h_box_layout.addWidget(button) h_box_layout.setContentsMargins(2, 0, 0, 2) h_box_layout.setAlignment(Qt.AlignCenter) widget = QWidget() widget.setLayout(h_box_layout) self.parent().setIndexWidget(index, widget) # 不再用QStyleOptionButton绘制 def force_action(self, sender): model = self.parent().model # 使用基类的验证方法获取行索引 view_row, source_row = self._validate_button_indices(sender) if view_row is None: return varName = model.datas[source_row][2] minValue = model.datas[source_row][4] maxValue = model.datas[source_row][5] forceValue = model.inputValues.get(source_row, '') if forceValue == '': QMessageBox.warning(self.parent(), '提示', '请先输入强制值') return try: protocolManage = Globals.getValue('protocolManage') if protocolManage and protocolManage.RpcServer: resp = protocolManage.RpcServer.writeVar(varName, float(forceValue)) if resp.get('result') == 'success': QMessageBox.information(self.parent(), '提示', f'{varName} 强制成功!') else: reason = resp.get('reason', '') QMessageBox.warning(self.parent(), '失败', f'{varName} 强制失败: {reason}') except Exception as e: QMessageBox.warning(self.parent(), '错误', f'强制失败: {e}')