import qtawesome from PyQt5.QtCore import Qt, QVariant, QSize, QTimer from PyQt5.QtWidgets import QHBoxLayout, QWidget, QMessageBox, QComboBox from protocol.TCP.TemToMv import temToMv from model.ProjectModel.VarManage import * from UI.VarManages.ModbusModel import * from UI.VarManages.BaseButtonDelegate import BaseButtonDelegate from UI.TrendManage.ActualTrendWidget import ActualTrend from utils import Globals import re class TcRtdModel(VarTableModel): def __init__(self, header, data: list, table = None): ''' header : 表头变量 data : 表格内容 table : 缺省参数 ''' VarTableModel.__init__(self, header, data, table = table) # 添加定时刷新缓存机制 self.valueCache = {} self.cacheTimer = QTimer() self.cacheTimer.timeout.connect(self.refreshValueCache) self.cacheTimer.start(300) # 每秒刷新一次缓存 # 添加缓存刷新方法 def refreshValueCache(self): """刷新所有变量的值缓存""" for row in self.datas: varName = row[3] try: self.valueCache[varName] = Globals.getValue('protocolManage').readVariableValue(varName) # print(Globals.getValue('protocolManage').readVariableValue(varName)) except: self.valueCache[varName] = None def initTable(self): self.datas = [] # proType = Globals.getValue('currentProType') # if proType in ['5']: varDatas = TcRtdManage.getAllVar() if not varDatas: # self.layoutChanged.emit() self.table.proxy.invalidate() return for x in varDatas: x.insert(1, '') x.insert(2, '') self.datas.append(x) x.append('') self.checkList = ['Unchecked'] * len(self.datas) # self.layoutChanged.emit() self.table.proxy.invalidate() # 初始化后立即刷新缓存 self.refreshValueCache() def data(self, QModelIndex, role=None): # print(Qt.__dict__.items()) if role == Qt.TextAlignmentRole: return Qt.AlignCenter if not QModelIndex.isValid(): print("行或者列有问题") return QVariant() if role == Qt.BackgroundRole: if self.datas[QModelIndex.row()][3] in Globals.getValue('forceVars'): return QtGui.QColor('#00FF7F') if role == Qt.TextColorRole: return QtGui.QColor('#1A1A1A') if role == Qt.CheckStateRole: if QModelIndex.column() == 0: return Qt.Checked if self.checkList[QModelIndex.row()] == 'Checked' else Qt.Unchecked else: return None if role == Qt.ToolTipRole: if QModelIndex.column() == 0: return self.checkList[QModelIndex.row()] if role == Qt.DisplayRole or role == Qt.EditRole: if QModelIndex.row() in self.editableList: return self.datas[QModelIndex.row()][QModelIndex.column()] if role != Qt.DisplayRole: return QVariant() # 修改:使用缓存值代替table.valueList if QModelIndex.column() == 2: varName = self.datas[QModelIndex.row()][3] # print(self.valueCache.get(varName, None)) return self.valueCache.get(varName, None) return QVariant(self.datas[QModelIndex.row()][QModelIndex.column()]) def flags(self, index): if index.column() == 0: return Qt.ItemIsEnabled | Qt.ItemIsUserCheckable if index.row() in self.editableList and index.column() or index.column() == 1 or index.column() == 8: if index.column() == 4: return Qt.ItemIsEnabled return Qt.ItemIsEnabled | Qt.ItemIsUserCheckable | Qt.ItemIsEditable return Qt.ItemIsEnabled class TcRtdButtonDelegate(BaseButtonDelegate): """该类用于向单元格中添加按钮 任务表格""" def __init__(self, parent=None): super(TcRtdButtonDelegate, self).__init__(parent) self.trendWindows = {} # 保存所有打开的趋势窗口 def paint(self, painter, option, index): # 首先绘制背景颜色,与其他委托保持一致 if index.data(Qt.BackgroundRole): height = option.rect.height() top = option.rect.top() # 减少高度调整,保持更多的绘制区域 paint_rect = option.rect paint_rect.setHeight(max(46, height - 4)) # 最小保持46px高度 paint_rect.moveTop(top + 2) painter.fillRect(paint_rect, index.data(Qt.BackgroundRole)) # 然后创建按钮部件 if not self.parent().indexWidget(index): button1 = QPushButton( qtawesome.icon('fa.play', color='#1fbb6f'), "", self.parent(), clicked=self.start_action ) button1.setIconSize(QSize(15, 15)) button1.setToolTip("启动强制") button2 = QPushButton( qtawesome.icon('fa.pencil', color='#4c8cf2'), "", self.parent(), clicked=self.edit_action ) button2.setToolTip("编辑变量") button3 = QPushButton( qtawesome.icon('fa.line-chart', color='#393c4e'), "", self.parent(), clicked=self.trend_action ) button3.setToolTip("趋势图") button1.clicked.connect(self.start_action) button2.clicked.connect(self.edit_action) button3.clicked.connect(self.trend_action) button2.oldName = False button2.isEdit = True button1.index = [index.row(), index.column()] button2.index = [index.row(), index.column()] button3.index = [index.row(), index.column()] data = self.parent().model.datas[index.row()] for x in data[:-1]: if x != '': break else: button2.isEdit = False button2.setIcon(qtawesome.icon('fa.save', color='#1fbb6f')) button2.setToolTip("保存变量") self.parent().model.editableList.append(button2.index[0]) h_box_layout = QHBoxLayout() h_box_layout.addWidget(button1) h_box_layout.addWidget(button2) h_box_layout.addWidget(button3) h_box_layout.setContentsMargins(2, 2, 2, 2) h_box_layout.setAlignment(Qt.AlignCenter) h_box_layout.setSpacing(3) widget = QWidget() widget.setLayout(h_box_layout) # 设置widget的背景为透明,让底层的背景颜色显示出来 widget.setStyleSheet(""" QWidget { background-color: transparent; } """) self.parent().setIndexWidget( index, widget ) def start_action(self): sender = self.sender() model = self.parent().model # 使用基类的验证方法获取行索引 view_row, source_row = self._validate_button_indices(sender) if view_row is None: return # 获取强制值(从视图)和其他数据(从源模型) value = self._get_view_data(view_row, 1) # 强制值列 varType = model.datas[source_row][6] min = model.datas[source_row][7] max = model.datas[source_row][8] compensation = model.datas[source_row][9] pattern = re.compile(r'[^0-9\.-]+') print(model.datas[source_row][3]) if not value or re.findall(pattern, str(value) + str(compensation)): reply = QMessageBox.question(self.parent(), '警告', "请输入强制值或数字", QMessageBox.Yes) return if min and max: if float(value) < float(min) or float(value) > float(max): reply = QMessageBox.question(self.parent(), '警告', "超出量程范围", QMessageBox.Yes) return elif min and not max: if float(value) < float(min): reply = QMessageBox.question(self.parent(), '警告', "超出量程范围", QMessageBox.Yes) return elif max and not min: if float(value) > float(max): reply = QMessageBox.question(self.parent(), '警告', "超出量程范围", QMessageBox.Yes) return mv = temToMv(varType, float(value)) if not mv and mv != 0: reply = QMessageBox.question(self.parent(), '警告', "输入值有误", QMessageBox.Yes) return # 直接写入变量值 res = Globals.getValue('protocolManage').writeVariableValue( model.datas[source_row][3], float(value) ) if res: forceVars = Globals.getValue('forceVars') forceVars.add(model.datas[source_row][3]) Globals.setValue('forceVars', forceVars) else: QMessageBox.information(self.parent(), '提示', '写入失败', QMessageBox.Yes) def edit_action(self): sender = self.sender() model = self.parent().model # 使用基类的验证方法获取行索引 view_row, source_row = self._validate_button_indices(sender) if view_row is None: return if sender.isEdit: sender.setIcon(qtawesome.icon('fa.save', color='#1fbb6f')) sender.isEdit = False sender.oldName = model.datas[source_row][3] model.editableList.append(source_row) else: varMes = model.datas[source_row] name, channelNumber, des, varType, min, max, compensationVar = str(varMes[3]), str(varMes[4]), str(varMes[5]),str(varMes[6]), str(varMes[7]), str(varMes[8]), str(varMes[9]) if not name or not varType: reply = QMessageBox.question(self.parent(), '警告', "有字段为空", QMessageBox.Yes) return sender.isEdit = True model.editableList.remove(source_row) if sender.oldName: if sender.oldName == name: TcRtdManage.editVar(name=sender.oldName, Nname=name, channelNumber = channelNumber, des=des, varType=varType, min=min, max=max, compensationVar = compensationVar) else: if GlobalVarManager.isVarNameExist(name): QMessageBox.information(self.parent(), '提示', '已有同名变量') return else: TcRtdManage.editVar(name=sender.oldName, Nname=name, channelNumber = channelNumber, des=des, varType=varType, min=min, max=max, compensationVar = compensationVar) else: if GlobalVarManager.isVarNameExist(name): QMessageBox.information(self.parent(), '提示', '已有同名变量') return else: TcRtdManage.createVar(varName=name, channelNumber = channelNumber, varType=varType, des=des, min=min, max=max, compensationVar = compensationVar) sender.setIcon(qtawesome.icon('fa.pencil', color='#4c8cf2')) varMes = TcRtdManage.getByName(name) varMes.insert(1, '') varMes.insert(2, '') varMes.append('') model.insert_data(varMes, source_row) model.remove_row(source_row + 1) def trend_action(self): sender = 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][3] # 以变量名为key,避免重复打开 if varName not in self.trendWindows or self.trendWindows[varName] is None: self.trendWindows[varName] = ActualTrend(varName=varName) self.trendWindows[varName].show() self.trendWindows[varName].raise_() self.trendWindows[varName].activateWindow() class TcRtdTypeDelegate(TcRtdButtonDelegate): def __init__(self, parent=None): super(TcRtdTypeDelegate, self).__init__(parent) def paint(self, painter, option, index): if index.data(Qt.BackgroundRole): height = option.rect.height() top = option.rect.top() # 减少高度调整,保持更多的绘制区域 paint_rect = option.rect paint_rect.setHeight(max(46, height - 4)) # 最小保持46px高度 paint_rect.moveTop(top + 2) painter.fillRect(paint_rect, index.data(Qt.BackgroundRole)) if not self.parent().indexWidget(index): comboBox = QComboBox(self.parent()) if index.row() < 8: item = ['R', 'S', 'B', 'J', 'T','E', 'K', 'N', 'C', 'A'] comboBox.addItems(item) i = item.index(self.parent().model.datas[index.row()][index.column()]) comboBox.setCurrentIndex(i) else: item = ['PT100'] comboBox.addItems(item) comboBox.currentIndexChanged.connect(self.indexChange) comboBox.setObjectName('TcRtdTypeBox') comboBox.setEditable(True) comboBox.lineEdit().setAlignment(Qt.AlignCenter) h_box_layout = QHBoxLayout() h_box_layout.addWidget(comboBox) h_box_layout.setContentsMargins(0, 0, 0, 0) comboBox.index = [index.row(), index.column()] widget = QWidget() widget.setLayout(h_box_layout) row = index.row() # if row % 2 == 0: # comboBox.setStyleSheet("QComboBox { background-color: #EFEFEF }") # else: # comboBox.setStyleSheet("QComboBox { background-color: #e9e7e3 }") widget.setStyleSheet("QComboBox { background-color: transparent; }") self.parent().setIndexWidget( index, widget ) def indexChange(self): sender = self.sender() index = sender.currentIndex() varType = sender.itemText(index) name = self.parent().model.datas[sender.index[0]][3] TcRtdManage.editvarType(name, varType) self.parent().model.datas[sender.index[0]][sender.index[1]] = varType