import typing import sys import qtawesome from PyQt5 import QtGui,QtCore,QtWidgets from PyQt5.QtCore import QAbstractTableModel, QModelIndex, Qt, QVariant, QSize from PyQt5.QtWidgets import QItemDelegate, QHBoxLayout, QWidget, QTableView, QMessageBox, QComboBox from protocol.Celery.MBTCPMaster import app as MBTCPMApp from protocol.Celery.MBRTUMaster import app as MBRTUMApp from protocol.Celery.MBRTUSlave import app as MBRTUSApp from protocol.Celery.MBTCPSlave import app as MBTCPSApp # from protocol.Celery.MBTCPMaster.MBTCPMTask import setValue as setMTcpValue # from protocol.Celery.MBRTUMaster.MBRTUMTask import setValue as setMRTUValue from celery.schedules import crontab, timedelta from celery.result import AsyncResult, GroupResult from ..TrendManage.ActualTrendWidget import ActualTrend from protocol.TCP.TemToMv import temToMv from protocol.TCP.Analog import getRealAO from model.ProjectModel.VarManage import * from utils import Globals import re sys.path.append('protocol/Celery/MBTCPMaster') class QPushButton(QtWidgets.QPushButton): def __init__(self, *__args: any,clicked = None): super(QPushButton,self).__init__(*__args) self.setCursor(Qt.PointingHandCursor) self.setIconSize(QSize(25, 25)) class VarTableModel(QAbstractTableModel): ''' 变量表模型类''' def __init__(self, header, data: list, table = None): ''' header : 表头变量 data : 表格内容 table : 缺省参数 ''' QAbstractTableModel.__init__(self, parent=None) self.header = header self.datas = data self.checkList = ['Unchecked'] * len(self.datas) self.supportedDragActions() self.table = table self.editableList = [] # 表格中可编辑项 def initTable(self): self.datas = [] self.table.parent.initIcon() proType = Globals.getValue('currentProType') if proType in ['1', '2', '3', '0']: varDatas = ModbusVarManage.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) self.checkList = ['Unchecked'] * len(self.datas) # self.layoutChanged.emit() self.table.proxy.invalidate() def append_data(self, x): self.datas.append(x) self.checkList = ['Unchecked'] * len(self.datas) self.table.proxy.invalidate() # self.layoutChanged.emit() def insert_data(self, x, index): self.datas.insert(index, x) self.checkList = ['Unchecked'] * len(self.datas) self.table.proxy.invalidate() def remove_row(self, row): self.datas.pop(row) self.checkList = ['UnChecked'] * len(self.datas) self.table.proxy.invalidate() def rowCount(self, parent: QModelIndex = ...) -> int: if len(self.datas) > 0: return len(self.datas) return 0 def columnCount(self, parent: QModelIndex = ...) -> int: return len(self.header) 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.BackgroundColorRole: if QModelIndex.row() % 2 == 0 and self.datas[QModelIndex.row()][3] not in Globals.getValue('forceVars'): return QtGui.QColor('#EFEFEF') 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() # 获取变量值并插入表格 if QModelIndex.column() == 2: varName = self.datas[QModelIndex.row()][3] if varName != '': # print(uid) try: uid = MBTCPMApp.backend.get('ModBus').decode('utf-8') res = AsyncResult(uid) # 参数为task id if res.result: # print(res.result, res.date_done) result = res.result[varName] if result or result in [0, '0']: self.datas[QModelIndex.row()][QModelIndex.column()] = result except: pass return QVariant(self.datas[QModelIndex.row()][QModelIndex.column()]) def headerData(self, section: int, orientation: Qt.Orientation, role: int = ...) -> typing.Any: # 表头 if role != Qt.DisplayRole: return None if orientation == Qt.Horizontal: return self.header[section] def setData(self, index, value, role): row = index.row() col = index.column() if role == Qt.CheckStateRole and col == 0: self.checkList[row] = 'Checked' if value == Qt.Checked else 'Unchecked' return True if role == Qt.EditRole: self.datas[row][col] = value return True return True 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: return Qt.ItemIsEnabled | Qt.ItemIsUserCheckable | Qt.ItemIsEditable return Qt.ItemIsEnabled def headerClick(self, isOn): self.beginResetModel() if isOn: self.checkList = [] self.checkList = ['Checked'] * len(self.datas) else: self.checkList = [] self.checkList = ['UnChecked'] * len(self.datas) self.endResetModel() def dragMoveEvent(self, event): event.setDropAction(QtCore.Qt.MoveAction) event.accept() def moveRow(self, sourceParent: QModelIndex, sourceRow: int, destinationParent: QModelIndex, destinationChild: int) -> bool: if self.datas[destinationChild] == self.datas[sourceRow]: return self.datas[sourceRow], self.datas[destinationChild] = self.datas[destinationChild], self.datas[sourceRow] self.table.proxy.invalidate() def refreshComboBox(self): for i in range(len(self.datas)): cbRow = str('cb' + str(i) + '5') index = self.index(i, 5) delegate = self.table.itemDelegate(index) comboBox = getattr(delegate, cbRow) if self.datas[i][5] in [0, 1]: comboBox.setCurrentIndex(self.datas[i][5]) elif self.datas[i][5] in [3, 4]: comboBox.setCurrentIndex(self.datas[i][5] - 1) else: comboBox.setCurrentIndex(-1) class ModBusTCPSlaveModel(VarTableModel): def __init__(self, header, data: list, table = None): ''' header : 表头变量 data : 表格内容 table : 缺省参数 ''' VarTableModel.__init__(self, header, data, table = table) class VarButtonDelegate(QItemDelegate): """该类用于向单元格中添加按钮 任务表格""" def __init__(self, parent=None): super(VarButtonDelegate, self).__init__(parent) def paint(self, painter, option, index): 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.setStyleSheet("border:none;") button2 = QPushButton( qtawesome.icon('fa.pencil', color='#4c8cf2'), "", self.parent(), clicked=self.edit_action ) # button2.setStyleSheet("border:none;") button3 = QPushButton( qtawesome.icon('fa.trash', color='#ff6d6d'), "", self.parent(), clicked=self.delete_action ) # button3.setStyleSheet("border:none;") button4 = QPushButton( qtawesome.icon('fa.line-chart', color='#393c4e'), "", self.parent(), clicked=self.trend_action ) comboBox = QComboBox(self.parent()) comboBox.addItem('int', 0) comboBox.addItem('ABCD', 1) comboBox.addItem('CDAB', 2) comboBox.addItem('BADC', 3) comboBox.addItem('DCBA', 4) comboBox.setCurrentText(self.parent().model.datas[index.row()][index.column()]) comboBox.currentIndexChanged.connect(self.indexChange) button1.clicked.connect(self.start_action) button2.clicked.connect(self.edit_action) button3.clicked.connect(self.delete_action) button4.clicked.connect(self.trend_action) button2.oldName = False button2.isEdit = True # button4.setStyleSheet("border:none;") button1.index = [index.row(), index.column()] button2.index = [index.row(), index.column()] button3.index = [index.row(), index.column()] button4.index = [index.row(), index.column()] comboBox.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')) self.parent().model.editableList.append(button2.index[0]) h_box_layout = QHBoxLayout() h_box_layout.addWidget(comboBox) h_box_layout.addWidget(button1) h_box_layout.addWidget(button2) h_box_layout.addWidget(button3) h_box_layout.addWidget(button4) 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 ) # widget.setStyleSheet(''' # QWidget{background : #ffffff; # margin-bottom:4px; # margin-top:4px;}''') def indexChange(self): sender = self.sender() index = sender.currentIndex() text = sender.itemText(index) name = self.parent().model.datas[sender.index[0]][3] ModbusVarManage.editOrder(name, text) self.parent().model.datas[sender.index[0]][sender.index[1]] = text def start_action(self): sender = self.sender() model = self.parent().model varMes = model.datas[sender.index[0]] value, name, des, varType, slaveID, address, min, max, order = str(varMes[1]), str(varMes[3]), str(varMes[4]), str(varMes[5]), str(varMes[6]), str(varMes[7]), str(varMes[8]), str(varMes[9]), str(varMes[10]) pattern = re.compile(r'[^0-9\.-]+') if not value or re.findall(pattern, str(value)): 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 # 0 : MODBUSTCP 主站模式 # 1 : MODBUSTCP 从站模式 # 2 : MODBUSRTU 主站模式 # 3 : MODBUSRTU 从站模式 proType = Globals.getValue('currentProType') forceVars = Globals.getValue('forceVars') forceVars.add(name) Globals.setValue('forceVars', forceVars) # print(Globals.getValue('forceVars')) if proType == '0': MBTCPMApp.send_task('protocol.Celery.MBTCPMaster.MBTCPMTask.setValue',args=[name, varType, slaveID, address, value, order]) if proType == '1': MBTCPSApp.send_task('protocol.Celery.MBTCPSlave.MBTCPSTask.setValue',args=[name, varType, slaveID, address, value]) elif proType == '2': MBRTUMApp.send_task('protocol.Celery.MBRTUMaster.MBRTUMTask.setValue',args=[name, varType, slaveID, address, value, order]) elif proType == '3': MBRTUSApp.send_task('protocol.Celery.MBRTUSlave.MBRTUSTask.setValue',args=[name, varType, slaveID, address, value]) def edit_action(self): sender = self.sender() model = self.parent().model cbRow = str('cb' + str(sender.index[0]) + str(5)) index = self.parent().model.index(sender.index[0], 5) delegate = self.parent().itemDelegate(index) checkbox = getattr(delegate, cbRow) if sender.isEdit: sender.setIcon(qtawesome.icon('fa.save', color='#1fbb6f')) sender.isEdit = False sender.oldName = model.datas[sender.index[0]][3] model.editableList.append(sender.index[0]) checkbox.setEnabled(True) else: varMes = model.datas[sender.index[0]] name, des, varType, slaveID, address, min, max, order = str(varMes[3]), str(varMes[4]), str(varMes[5]), str(varMes[6]), str(varMes[7]), str(varMes[8]), str(varMes[9]), str(varMes[-1]) print(name, des, varType, slaveID, address, min, max, order) if not name or not varType: reply = QMessageBox.question(self.parent(), '警告', "有字段为空", QMessageBox.Yes) return sender.isEdit = True checkbox.setEnabled(False) model.editableList.remove(sender.index[0]) if sender.oldName: ModbusVarManage.editVar(name = sender.oldName, Nname = name, des = des, varType = varType, slaveID = slaveID, address = address, min = min, max = max, order = order) else: ModbusVarManage.createVar(varName = name, varType = varType, des = des, address = address, slaveID = slaveID, min = min, max = max, order = order) sender.setIcon(qtawesome.icon('fa.pencil', color='#4c8cf2')) rowIndex = sender.index[0] varMes = ModbusVarManage.getByName(name) varMes.append('int') varMes.insert(1, '') varMes.insert(2, '') model.insert_data(varMes, rowIndex) model.remove_row(rowIndex + 1) def delete_action(self): sender = self.sender() model = self.parent().model name = str(model.datas[sender.index[0]][3]) ModbusVarManage.deleteVar(name = name) model.remove_row(sender.index[0]) def trend_action(self): model = self.parent().model if model.table.parent._isPopenOpen: sender = self.sender() name = str(model.datas[sender.index[0]][3]) trend = ActualTrend(varName = name) trend.show() class ModbusTypeBox(VarButtonDelegate): def __init__(self, parent=None): super(ModbusTypeBox, self).__init__(parent) def paint(self, painter, option, index): if not self.parent().indexWidget(index): data = self.parent().model.datas[index.row()] comBox = str('cb' + str(index.row()) + str(index.column())) setattr(self, comBox, QComboBox(self.parent())) comboBox = getattr(self, comBox) item = ['Coil Status', 'Input Status', 'Input Register', 'Holding Register'] comboBox.addItems(item) # comboBox.setItemData(0, 'Coil Status') # comboBox.setItemData(1, 'Input Status') # comboBox.setItemData(2, '3', role = Qt.UserRole) # comboBox.setItemData(3, '4', role = Qt.UserRole) if self.parent().model.datas[index.row()][index.column()] in [0, 1]: comboBox.setCurrentIndex(self.parent().model.datas[index.row()][index.column()]) elif self.parent().model.datas[index.row()][index.column()] in [3, 4]: comboBox.setCurrentIndex(self.parent().model.datas[index.row()][index.column()] - 1) else: comboBox.setCurrentIndex(-1) # self.parent().model.comboboxList.append(comboBox) comboBox.currentIndexChanged.connect(self.indexChange) comboBox.setObjectName('ModbusTypeBox') comboBox.setEditable(True) comboBox.lineEdit().setAlignment(Qt.AlignCenter) # comboBox.setEnabled(False) h_box_layout = QHBoxLayout() h_box_layout.addWidget(comboBox) h_box_layout.setContentsMargins(0, 0, 0, 0) # h_box_layout.setAlignment(Qt.AlignCenter) comboBox.index = [index.row(), index.column()] row = index.row() if row % 2 == 0: comboBox.setStyleSheet("QComboBox { background-color: #EFEFEF; height: 40px; }") else: comboBox.setStyleSheet("QComboBox { background-color: #e9e7e3; height: 40px; }") if str(data[index.column()]): comboBox.setEnabled(False) else: comboBox.setEnabled(True) widget = QWidget() widget.setLayout(h_box_layout) self.parent().setIndexWidget( index, widget ) def indexChange(self): sender = self.sender() index = sender.currentIndex() if index in [2, 3]: index += 1 text = sender.itemText(index) self.parent().model.datas[sender.index[0]][sender.index[1]] = index