Compare commits

...

2 Commits

@ -11,6 +11,7 @@ QComboBox, QStyledItemDelegate, QVBoxLayout, QSplitter
from UI.ProfibusWidgets.LoadingDataWidget import LoadingDataWidget from UI.ProfibusWidgets.LoadingDataWidget import LoadingDataWidget
from UI.ProfibusWidgets.ObjectTypeEditlayout import ObjectTypeEditlayout from UI.ProfibusWidgets.ObjectTypeEditlayout import ObjectTypeEditlayout
from UI.VarManages.BaseButtonDelegate import BaseButtonDelegate
from utils import Globals from utils import Globals
@ -147,10 +148,10 @@ class VarTableModel(QAbstractTableModel):
class VarButtonDelegate(QItemDelegate): class ProfibusButtonDelegate(BaseButtonDelegate):
"""该类用于向单元格中添加按钮 任务表格""" """该类用于向单元格中添加按钮 任务表格"""
def __init__(self, parent=None): def __init__(self, parent=None):
super(VarButtonDelegate, self).__init__(parent) super(ProfibusButtonDelegate, self).__init__(parent)
def paint(self, painter, option, index): def paint(self, painter, option, index):
if not self.parent().indexWidget(index): if not self.parent().indexWidget(index):
@ -239,9 +240,15 @@ class VarButtonDelegate(QItemDelegate):
sender = self.sender() sender = self.sender()
blockView = self.parent() blockView = self.parent()
model = blockView.model model = blockView.model
# 使用基类的验证方法获取行索引
view_row, source_row = self._validate_button_indices(sender)
if view_row is None:
return
blockType = blockView.blockType blockType = blockView.blockType
blockIndex = blockView.blcokIndex blockIndex = blockView.blcokIndex
parmIndex = model.datas[sender.index[0]][1] parmIndex = model.datas[source_row][1]
blockManage = Globals.getValue('blockManage') blockManage = Globals.getValue('blockManage')
values = [] values = []
#修改单位 #修改单位
@ -261,7 +268,7 @@ class VarButtonDelegate(QItemDelegate):
values = objectTypeEditlayout.getEditlineValue() values = objectTypeEditlayout.getEditlineValue()
dataType = model.datas[sender.index[0]][4] dataType = model.datas[source_row][4]
if not values: if not values:
reply = QMessageBox.question(self.parent(), reply = QMessageBox.question(self.parent(),
'警告', '警告',
@ -286,7 +293,13 @@ class VarButtonDelegate(QItemDelegate):
sender = self.sender() sender = self.sender()
blockView = self.parent() blockView = self.parent()
model = blockView.model model = blockView.model
parmIndex = model.datas[sender.index[0]][1]
# 使用基类的验证方法获取行索引
view_row, source_row = self._validate_button_indices(sender)
if view_row is None:
return
parmIndex = model.datas[source_row][1]
blockType = blockView.blockType blockType = blockView.blockType
blockIndex = blockView.blcokIndex blockIndex = blockView.blcokIndex
# print(blockName, blcokIndex, index) # print(blockName, blcokIndex, index)
@ -297,7 +310,7 @@ class VarButtonDelegate(QItemDelegate):
# self.loadingDataWidget.loadData(1, 1) # self.loadingDataWidget.loadData(1, 1)
self.loadingDataWidget = LoadingDataWidget(refreshType = True) self.loadingDataWidget = LoadingDataWidget(refreshType = True)
self.loadingDataWidget.exec_() self.loadingDataWidget.exec_()
model.updateColumn(sender.index[0], value) model.updateColumn(source_row, value)
# self.parent().resizeHeader() # self.parent().resizeHeader()
blockView.proxy.invalidate() blockView.proxy.invalidate()

@ -2,7 +2,7 @@ from PyQt5 import QtCore
from PyQt5.QtGui import QTextDocument from PyQt5.QtGui import QTextDocument
from PyQt5.QtCore import Qt from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import QHeaderView, QAbstractItemView, QTableView, QWidget, QDesktopWidget from PyQt5.QtWidgets import QHeaderView, QAbstractItemView, QTableView, QWidget, QDesktopWidget
from UI.ProfibusWidgets.BlockParameterModel import VarTableModel, VarButtonDelegate from UI.ProfibusWidgets.BlockParameterModel import VarTableModel, ProfibusButtonDelegate
from utils.DBModels.DeviceParModels import * from utils.DBModels.DeviceParModels import *
@ -49,7 +49,7 @@ class ParmView(QTableView):
self.setData() self.setData()
def setHeader(self): def setHeader(self):
self.setItemDelegateForColumn(7, VarButtonDelegate(self)) self.setItemDelegateForColumn(7, ProfibusButtonDelegate(self))
# self.setItemDelegateForColumn(5, ComboBoxDelegate(self)) # self.setItemDelegateForColumn(5, ComboBoxDelegate(self))
self.model = VarTableModel(['序号','索引', '参数名', '描述', '数据类型', '访问', '当前值', '输入值'], [], table = self) self.model = VarTableModel(['序号','索引', '参数名', '描述', '数据类型', '访问', '当前值', '输入值'], [], table = self)

@ -112,7 +112,13 @@ class AnalogButtonDelegate(TcRtdButtonDelegate):
def trend_action(self): def trend_action(self):
sender = self.sender() sender = self.sender()
model = self.parent().model model = self.parent().model
varName = model.datas[sender.index[0]][3]
# 使用基类的验证方法获取行索引
view_row, source_row = self._validate_button_indices(sender)
if view_row is None:
return
varName = model.datas[source_row][3]
# 以变量名为key避免重复打开 # 以变量名为key避免重复打开
if varName not in self.trendWindows or self.trendWindows[varName] is None: if varName not in self.trendWindows or self.trendWindows[varName] is None:
self.trendWindows[varName] = ActualTrend(varName=varName) self.trendWindows[varName] = ActualTrend(varName=varName)
@ -123,13 +129,19 @@ class AnalogButtonDelegate(TcRtdButtonDelegate):
def edit_action(self): def edit_action(self):
sender = self.sender() sender = self.sender()
model = self.parent().model model = self.parent().model
# 使用基类的验证方法获取行索引
view_row, source_row = self._validate_button_indices(sender)
if view_row is None:
return
if sender.isEdit: if sender.isEdit:
sender.setIcon(qtawesome.icon('fa.save', color='#1fbb6f')) sender.setIcon(qtawesome.icon('fa.save', color='#1fbb6f'))
sender.isEdit = False sender.isEdit = False
sender.oldName = model.datas[sender.index[0]][3] sender.oldName = model.datas[source_row][3]
model.editableList.append(sender.index[0]) model.editableList.append(source_row)
else: else:
varMes = model.datas[sender.index[0]] varMes = model.datas[source_row]
name,channelNumber, des, varType, min, max = str(varMes[3]), str(varMes[4]), str(varMes[5]),str(varMes[6]), str(varMes[7]), str(varMes[8]) name,channelNumber, des, varType, min, max = str(varMes[3]), str(varMes[4]), str(varMes[5]),str(varMes[6]), str(varMes[7]), str(varMes[8])
if not name or not varType: if not name or not varType:
reply = QMessageBox.question(self.parent(), reply = QMessageBox.question(self.parent(),
@ -138,7 +150,7 @@ class AnalogButtonDelegate(TcRtdButtonDelegate):
QMessageBox.Yes) QMessageBox.Yes)
return return
sender.isEdit = True sender.isEdit = True
model.editableList.remove(sender.index[0]) model.editableList.remove(source_row)
if sender.oldName: if sender.oldName:
if sender.oldName == name: if sender.oldName == name:
AnalogManage.editVar(name=sender.oldName, Nname=name, channelNumber = channelNumber, AnalogManage.editVar(name=sender.oldName, Nname=name, channelNumber = channelNumber,
@ -159,24 +171,30 @@ class AnalogButtonDelegate(TcRtdButtonDelegate):
des=des, varType=varType, min=min, max=max) des=des, varType=varType, min=min, max=max)
sender.setIcon(qtawesome.icon('fa.pencil', color='#4c8cf2')) sender.setIcon(qtawesome.icon('fa.pencil', color='#4c8cf2'))
rowIndex = sender.index[0]
varMes = AnalogManage.getByName(name) varMes = AnalogManage.getByName(name)
varMes.insert(1, '') varMes.insert(1, '')
varMes.insert(2, '') varMes.insert(2, '')
varMes.append('') varMes.append('')
model.insert_data(varMes, rowIndex) model.insert_data(varMes, source_row)
model.remove_row(rowIndex + 1) model.remove_row(source_row + 1)
def start_action(self): def start_action(self):
sender = self.sender() sender = self.sender()
model = self.parent().model model = self.parent().model
value = model.datas[sender.index[0]][1]
varType = model.datas[sender.index[0]][6] # 使用基类的验证方法获取行索引
min = model.datas[sender.index[0]][7] view_row, source_row = self._validate_button_indices(sender)
max = model.datas[sender.index[0]][8] if view_row is None:
# print(model.datas[sender.index[0]][9]) 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]
# print(model.datas[source_row][9])
pattern = re.compile(r'[^0-9\.-]+') pattern = re.compile(r'[^0-9\.-]+')
if varType in ['AI', 'DI'] and model.datas[sender.index[0]][9] != '模拟值': if varType in ['AI', 'DI'] and model.datas[source_row][9] != '模拟值':
reply = QMessageBox.question(self.parent(), reply = QMessageBox.question(self.parent(),
'警告', '警告',
"AI,DI类型变量不允许强制值", "AI,DI类型变量不允许强制值",
@ -196,14 +214,14 @@ class AnalogButtonDelegate(TcRtdButtonDelegate):
"请输入强制值或数字", "请输入强制值或数字",
QMessageBox.Yes) QMessageBox.Yes)
return return
if sender.index[0] > 15: if source_row > 15:
if not value.isdigit: if not value.isdigit:
reply = QMessageBox.question(self.parent(), reply = QMessageBox.question(self.parent(),
'警告', '警告',
"请输入0或1", "请输入0或1",
QMessageBox.Yes) QMessageBox.Yes)
return return
if min and max and sender.index[0] < 16: if min and max and source_row < 16:
if float(value) < float(min) or float(value) > float(max): if float(value) < float(min) or float(value) > float(max):
reply = QMessageBox.question(self.parent(), reply = QMessageBox.question(self.parent(),
'警告', '警告',
@ -213,29 +231,30 @@ class AnalogButtonDelegate(TcRtdButtonDelegate):
else: else:
min = None min = None
max = None max = None
# print(value, sender.index[0]) # print(value, source_row)
if (float(value) > 20 or float(value)) < 4 and sender.index[0] < 8: if (float(value) > 20 or float(value)) < 4 and source_row < 8:
reply = QMessageBox.question(self.parent(), reply = QMessageBox.question(self.parent(),
'警告', '警告',
"超出量程范围1", "超出量程范围1",
QMessageBox.Yes) QMessageBox.Yes)
return return
if float(value) > 10000 or float(value) < 0.1 and 8 < sender.index[0] < 16: if float(value) > 10000 or float(value) < 0.1 and 8 < source_row < 16:
reply = QMessageBox.question(self.parent(), reply = QMessageBox.question(self.parent(),
'警告', '警告',
"超出量程范围2", "超出量程范围2",
QMessageBox.Yes) QMessageBox.Yes)
return return
# if sender.index[0] < 8: # if source_row < 8:
# model.table.realList[sender.index[0]] = getRealAO(float(value), max, min) # model.table.realList[source_row] = getRealAO(float(value), max, min)
# model.table.valueList[sender.index[0]] = float(value) # model.table.valueList[source_row] = float(value)
# else: # else:
# model.table.realList[sender.index[0]] = float(value) # model.table.realList[source_row] = float(value)
# model.table.valueList[sender.index[0]] = float(value) # model.table.valueList[source_row] = float(value)
res = Globals.getValue('protocolManage').writeVariableValue(model.datas[sender.index[0]][3], float(value)) # print(model.datas[source_row][3])
res = Globals.getValue('protocolManage').writeVariableValue(model.datas[source_row][3], float(value))
if res: if res:
forceVars = Globals.getValue('forceVars') forceVars = Globals.getValue('forceVars')
forceVars.add(model.datas[sender.index[0]][3]) forceVars.add(model.datas[source_row][3])
Globals.setValue('forceVars', forceVars) Globals.setValue('forceVars', forceVars)
else: else:
QMessageBox.information(self.parent(), '提示', '写入失败', QMessageBox.Yes) QMessageBox.information(self.parent(), '提示', '写入失败', QMessageBox.Yes)

@ -0,0 +1,79 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
基础按钮委托类
提供通用的按钮索引获取和数据访问方法
"""
from PyQt5.QtWidgets import QItemDelegate, QMessageBox
from PyQt5.QtCore import Qt
class BaseButtonDelegate(QItemDelegate):
"""基础按钮委托类,提供通用的索引处理方法"""
def __init__(self, parent=None):
super(BaseButtonDelegate, self).__init__(parent)
def _get_button_row_indices(self, button):
"""
获取按钮所在的视图行和源模型行索引
返回: (view_row, source_row) (None, None) 如果找不到
"""
table_view = self.parent()
# 获取操作列索引(最后一列)
if hasattr(table_view, 'proxy') and table_view.proxy:
operation_col = table_view.proxy.columnCount() - 1
row_count = table_view.proxy.rowCount()
else:
operation_col = table_view.model.columnCount() - 1
row_count = table_view.model.rowCount()
# 查找按钮所在的行
for row in range(row_count):
if hasattr(table_view, 'proxy') and table_view.proxy:
index = table_view.proxy.index(row, operation_col)
else:
index = table_view.model.index(row, operation_col)
widget = table_view.indexWidget(index)
if widget and widget.layout():
for i in range(widget.layout().count()):
if widget.layout().itemAt(i).widget() == button:
view_row = row
# 转换为源模型索引
if hasattr(table_view, 'proxy') and table_view.proxy:
proxy_index = table_view.proxy.index(view_row, 0)
source_index = table_view.proxy.mapToSource(proxy_index)
source_row = source_index.row()
else:
source_row = view_row
return view_row, source_row
return None, None
def _get_view_data(self, view_row, column):
"""
从视图中获取指定行列的数据
"""
table_view = self.parent()
if hasattr(table_view, 'proxy') and table_view.proxy:
index = table_view.proxy.index(view_row, column)
return table_view.proxy.data(index, Qt.DisplayRole)
else:
return table_view.model.datas[view_row][column]
def _validate_button_indices(self, button):
"""
验证并获取按钮索引如果失败则显示错误消息
返回: (view_row, source_row) (None, None)
"""
view_row, source_row = self._get_button_row_indices(button)
if view_row is None:
QMessageBox.warning(self.parent(), '错误', '无法确定按钮所在行', QMessageBox.Yes)
return None, None
return view_row, source_row

@ -5,7 +5,7 @@ from PyQt5.QtWidgets import QHBoxLayout, QWidget, QMessageBox
from model.ProjectModel.VarManage import * from model.ProjectModel.VarManage import *
from UI.VarManages.ModbusModel import * from UI.VarManages.ModbusModel import *
from utils import Globals from utils import Globals
from UI.VarManages.BaseButtonDelegate import BaseButtonDelegate
class HartModel(VarTableModel): class HartModel(VarTableModel):
def __init__(self, header, data: list, table = None): def __init__(self, header, data: list, table = None):
@ -86,7 +86,7 @@ class HartModel(VarTableModel):
return Qt.ItemIsEnabled return Qt.ItemIsEnabled
class HartButtonDelegate(VarButtonDelegate): class HartButtonDelegate(BaseButtonDelegate):
"""该类用于向单元格中添加按钮 任务表格""" """该类用于向单元格中添加按钮 任务表格"""
def __init__(self, parent=None): def __init__(self, parent=None):
@ -128,13 +128,19 @@ class HartButtonDelegate(VarButtonDelegate):
def edit_action(self): def edit_action(self):
sender = self.sender() sender = self.sender()
model = self.parent().model model = self.parent().model
# 使用基类的验证方法获取行索引
view_row, source_row = self._validate_button_indices(sender)
if view_row is None:
return
if sender.isEdit: if sender.isEdit:
sender.setIcon(qtawesome.icon('fa.save', color='#1fbb6f')) sender.setIcon(qtawesome.icon('fa.save', color='#1fbb6f'))
sender.isEdit = False sender.isEdit = False
sender.oldName = model.datas[sender.index[0]][1] sender.oldName = model.datas[source_row][1]
model.editableList.append(sender.index[0]) model.editableList.append(source_row)
else: else:
varMes = model.datas[sender.index[0]] varMes = model.datas[source_row]
name, des = str(varMes[1]), str(varMes[2]) name, des = str(varMes[1]), str(varMes[2])
if not name : if not name :
reply = QMessageBox.question(self.parent(), reply = QMessageBox.question(self.parent(),
@ -143,13 +149,12 @@ class HartButtonDelegate(VarButtonDelegate):
QMessageBox.Yes) QMessageBox.Yes)
return return
sender.isEdit = True sender.isEdit = True
model.editableList.remove(sender.index[0]) model.editableList.remove(source_row)
if sender.oldName: if sender.oldName:
HartVarManage.editVar(name = sender.oldName, Nname = name, des = des) HartVarManage.editVar(name = sender.oldName, Nname = name, des = des)
else: else:
HartVarManage.createVar(varName = name, des = des) HartVarManage.createVar(varName = name, des = des)
sender.setIcon(qtawesome.icon('fa.pencil', color='#4c8cf2')) sender.setIcon(qtawesome.icon('fa.pencil', color='#4c8cf2'))
rowIndex = sender.index[0]
varMes = HartVarManage.getByName(name) varMes = HartVarManage.getByName(name)
model.insert_data(varMes, rowIndex) model.insert_data(varMes, source_row)
model.remove_row(rowIndex + 1) model.remove_row(source_row + 1)

@ -4,6 +4,7 @@ from PyQt5.QtCore import Qt, QVariant, QSize
from PyQt5.QtWidgets import QHBoxLayout, QWidget, QMessageBox, QComboBox from PyQt5.QtWidgets import QHBoxLayout, QWidget, QMessageBox, QComboBox
from model.ProjectModel.VarManage import * from model.ProjectModel.VarManage import *
from UI.VarManages.ModbusModel import * from UI.VarManages.ModbusModel import *
from UI.VarManages.BaseButtonDelegate import BaseButtonDelegate
from utils import Globals from utils import Globals
import re import re
@ -75,7 +76,7 @@ class HartSimulateModel(VarTableModel):
return Qt.ItemIsEnabled return Qt.ItemIsEnabled
class HartSimulateButtonDelegate(VarButtonDelegate): class HartSimulateButtonDelegate(BaseButtonDelegate):
"""该类用于向单元格中添加按钮 任务表格""" """该类用于向单元格中添加按钮 任务表格"""
def __init__(self, parent=None): def __init__(self, parent=None):
@ -128,13 +129,19 @@ class HartSimulateButtonDelegate(VarButtonDelegate):
def edit_action(self): def edit_action(self):
sender = self.sender() sender = self.sender()
model = self.parent().model model = self.parent().model
# 使用基类的验证方法获取行索引
view_row, source_row = self._validate_button_indices(sender)
if view_row is None:
return
if sender.isEdit: if sender.isEdit:
sender.setIcon(qtawesome.icon('fa.save', color='#1fbb6f')) sender.setIcon(qtawesome.icon('fa.save', color='#1fbb6f'))
sender.isEdit = False sender.isEdit = False
sender.oldName = model.datas[sender.index[0]][1] sender.oldName = model.datas[source_row][1]
model.editableList.append(sender.index[0]) model.editableList.append(source_row)
else: else:
varMes = model.datas[sender.index[0]] varMes = model.datas[source_row]
name, des = str(varMes[1]), str(varMes[2]) name, des = str(varMes[1]), str(varMes[2])
# print(name, des) # print(name, des)
if not name : if not name :
@ -144,24 +151,30 @@ class HartSimulateButtonDelegate(VarButtonDelegate):
QMessageBox.Yes) QMessageBox.Yes)
return return
sender.isEdit = True sender.isEdit = True
model.editableList.remove(sender.index[0]) model.editableList.remove(source_row)
if sender.oldName: if sender.oldName:
HartSimulateVarManage.editVar(name = sender.oldName, Nname = name, des = des) HartSimulateVarManage.editVar(name = sender.oldName, Nname = name, des = des)
else: else:
HartSimulateVarManage.createVar(varName = name, des = des) HartSimulateVarManage.createVar(varName = name, des = des)
sender.setIcon(qtawesome.icon('fa.pencil', color='#4c8cf2')) sender.setIcon(qtawesome.icon('fa.pencil', color='#4c8cf2'))
rowIndex = sender.index[0]
varMes = HartSimulateVarManage.getByName(name) varMes = HartSimulateVarManage.getByName(name)
model.insert_data(varMes, rowIndex) model.insert_data(varMes, source_row)
model.remove_row(rowIndex + 1) model.remove_row(source_row + 1)
def start_action(self): def start_action(self):
sender = self.sender() sender = self.sender()
model = self.parent().model model = self.parent().model
value1 = model.datas[sender.index[0]][3]
minSpan = model.datas[sender.index[0]][7] # 使用基类的验证方法获取行索引
maxSpan = model.datas[sender.index[0]][8] view_row, source_row = self._validate_button_indices(sender)
writeList = [str(x) for x in model.datas[sender.index[0]][3:9]] if view_row is None:
return
# 获取强制值(从视图)和其他数据(从源模型)
value1 = self._get_view_data(view_row, 3) # 强制值列
minSpan = model.datas[source_row][7]
maxSpan = model.datas[source_row][8]
writeList = [str(x) for x in model.datas[source_row][3:9]]
pattern = re.compile(r'[^0-9\.-]+') pattern = re.compile(r'[^0-9\.-]+')
if minSpan and maxSpan and value1 and not re.findall(pattern, str(value1) + str(minSpan) + str(maxSpan)): if minSpan and maxSpan and value1 and not re.findall(pattern, str(value1) + str(minSpan) + str(maxSpan)):
if float(value1) < float(minSpan) or float(value1) > float(maxSpan): if float(value1) < float(minSpan) or float(value1) > float(maxSpan):
@ -188,5 +201,5 @@ class HartSimulateButtonDelegate(VarButtonDelegate):
return return
forceVars = Globals.getValue('forceVars') forceVars = Globals.getValue('forceVars')
forceVars.add(model.datas[sender.index[0]][1]) forceVars.add(model.datas[source_row][1])
Globals.setValue('forceVars', forceVars) Globals.setValue('forceVars', forceVars)

@ -9,6 +9,7 @@ from PyQt5 import QtGui,QtCore,QtWidgets
from PyQt5.QtCore import QAbstractTableModel, QModelIndex, Qt, QVariant, QSize from PyQt5.QtCore import QAbstractTableModel, QModelIndex, Qt, QVariant, QSize
from PyQt5.QtWidgets import QItemDelegate, QHBoxLayout, QWidget, QMessageBox, QComboBox, QStyleOptionViewItem from PyQt5.QtWidgets import QItemDelegate, QHBoxLayout, QWidget, QMessageBox, QComboBox, QStyleOptionViewItem
from UI.VarManages.BaseButtonDelegate import BaseButtonDelegate
from sympy import N from sympy import N
@ -204,12 +205,12 @@ class VarTableModel(QAbstractTableModel):
class VarButtonDelegate(QItemDelegate): class ModbusButtonDelegate(BaseButtonDelegate):
"""该类用于向单元格中添加按钮 任务表格""" """该类用于向单元格中添加按钮 任务表格"""
trendWidgetDict = {} trendWidgetDict = {}
def __init__(self, parent=None): def __init__(self, parent=None):
super(VarButtonDelegate, self).__init__(parent) super(ModbusButtonDelegate, self).__init__(parent)
def trendWidget(self, varName): def trendWidget(self, varName):
if varName not in self.trendWidgetDict: if varName not in self.trendWidgetDict:
@ -310,8 +311,16 @@ class VarButtonDelegate(QItemDelegate):
def start_action(self): def start_action(self):
sender = self.sender() sender = self.sender()
model = self.parent().model 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]) # 使用基类的验证方法获取行索引
view_row, source_row = self._validate_button_indices(sender)
if view_row is None:
return
# 获取强制值(从视图)和其他数据(从源模型)
value = str(self._get_view_data(view_row, 1)) # 强制值列
varMes = model.datas[source_row]
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[10])
pattern = re.compile(r'[^0-9\.-]+') pattern = re.compile(r'[^0-9\.-]+')
if not value or re.findall(pattern, str(value)): if not value or re.findall(pattern, str(value)):
reply = QMessageBox.question(self.parent(), reply = QMessageBox.question(self.parent(),
@ -363,22 +372,27 @@ class VarButtonDelegate(QItemDelegate):
sender = self.sender() sender = self.sender()
model = self.parent().model model = self.parent().model
modbusType = self.parent().modbusType modbusType = self.parent().modbusType
fucationCbRow = str('cb' + str(sender.index[0]) + str(5))
fucationIndex = self.parent().model.index(sender.index[0], 5) # 使用基类的验证方法获取行索引
view_row, source_row = self._validate_button_indices(sender)
if view_row is None:
return
fucationCbRow = str('cb' + str(source_row) + str(5))
fucationIndex = self.parent().model.index(source_row, 5)
fucationDelegate = self.parent().itemDelegate(fucationIndex) fucationDelegate = self.parent().itemDelegate(fucationIndex)
fucationCheckbox = getattr(fucationDelegate, fucationCbRow) fucationCheckbox = getattr(fucationDelegate, fucationCbRow)
if sender.isEdit: if sender.isEdit:
sender.setIcon(qtawesome.icon('fa.save', color='#1fbb6f')) sender.setIcon(qtawesome.icon('fa.save', color='#1fbb6f'))
sender.isEdit = False sender.isEdit = False
sender.oldName = model.datas[sender.index[0]][3] sender.oldName = model.datas[source_row][3]
model.editableList.append(sender.index[0]) model.editableList.append(source_row)
fucationCheckbox.setEnabled(True) fucationCheckbox.setEnabled(True)
self.parent().viewport().update() self.parent().viewport().update()
else: else:
varMes = model.datas[sender.index[0]] varMes = model.datas[source_row]
name, des, varType, slaveID, address, min, max, varModel, order = str(varMes[3]), str(varMes[4]), str(varMes[5]), str(varMes[6]), str(varMes[7]), str(varMes[8]), str(varMes[9]), str(varMes[-2]), str(varMes[-1]) name, des, varType, slaveID, address, min, max, varModel, order = str(varMes[3]), str(varMes[4]), str(varMes[5]), str(varMes[6]), str(varMes[7]), str(varMes[8]), str(varMes[9]), str(varMes[-2]), str(varMes[-1])
if varType == '': if varType == '':
varType = 0 varType = 0
@ -419,36 +433,47 @@ class VarButtonDelegate(QItemDelegate):
sender.setIcon(qtawesome.icon('fa.pencil', color='#4c8cf2')) sender.setIcon(qtawesome.icon('fa.pencil', color='#4c8cf2'))
rowIndex = sender.index[0]
varMes = ModbusVarManage.getByName(name, modbusType) varMes = ModbusVarManage.getByName(name, modbusType)
varMes.append('本地值') varMes.append('本地值')
varMes.append('int') varMes.append('int')
varMes.insert(1, '') varMes.insert(1, '')
varMes.insert(2, '') varMes.insert(2, '')
model.insert_data(varMes, rowIndex) model.insert_data(varMes, source_row)
model.remove_row(rowIndex + 1) model.remove_row(source_row + 1)
sender.isEdit = True sender.isEdit = True
fucationCheckbox.setEnabled(False) fucationCheckbox.setEnabled(False)
# varModelCheckbox.setEnabled(False) # varModelCheckbox.setEnabled(False)
model.editableList.remove(sender.index[0]) model.editableList.remove(source_row)
self.parent().viewport().update() self.parent().viewport().update()
def delete_action(self): def delete_action(self):
sender = self.sender() sender = self.sender()
model = self.parent().model model = self.parent().model
name = str(model.datas[sender.index[0]][3])
# 使用基类的验证方法获取行索引
view_row, source_row = self._validate_button_indices(sender)
if view_row is None:
return
name = str(model.datas[source_row][3])
modbusType = self.parent().modbusType modbusType = self.parent().modbusType
if sender.editButton.isEdit: if sender.editButton.isEdit:
ModbusVarManage.deleteVar(name = name, modbusType = modbusType) ModbusVarManage.deleteVar(name = name, modbusType = modbusType)
model.remove_row(sender.index[0]) model.remove_row(source_row)
def trend_action(self): def trend_action(self):
model = self.parent().model model = self.parent().model
if model.table.parent._isPopenOpen: if model.table.parent._isPopenOpen:
sender = self.sender() sender = self.sender()
name = str(model.datas[sender.index[0]][3])
# 使用基类的验证方法获取行索引
view_row, source_row = self._validate_button_indices(sender)
if view_row is None:
return
name = str(model.datas[source_row][3])
trend = self.trendWidget(varName = name) trend = self.trendWidget(varName = name)
trend.show() trend.show()

@ -89,8 +89,9 @@ class RpcVarModel(QAbstractTableModel):
return Qt.ItemIsEnabled return Qt.ItemIsEnabled
from PyQt5.QtWidgets import QStyledItemDelegate, QPushButton, QStyleOptionButton, QStyle, QApplication from PyQt5.QtWidgets import QStyledItemDelegate, QPushButton, QStyleOptionButton, QStyle, QApplication
from UI.VarManages.BaseButtonDelegate import BaseButtonDelegate
class RpcVarButtonDelegate(QStyledItemDelegate): class RpcVarButtonDelegate(BaseButtonDelegate):
def __init__(self, parent=None): def __init__(self, parent=None):
super(RpcVarButtonDelegate, self).__init__(parent) super(RpcVarButtonDelegate, self).__init__(parent)
@ -116,11 +117,16 @@ class RpcVarButtonDelegate(QStyledItemDelegate):
def force_action(self, sender): def force_action(self, sender):
model = self.parent().model model = self.parent().model
row = sender.index[0]
varName = model.datas[row][2] # 使用基类的验证方法获取行索引
minValue = model.datas[row][4] view_row, source_row = self._validate_button_indices(sender)
maxValue = model.datas[row][5] if view_row is None:
forceValue = model.inputValues.get(row, '') 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 == '': if forceValue == '':
QMessageBox.warning(self.parent(), '提示', '请先输入强制值') QMessageBox.warning(self.parent(), '提示', '请先输入强制值')
return return

@ -6,6 +6,7 @@ from PyQt5.QtWidgets import QHBoxLayout, QWidget, QMessageBox, QComboBox
from protocol.TCP.TemToMv import temToMv from protocol.TCP.TemToMv import temToMv
from model.ProjectModel.VarManage import * from model.ProjectModel.VarManage import *
from UI.VarManages.ModbusModel import * from UI.VarManages.ModbusModel import *
from UI.VarManages.BaseButtonDelegate import BaseButtonDelegate
from UI.TrendManage.ActualTrendWidget import ActualTrend from UI.TrendManage.ActualTrendWidget import ActualTrend
from utils import Globals from utils import Globals
import re import re
@ -105,7 +106,7 @@ class TcRtdModel(VarTableModel):
class TcRtdButtonDelegate(VarButtonDelegate): class TcRtdButtonDelegate(BaseButtonDelegate):
"""该类用于向单元格中添加按钮 任务表格""" """该类用于向单元格中添加按钮 任务表格"""
def __init__(self, parent=None): def __init__(self, parent=None):
@ -173,12 +174,20 @@ class TcRtdButtonDelegate(VarButtonDelegate):
def start_action(self): def start_action(self):
sender = self.sender() sender = self.sender()
model = self.parent().model model = self.parent().model
value = model.datas[sender.index[0]][1]
varType = model.datas[sender.index[0]][6] # 使用基类的验证方法获取行索引
min = model.datas[sender.index[0]][7] view_row, source_row = self._validate_button_indices(sender)
max = model.datas[sender.index[0]][8] if view_row is None:
compensation = model.datas[sender.index[0]][9] 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\.-]+') pattern = re.compile(r'[^0-9\.-]+')
print(model.datas[source_row][3])
if not value or re.findall(pattern, str(value) + str(compensation)): if not value or re.findall(pattern, str(value) + str(compensation)):
reply = QMessageBox.question(self.parent(), reply = QMessageBox.question(self.parent(),
'警告', '警告',
@ -216,13 +225,13 @@ class TcRtdButtonDelegate(VarButtonDelegate):
# 直接写入变量值 # 直接写入变量值
res = Globals.getValue('protocolManage').writeVariableValue( res = Globals.getValue('protocolManage').writeVariableValue(
model.datas[sender.index[0]][3], model.datas[source_row][3],
float(value) float(value)
) )
if res: if res:
forceVars = Globals.getValue('forceVars') forceVars = Globals.getValue('forceVars')
forceVars.add(model.datas[sender.index[0]][3]) forceVars.add(model.datas[source_row][3])
Globals.setValue('forceVars', forceVars) Globals.setValue('forceVars', forceVars)
else: else:
QMessageBox.information(self.parent(), '提示', '写入失败', QMessageBox.Yes) QMessageBox.information(self.parent(), '提示', '写入失败', QMessageBox.Yes)
@ -230,13 +239,19 @@ class TcRtdButtonDelegate(VarButtonDelegate):
def edit_action(self): def edit_action(self):
sender = self.sender() sender = self.sender()
model = self.parent().model model = self.parent().model
# 使用基类的验证方法获取行索引
view_row, source_row = self._validate_button_indices(sender)
if view_row is None:
return
if sender.isEdit: if sender.isEdit:
sender.setIcon(qtawesome.icon('fa.save', color='#1fbb6f')) sender.setIcon(qtawesome.icon('fa.save', color='#1fbb6f'))
sender.isEdit = False sender.isEdit = False
sender.oldName = model.datas[sender.index[0]][3] sender.oldName = model.datas[source_row][3]
model.editableList.append(sender.index[0]) model.editableList.append(source_row)
else: else:
varMes = model.datas[sender.index[0]] 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]) 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: if not name or not varType:
reply = QMessageBox.question(self.parent(), reply = QMessageBox.question(self.parent(),
@ -245,7 +260,7 @@ class TcRtdButtonDelegate(VarButtonDelegate):
QMessageBox.Yes) QMessageBox.Yes)
return return
sender.isEdit = True sender.isEdit = True
model.editableList.remove(sender.index[0]) model.editableList.remove(source_row)
if sender.oldName: if sender.oldName:
if sender.oldName == name: if sender.oldName == name:
TcRtdManage.editVar(name=sender.oldName, Nname=name, channelNumber = channelNumber, des=des, TcRtdManage.editVar(name=sender.oldName, Nname=name, channelNumber = channelNumber, des=des,
@ -267,18 +282,23 @@ class TcRtdButtonDelegate(VarButtonDelegate):
min=min, max=max, compensationVar = compensationVar) min=min, max=max, compensationVar = compensationVar)
sender.setIcon(qtawesome.icon('fa.pencil', color='#4c8cf2')) sender.setIcon(qtawesome.icon('fa.pencil', color='#4c8cf2'))
rowIndex = sender.index[0]
varMes = TcRtdManage.getByName(name) varMes = TcRtdManage.getByName(name)
varMes.insert(1, '') varMes.insert(1, '')
varMes.insert(2, '') varMes.insert(2, '')
varMes.append('') varMes.append('')
model.insert_data(varMes, rowIndex) model.insert_data(varMes, source_row)
model.remove_row(rowIndex + 1) model.remove_row(source_row + 1)
def trend_action(self): def trend_action(self):
sender = self.sender() sender = self.sender()
model = self.parent().model model = self.parent().model
varName = model.datas[sender.index[0]][3]
# 使用基类的验证方法获取行索引
view_row, source_row = self._validate_button_indices(sender)
if view_row is None:
return
varName = model.datas[source_row][3]
# 以变量名为key避免重复打开 # 以变量名为key避免重复打开
if varName not in self.trendWindows or self.trendWindows[varName] is None: if varName not in self.trendWindows or self.trendWindows[varName] is None:
self.trendWindows[varName] = ActualTrend(varName=varName) self.trendWindows[varName] = ActualTrend(varName=varName)

@ -80,7 +80,7 @@ class VarTableView(QTableView):
def setHeader(self): def setHeader(self):
self.setItemDelegateForColumn(11, VarButtonDelegate(self)) self.setItemDelegateForColumn(11, ModbusButtonDelegate(self))
self.setItemDelegateForColumn(5, ModbusTypeBox(self)) self.setItemDelegateForColumn(5, ModbusTypeBox(self))
self.setItemDelegateForColumn(10, ModbusVarModelBox(self)) self.setItemDelegateForColumn(10, ModbusVarModelBox(self))
self.model = VarTableModel(['ID', '强制值', '当前值', '变量名', '变量描述', '变量类型', self.model = VarTableModel(['ID', '强制值', '当前值', '变量名', '变量描述', '变量类型',

@ -71,7 +71,7 @@ class VarWidgets(QtWidgets.QWidget):
self.timer = QTimer(self) self.timer = QTimer(self)
# 将定时器超时信号与槽函数showTime()连接 # 将定时器超时信号与槽函数showTime()连接
self.timer.timeout.connect(self.proxy.invalidate) self.timer.timeout.connect(self.proxy.invalidate)
self.timer.start(50) # 启动timer self.timer.start(500) # 启动timer
Globals.setValue(str(self.modbusType) + 'Table', self.varView) Globals.setValue(str(self.modbusType) + 'Table', self.varView)

@ -51,8 +51,8 @@ class ModbusManager:
"""启动 Modbus TCP 主站""" """启动 Modbus TCP 主站"""
try: try:
if self.modbusTcpMaster is not None: if self.modbusTcpMaster is not None:
return True self.modbusTcpMaster.master.close()
self.modbusTcpMaster = None
# 从数据库获取TCP设置 # 从数据库获取TCP设置
tcpSettings = self._getTcpSettings('master') tcpSettings = self._getTcpSettings('master')
if not tcpSettings: if not tcpSettings:
@ -93,8 +93,8 @@ class ModbusManager:
"""启动 Modbus RTU 主站""" """启动 Modbus RTU 主站"""
try: try:
if self.modbusRtuMaster is not None: if self.modbusRtuMaster is not None:
return True self.modbusRtuMaster.master.close()
self.modbusRtuMaster = None
# 从数据库获取RTU设置 # 从数据库获取RTU设置
rtuSettings = self._getRtuSettings('master') rtuSettings = self._getRtuSettings('master')
if not rtuSettings: if not rtuSettings:
@ -136,8 +136,9 @@ class ModbusManager:
"""启动 Modbus TCP 从站""" """启动 Modbus TCP 从站"""
try: try:
if self.modbusTcpSlave is not None: if self.modbusTcpSlave is not None:
return True self.modbusTcpSlave.server.close()
self.modbusTcpSlave = None
# 从数据库获取TCP设置 # 从数据库获取TCP设置
tcpSettings = self._getTcpSettings('slave') tcpSettings = self._getTcpSettings('slave')
if not tcpSettings: if not tcpSettings:
@ -150,7 +151,7 @@ class ModbusManager:
) )
# 添加默认从站ID # 添加默认从站ID
self.modbusTcpSlave.addSlave(1) # self.modbusTcpSlave.addSlave(1)
return True return True
@ -177,10 +178,12 @@ class ModbusManager:
"""启动 Modbus RTU 从站""" """启动 Modbus RTU 从站"""
try: try:
if self.modbusRtuSlave is not None: if self.modbusRtuSlave is not None:
return True self.modbusRtuSlave.server.close()
self.modbusRtuSlave = None
# 从数据库获取RTU设置 # 从数据库获取RTU设置
rtuSettings = self._getRtuSettings('slave') rtuSettings = self._getRtuSettings('slave')
if not rtuSettings: if not rtuSettings:
return False return False
@ -197,7 +200,7 @@ class ModbusManager:
self.modbusRtuSlave.start() self.modbusRtuSlave.start()
# 添加默认从站ID # 添加默认从站ID
self.modbusRtuSlave.addSlave(1) # self.modbusRtuSlave.addSlave(1)
return True return True
@ -309,40 +312,7 @@ class ModbusManager:
except Exception as e: except Exception as e:
print(f"写入RTU从站变量失败: {str(e)}") print(f"写入RTU从站变量失败: {str(e)}")
return False return False
def readModbusTcpMasterValue(self, info):
"""读取TCP主站变量值"""
try:
if self.modbusTcpMaster is None:
return None
slaveId = int(info['slaveID'])
address = int(info['address'])
varType = int(info['varType'])
order = info['order']
return self._readModbusValue(self.modbusTcpMaster, slaveId, address, varType, order)
except Exception as e:
print(f"读取TCP主站变量失败: {str(e)}")
return None
def readModbusRtuMasterValue(self, info):
"""读取RTU主站变量值"""
try:
if self.modbusRtuMaster is None:
return None
slaveId = int(info['slaveID'])
address = int(info['address'])
varType = int(info['varType'])
order = info['order']
return self._readModbusValue(self.modbusRtuMaster, slaveId, address, varType, order)
except Exception as e:
print(f"读取RTU主站变量失败: {str(e)}")
return None
def readModbusTcpSlaveValue(self, info): def readModbusTcpSlaveValue(self, info):
"""读取TCP从站变量值""" """读取TCP从站变量值"""
@ -509,6 +479,7 @@ class ModbusManager:
if value != 'error' and self.variableValueCache is not None and self.cacheLock is not None: if value != 'error' and self.variableValueCache is not None and self.cacheLock is not None:
with self.cacheLock: with self.cacheLock:
self.variableValueCache[varName] = value self.variableValueCache[varName] = value
print(varName, value)
except Exception as e: except Exception as e:
print(f"读取TCP主站变量失败 {varName}: {str(e)}") print(f"读取TCP主站变量失败 {varName}: {str(e)}")

@ -69,7 +69,11 @@ class RTUSlave():
def readValue(self, slaveId, name, address, order = 'int'): def readValue(self, slaveId, name, address, order = 'int'):
try: try:
slave = self.server.get_slave(slaveId) try:
slave = self.server.get_slave(slaveId)
except Exception as e:
if type(e) == MissingKeyError:
self.addSlave(slaveId)
if order == 'int': if order == 'int':
value = slave.get_values(name, address, 1)[0] value = slave.get_values(name, address, 1)[0]
else: else:
@ -86,7 +90,6 @@ class RTUSlave():
value = ABCDToFloat(value) value = ABCDToFloat(value)
return value return value
except Exception as e: except Exception as e:
print(e)
return 'error' return 'error'

@ -2,6 +2,7 @@
import modbus_tk import modbus_tk
import modbus_tk.defines as cst import modbus_tk.defines as cst
from modbus_tk import modbus_tcp, hooks from modbus_tk import modbus_tcp, hooks
from modbus_tk.exceptions import *
import serial import serial
import struct import struct
from .ByteOrder import * from .ByteOrder import *
@ -80,7 +81,11 @@ class TCPSlave():
def readValue(self, slaveId, name, address, order = 'int'): def readValue(self, slaveId, name, address, order = 'int'):
try: try:
slave = self.server.get_slave(slaveId) try:
slave = self.server.get_slave(slaveId)
except Exception as e:
if type(e) == MissingKeyError:
self.addSlave(slaveId)
if order == 'int': if order == 'int':
value = slave.get_values(name, address, 1)[0] value = slave.get_values(name, address, 1)[0]
else: else:
@ -95,6 +100,7 @@ class TCPSlave():
value = CDABToFloat(value) value = CDABToFloat(value)
return value return value
except Exception as e: except Exception as e:
return 'error' return 'error'

@ -35,7 +35,7 @@ class ProtocolManage(object):
# Modbus 管理器 # Modbus 管理器
self.modbusManager = ModbusManager() self.modbusManager = ModbusManager()
self.modbusManager.setVariableCache(self.variableValueCache, None, self.varInfoCache) # self.modbusManager.setVariableCache(self.variableValueCache, None, self.varInfoCache)
self.refreshVarCache() self.refreshVarCache()
self.cacheLock = threading.Lock() self.cacheLock = threading.Lock()
@ -238,12 +238,12 @@ class ProtocolManage(object):
info = varInfo['variableData'] info = varInfo['variableData']
try: try:
# 拆分为独立的协议条件判断 # 拆分为独立的协议条件判断
if modelType == 'ModbusTcpMasterVar': # if modelType == 'ModbusTcpMasterVar':
value = self.modbusManager.readModbusTcpMasterValue(info) # value = self.modbusManager.readModbusTcpMasterValue(info)
elif modelType == 'ModbusTcpSlaveVar': if modelType == 'ModbusTcpSlaveVar':
value = self.modbusManager.readModbusTcpSlaveValue(info) value = self.modbusManager.readModbusTcpSlaveValue(info)
elif modelType == 'ModbusRtuMasterVar': # elif modelType == 'ModbusRtuMasterVar':
value = self.modbusManager.readModbusRtuMasterValue(info) # value = self.modbusManager.readModbusRtuMasterValue(info)
elif modelType == 'ModbusRtuSlaveVar': elif modelType == 'ModbusRtuSlaveVar':
value = self.modbusManager.readModbusRtuSlaveValue(info) value = self.modbusManager.readModbusRtuSlaveValue(info)
elif modelType == 'HartVar': elif modelType == 'HartVar':

Loading…
Cancel
Save