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.

409 lines
16 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 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.table.reset()#强制重绘
# 初始化后立即刷新缓存
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][10]
pattern = re.compile(r'[^0-9\.-]+')
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, unit = str(varMes[3]), str(varMes[4]), str(varMes[5]),str(varMes[6]), str(varMes[7]), str(varMes[8]), str(varMes[10]), 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, unit = unit)
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, unit = unit)
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, unit = unit)
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())
# 根据实际的变量类型来设置下拉框选项,而不是根据行号
currentValue = self.parent().model.datas[index.row()][index.column()]
# 定义所有可能的类型
tcTypes = ['R', 'S', 'B', 'J', 'T','E', 'K', 'N', 'C', 'A']
rtdTypes = ['PT100']
print(currentValue,2321312)
# 如果当前值是热电偶类型
if currentValue in tcTypes:
item = tcTypes
comboBox.addItems(item)
try:
i = item.index(currentValue)
comboBox.setCurrentIndex(i)
except ValueError:
comboBox.setCurrentIndex(0)
# 如果当前值是热电阻类型
elif currentValue in rtdTypes:
item = rtdTypes
comboBox.addItems(item)
comboBox.setCurrentIndex(0)
# 如果当前值不在任何已知类型中,显示所有可用选项
else:
# 显示所有可用的类型选项,让用户自由选择
all_types = tcTypes + rtdTypes
comboBox.addItems(all_types)
# 不设置当前索引,让用户看到空值状态
comboBox.setCurrentText('')
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