更换界面样式 修复远程数据丢失bug

main
zcwBit 4 months ago
parent ea3f8acb28
commit 180a2e92e7

File diff suppressed because it is too large Load Diff

@ -174,9 +174,9 @@ class MainWindow(QMainWindow):
self.horizontalLayout.addWidget(self.leftWidget)
self.horizontalLayout.addWidget(self.rightWidget)
self.horizontalLayout.setStretch(0, 1)
self.horizontalLayout.setStretch(1, 7)
self.horizontalLayout.setStretch(1, 10)
self.horizontalLayout.setContentsMargins(0, 0, 0, 0)
self.horizontalLayout.setSpacing(5)
self.horizontalLayout.setSpacing(1)
self.verticalLayout.setContentsMargins(0, 0, 0, 0)
self.verticalLayout.addWidget(self.topWidget)
self.verticalLayout.addLayout(self.horizontalLayout)

@ -2,6 +2,7 @@ from PyQt5 import QtCore, QtWidgets
from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import QWidget, QSizePolicy
from PyQt5.QtGui import QIcon
import qtawesome as qta
class MainLeft(QWidget):
def __init__(self):
@ -11,12 +12,10 @@ class MainLeft(QWidget):
def setupUi(self):
# 创建导航按钮
self.createProject = QtWidgets.QPushButton(self)
self.createProject.setObjectName("createProject")
# self.openProject = QtWidgets.QPushButton(self)
# self.openProject.setObjectName("openProject")
self.varMag = QtWidgets.QPushButton(self)
self.varMag.setObjectName("varMag")
@ -30,162 +29,211 @@ class MainLeft(QWidget):
self.protocolMag.setObjectName("protocolMag")
self.procedureMag = QtWidgets.QPushButton(self)
self.procedureMag.setObjectName("protocolMag")
self.procedureMag.setObjectName("procedureMag")
self.controlMag = QtWidgets.QPushButton(self)
self.controlMag.setObjectName("controlMag")
# 创建主布局
self.verticalLayout = QtWidgets.QVBoxLayout(self)
self.verticalLayout.setContentsMargins(0, 0, 0, 0)
self.verticalLayout.setContentsMargins(16, 24, 16, 24)
self.verticalLayout.setSpacing(6)
self.verticalLayout.setObjectName("verticalLayout")
spacerItem = QtWidgets.QSpacerItem(40, 10, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
self.verticalLayout.addWidget(QtWidgets.QSplitter())
# 顶部间距
topSpacer = QtWidgets.QSpacerItem(20, 20, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Fixed)
self.verticalLayout.addItem(topSpacer)
# 添加导航按钮
self.verticalLayout.addWidget(self.createProject)
self.verticalLayout.addWidget(QtWidgets.QSplitter())
# self.verticalLayout.addWidget(self.openProject)
# self.verticalLayout.addWidget(QtWidgets.QSplitter())
self.verticalLayout.addWidget(self.varMag)
self.verticalLayout.addWidget(QtWidgets.QSplitter())
self.verticalLayout.addWidget(self.trendMag)
self.verticalLayout.addWidget(QtWidgets.QSplitter())
self.verticalLayout.addWidget(self.userMag)
self.verticalLayout.addWidget(QtWidgets.QSplitter())
self.verticalLayout.addWidget(self.protocolMag)
self.verticalLayout.addWidget(QtWidgets.QSplitter())
self.verticalLayout.addWidget(self.procedureMag)
self.verticalLayout.addWidget(QtWidgets.QSplitter())
self.verticalLayout.addWidget(self.controlMag)
self.verticalLayout.addWidget(QtWidgets.QSplitter())
self.verticalLayout.setStretch(0, 1)
self.verticalLayout.setStretch(1, 4)
self.verticalLayout.setStretch(2, 2)
self.verticalLayout.setStretch(3, 4)
self.verticalLayout.setStretch(4, 2)
self.verticalLayout.setStretch(5, 4)
self.verticalLayout.setStretch(6, 2)
self.verticalLayout.setStretch(7, 4)
self.verticalLayout.setStretch(8, 2)
self.verticalLayout.setStretch(9, 4)
self.verticalLayout.setStretch(10, 2)
self.verticalLayout.setStretch(11, 4)
self.verticalLayout.setStretch(12, 2)
self.verticalLayout.setStretch(13, 4)
self.verticalLayout.setStretch(14, 35)
QtCore.QMetaObject.connectSlotsByName(self)
# 底部弹性空间
bottomSpacer = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding)
self.verticalLayout.addItem(bottomSpacer)
self.createProject.setText('工程管理')
# self.openProject.setText("打开工程")
self.varMag.setText("变量管理")
self.trendMag.setText("历史趋势")
self.userMag.setText("用户管理")
self.protocolMag.setText("通讯配置")
self.procedureMag.setText("规程管理")
self.controlMag.setText("控制系统")
self.createProject.setIcon(QIcon('./Static/newH.png'))
# self.openProject.setIcon(QIcon('./Static/open.png'))
self.varMag.setIcon(QIcon('./Static/varMag.png'))
self.trendMag.setIcon(QIcon('./Static/trend.png'))
self.userMag.setIcon(QIcon('./Static/userMag.png'))
self.protocolMag.setIcon(QIcon('./Static/setting.png'))
self.procedureMag.setIcon(QIcon('./Static/procedure.png'))
self.controlMag.setIcon(QIcon('./Static/control.png'))
QtCore.QMetaObject.connectSlotsByName(self)
# 设置按钮文本
self.createProject.setText(' 工程管理')
self.varMag.setText(" 变量管理")
self.trendMag.setText(" 历史数据")
self.userMag.setText(" 用户管理")
self.protocolMag.setText(" 通讯配置")
self.procedureMag.setText(" 规程管理")
self.controlMag.setText(" 控制系统")
# 定义工业控制风格的图标配置
self.icon_config = {
'createProject': {
'icon': 'fa5s.project-diagram', # 项目图标
'normal_color': '#6B7280',
'hover_color': '#2277EF',
'selected_color': '#FFFFFF'
},
'varMag': {
'icon': 'fa5s.server', # 服务器/变量管理
'normal_color': '#6B7280',
'hover_color': '#2277EF',
'selected_color': '#FFFFFF'
},
'trendMag': {
'icon': 'fa5s.chart-area', # 面积图/历史趋势
'normal_color': '#6B7280',
'hover_color': '#2277EF',
'selected_color': '#FFFFFF'
},
'userMag': {
'icon': 'fa5s.user-shield', # 用户管理/权限
'normal_color': '#6B7280',
'hover_color': '#2277EF',
'selected_color': '#FFFFFF'
},
'protocolMag': {
'icon': 'fa5s.ethernet', # 以太网/通讯协议
'normal_color': '#6B7280',
'hover_color': '#2277EF',
'selected_color': '#FFFFFF'
},
'procedureMag': {
'icon': 'fa5s.clipboard-list', # 清单/规程管理
'normal_color': '#6B7280',
'hover_color': '#2277EF',
'selected_color': '#FFFFFF'
},
'controlMag': {
'icon': 'fa5s.microchip', # 芯片/控制系统
'normal_color': '#6B7280',
'hover_color': '#2277EF',
'selected_color': '#FFFFFF'
}
}
# 设置初始图标(正常状态)
self.setButtonIcon(self.createProject, 'createProject', 'normal')
self.setButtonIcon(self.varMag, 'varMag', 'normal')
self.setButtonIcon(self.trendMag, 'trendMag', 'normal')
self.setButtonIcon(self.userMag, 'userMag', 'normal')
self.setButtonIcon(self.protocolMag, 'protocolMag', 'normal')
self.setButtonIcon(self.procedureMag, 'procedureMag', 'normal')
self.setButtonIcon(self.controlMag, 'controlMag', 'normal')
# 配置所有按钮
for btn in [self.createProject, self.varMag, self.trendMag, self.userMag, self.protocolMag, self.procedureMag, self.controlMag]:
self.setBtn(btn)
# self.openProject.clicked.connect(lambda:self.openProject.setIcon(QIcon('./Static/openH.png')))
self.createProject.clicked.connect(lambda:self.createProject.setIcon(QIcon('./Static/newH.png')))
self.varMag.clicked.connect(lambda:self.varMag.setIcon(QIcon('./Static/varMagH.png')))
self.trendMag.clicked.connect(lambda:self.trendMag.setIcon(QIcon('./Static/trendH.png')))
self.userMag.clicked.connect(lambda:self.userMag.setIcon(QIcon('./Static/userMagH.png')))
self.protocolMag.clicked.connect(lambda:self.protocolMag.setIcon(QIcon('./Static/settingH.png')))
self.controlMag.clicked.connect(lambda:self.controlMag.setIcon(QIcon('./Static/controlH.png')))
# 连接点击事件 - 设置选中时的白色图标
self.createProject.clicked.connect(lambda: self.setSelectedIcon(self.createProject, 'createProject'))
self.varMag.clicked.connect(lambda: self.setSelectedIcon(self.varMag, 'varMag'))
self.trendMag.clicked.connect(lambda: self.setSelectedIcon(self.trendMag, 'trendMag'))
self.userMag.clicked.connect(lambda: self.setSelectedIcon(self.userMag, 'userMag'))
self.protocolMag.clicked.connect(lambda: self.setSelectedIcon(self.protocolMag, 'protocolMag'))
self.procedureMag.clicked.connect(lambda: self.setSelectedIcon(self.procedureMag, 'procedureMag'))
self.controlMag.clicked.connect(lambda: self.setSelectedIcon(self.controlMag, 'controlMag'))
# 设置默认选中状态
self.createProject.setChecked(True)
self.createProject.setDown(True)
self.setSelectedIcon(self.createProject, 'createProject')
def setButtonIcon(self, button, button_key, state):
"""设置按钮图标
Args:
button: 按钮对象
button_key: 按钮配置键
state: 状态 ('normal', 'hover', 'selected')
"""
config = self.icon_config[button_key]
icon_name = config['icon']
if state == 'normal':
color = config['normal_color']
elif state == 'hover':
color = config['hover_color']
elif state == 'selected':
color = config['selected_color']
else:
color = config['normal_color']
# 创建QtAwesome图标
icon = qta.icon(icon_name, color=color)
button.setIcon(icon)
def setSelectedIcon(self, button, button_key):
"""设置选中按钮的白色图标"""
self.setButtonIcon(button, button_key, 'selected')
def setBtn(self, btn):
btn.setCheckable(True)
btn.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Preferred)
btn.setAttribute(Qt.WA_Hover,True)
btn.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
btn.setAttribute(Qt.WA_Hover, True)
btn.installEventFilter(self)
btn.setIconSize(QtCore.QSize(26, 26))
btn.setIconSize(QtCore.QSize(22, 22))
btn.clicked.connect(self.clearButton)
btn.setAutoExclusive(True)
btn.clicked.connect(lambda:btn.setDown(True))
btn.clicked.connect(lambda:btn.setChecked(True))
btn.clicked.connect(lambda: btn.setDown(True))
btn.clicked.connect(lambda: btn.setChecked(True))
# 设置固定高度和样式
btn.setFixedHeight(56)
btn.setStyleSheet("""
QPushButton {
text-align: left;
padding-left: 20px;
border: none;
outline: none;
}
""")
def eventFilter(self, object, event):
if object == self.createProject:
if event.type() == QtCore.QEvent.HoverEnter:
self.createProject.setIcon(QIcon('./Static/newH.png'))
return True
if event.type() == QtCore.QEvent.HoverLeave and not self.createProject.isChecked():
self.createProject.setIcon(QIcon('./Static/new.png'))
return True
# if object == self.openProject:
# if event.type() == QtCore.QEvent.HoverEnter:
# self.openProject.setIcon(QIcon('./Static/openH.png'))
# return True
# if event.type() == QtCore.QEvent.HoverLeave and not self.openProject.isChecked():
# self.openProject.setIcon(QIcon('./Static/open.png'))
# return True
if object == self.varMag:
if event.type() == QtCore.QEvent.HoverEnter:
self.varMag.setIcon(QIcon('./Static/varMagH.png'))
return True
if event.type() == QtCore.QEvent.HoverLeave and not self.varMag.isChecked():
self.varMag.setIcon(QIcon('./Static/varMag.png'))
return True
if object == self.trendMag:
if event.type() == QtCore.QEvent.HoverEnter:
self.trendMag.setIcon(QIcon('./Static/trendH.png'))
return True
if event.type() == QtCore.QEvent.HoverLeave and not self.trendMag.isChecked():
self.trendMag.setIcon(QIcon('./Static/trend.png'))
return True
if object == self.userMag:
if event.type() == QtCore.QEvent.HoverEnter:
self.userMag.setIcon(QIcon('./Static/userMagH.png'))
return True
if event.type() == QtCore.QEvent.HoverLeave and not self.userMag.isChecked():
self.userMag.setIcon(QIcon('./Static/userMag.png'))
return True
if object == self.protocolMag:
if event.type() == QtCore.QEvent.HoverEnter:
self.protocolMag.setIcon(QIcon('./Static/settingH.png'))
return True
if event.type() == QtCore.QEvent.HoverLeave and not self.protocolMag.isChecked():
self.protocolMag.setIcon(QIcon('./Static/setting.png'))
return True
if object == self.controlMag:
# 定义按钮与配置键的映射
button_mapping = {
self.createProject: 'createProject',
self.varMag: 'varMag',
self.trendMag: 'trendMag',
self.userMag: 'userMag',
self.protocolMag: 'protocolMag',
self.procedureMag: 'procedureMag',
self.controlMag: 'controlMag'
}
if object in button_mapping:
button_key = button_mapping[object]
if event.type() == QtCore.QEvent.HoverEnter:
self.controlMag.setIcon(QIcon('./Static/controlH.png'))
if not object.isChecked():
self.setButtonIcon(object, button_key, 'hover')
return True
if event.type() == QtCore.QEvent.HoverLeave and not self.controlMag.isChecked():
self.controlMag.setIcon(QIcon('./Static/control.png'))
elif event.type() == QtCore.QEvent.HoverLeave:
if object.isChecked():
self.setButtonIcon(object, button_key, 'selected')
else:
self.setButtonIcon(object, button_key, 'normal')
return True
return False
def clearButton(self):
self.createProject.setDown(False)
# self.openProject.setDown(False)
self.varMag.setDown(False)
self.trendMag.setDown(False)
self.userMag.setDown(False)
self.protocolMag.setDown(False)
self.controlMag.setDown(False)
self.createProject.setIcon(QIcon('./Static/new.png'))
# self.openProject.setIcon(QIcon('./Static/open.png'))
self.varMag.setIcon(QIcon('./Static/varMag.png'))
self.trendMag.setIcon(QIcon('./Static/trend.png'))
self.userMag.setIcon(QIcon('./Static/userMag.png'))
self.protocolMag.setIcon(QIcon('./Static/setting.png'))
self.controlMag.setIcon(QIcon('./Static/control.png'))
# 重置所有按钮状态
buttons = [
(self.createProject, 'createProject'),
(self.varMag, 'varMag'),
(self.trendMag, 'trendMag'),
(self.userMag, 'userMag'),
(self.protocolMag, 'protocolMag'),
(self.procedureMag, 'procedureMag'),
(self.controlMag, 'controlMag')
]
for button, button_key in buttons:
button.setDown(False)
# 重置图标为正常状态
self.setButtonIcon(button, button_key, 'normal')

@ -71,11 +71,11 @@ class ProjectTableModel(QAbstractTableModel):
if role == Qt.BackgroundRole:
if str(self.datas[QModelIndex.row()][1]) == str(Globals.getValue('currentPro')):
return QtGui.QColor('#00FF7F')
return QtGui.QColor('#FFFFFF')
if role == Qt.TextColorRole:
if QModelIndex.column() == 6:
return QtGui.QColor('#000000')
return QtGui.QColor('#1A1A1A')
# return QtGui.QColor('#FFFFFF')
# if role == Qt.TextColorRole:
# if QModelIndex.column() == 6:
# return QtGui.QColor('#000000')
# return QtGui.QColor('#1A1A1A')
if role == Qt.CheckStateRole:
if QModelIndex.column() == 0:
return Qt.Checked if self.checkList[QModelIndex.row()] == 'Checked' else Qt.Unchecked
@ -146,7 +146,24 @@ class ProjectButtonDelegate(QItemDelegate):
def __init__(self, parent=None):
super(ProjectButtonDelegate, self).__init__(parent)
def sizeHint(self, option, index):
"""设置项目的尺寸提示,确保足够的高度"""
size = super().sizeHint(option, index)
size.setHeight(max(60, size.height())) # 最小高度60px
return size
def paint(self, painter, option, index):
# 首先绘制背景颜色与BackgroundDelegate保持一致
if index.data(QtCore.Qt.BackgroundRole):
height = option.rect.height()
top = option.rect.top()
# 减少高度调整,保持更多的绘制区域
paint_rect = option.rect
paint_rect.setHeight(max(56, height - 4)) # 最小保持56px高度
paint_rect.moveTop(top + 2)
painter.fillRect(paint_rect, index.data(QtCore.Qt.BackgroundRole))
# 然后创建按钮部件
if not self.parent().indexWidget(index):
button1 = QPushButton(
qtawesome.icon('fa.exchange', color='#1fbb6f'),
@ -195,6 +212,14 @@ class ProjectButtonDelegate(QItemDelegate):
widget = QWidget()
widget.setLayout(h_box_layout)
widget.setObjectName('projectBtnWidget')
# 设置widget的背景为透明让底层的背景颜色显示出来
widget.setStyleSheet("""
QWidget#projectBtnWidget {
background-color: transparent;
}
""")
self.parent().setIndexWidget(
index,
widget
@ -312,11 +337,20 @@ class BackgroundDelegate(QtWidgets.QStyledItemDelegate):
def __init__(self, *args):
super(BackgroundDelegate, self).__init__(*args)
self.setObjectName('item')
def sizeHint(self, option, index):
"""设置项目的尺寸提示,确保足够的高度"""
size = super().sizeHint(option, index)
size.setHeight(max(60, size.height())) # 最小高度60px
return size
def paint(self, painter, option, index):
# 确保绘制区域有足够的高度
if index.data(QtCore.Qt.BackgroundRole):
height = option.rect.height()
top = option.rect.top()
option.rect.setHeight(height - 7)
option.rect.moveTop(top + 6)
# 减少高度调整,保持更多的绘制区域
option.rect.setHeight(max(56, height - 4)) # 最小保持56px高度
option.rect.moveTop(top + 2)
painter.fillRect(option.rect, index.data(QtCore.Qt.BackgroundRole))
super().paint(painter, option, index)

@ -13,15 +13,23 @@ class ProjectTableView(QTableView):
self.setItemDelegateForColumn(4, ProjectButtonDelegate(self))
self.setShowGrid(False)
self.setSelectionBehavior(QAbstractItemView.SelectRows)
self.model = ProjectTableModel([' ID', '工程名称', '工程描述', '创建时间', '操作'],[], table = self)
self.model = ProjectTableModel([' ID', '工程名称', '工程描述', '创建时间', '操作'],[], table = self)
self.setModel(self.model)
self.header = CheckBoxHeader(changeY = True)
self.header = CheckBoxHeader(changeY = -15)
self.header.setStretchLastSection(True)
self.header.setSectionResizeMode(QHeaderView.Stretch)
self.header.checkClicked.connect(self.model.headerClick)
self.header.setObjectName('projectHeader')
self.setHorizontalHeader(self.header)
self.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
self.verticalHeader().setDefaultSectionSize(50)
self.verticalHeader().hide()
self.header.setSectionResizeMode(0, QHeaderView.Fixed)
self.header.resizeSection(0, 70)
# 设置行高
self.verticalHeader().setDefaultSectionSize(60)
self.verticalHeader().setMinimumSectionSize(60)
# 设置表格属性
self.setAlternatingRowColors(False)
self.setWordWrap(True)

@ -160,11 +160,20 @@ class DeviceMasterWidget(QMainWindow):
serverLayout.addWidget(self.publicServerInput)
publicLayout.addLayout(serverLayout)
# 启动公网服务端按钮
self.publicConnectButton = QPushButton('启动公网服务端模式')
# 公网服务端控制按钮
serverButtonLayout = QHBoxLayout()
self.publicConnectButton = QPushButton('启动公网服务端')
self.publicConnectButton.clicked.connect(self.startPublicServer)
self.publicConnectButton.setObjectName('setButton')
publicLayout.addWidget(self.publicConnectButton)
serverButtonLayout.addWidget(self.publicConnectButton)
self.publicDisconnectButton = QPushButton('关闭公网服务端')
self.publicDisconnectButton.clicked.connect(self.stopPublicServer)
self.publicDisconnectButton.setObjectName('setButton')
self.publicDisconnectButton.setEnabled(False)
serverButtonLayout.addWidget(self.publicDisconnectButton)
publicLayout.addLayout(serverButtonLayout)
# 公网客户端扫描区域
publicLayout.addWidget(QLabel('公网服务器客户端列表:'))
@ -276,10 +285,39 @@ class DeviceMasterWidget(QMainWindow):
# 设置为服务端模式
Globals.getValue('protocolManage').closeClient()
Globals.getValue('protocolManage').setServerMode(rabbitmqHost=serverIp)
# 更新按钮状态
self.publicConnectButton.setEnabled(False)
self.publicDisconnectButton.setEnabled(True)
QMessageBox.information(self, '成功', f'已启动公网服务端模式\n服务器地址: {serverIp}')
except Exception as e:
QMessageBox.critical(self, '失败', f'启动公网服务端模式失败: {str(e)}')
def stopPublicServer(self):
"""关闭公网服务端模式"""
try:
# 关闭服务端模式
Globals.getValue('protocolManage').closeServer()
# 更新按钮状态
self.publicConnectButton.setEnabled(True)
self.publicDisconnectButton.setEnabled(False)
# 清空客户端列表
self.publicClientList.clear()
self.publicClients = []
self.connectPublicButton.setEnabled(False)
# 停止自动刷新
if self.autoRefreshEnabled:
self.autoRefreshCheckBox.setChecked(False)
self.toggleAutoRefresh(0)
QMessageBox.information(self, '成功', '已关闭公网服务端模式')
except Exception as e:
QMessageBox.critical(self, '失败', f'关闭公网服务端模式失败: {str(e)}')
def scanPublicClients(self):
"""扫描公网服务器上的客户端"""
serverIp = self.publicServerInput.text().strip()
@ -485,9 +523,15 @@ class DeviceMasterWidget(QMainWindow):
protocolManage = Globals.getValue('protocolManage')
mode = ''
info = ''
# 重置按钮状态
isServerMode = False
isClientMode = False
if protocolManage:
if hasattr(protocolManage, 'RpcServer') and protocolManage.RpcServer:
mode = '服务端模式'
isServerMode = True
try:
clients = protocolManage.RpcServer.getClientNames()
clientIpMap = protocolManage.RpcServer.getClientIpMap() if hasattr(protocolManage.RpcServer, 'getClientIpMap') else {}
@ -502,6 +546,7 @@ class DeviceMasterWidget(QMainWindow):
self.disconnectList.clear()
elif hasattr(protocolManage, 'RpcClient') and protocolManage.RpcClient:
mode = '客户端模式'
isClientMode = True
try:
clientName = protocolManage.RpcClient.clientName
serverInfo = protocolManage.RpcClient.rabbitHost
@ -510,6 +555,11 @@ class DeviceMasterWidget(QMainWindow):
except:
info = '客户端信息获取失败'
self.disconnectList.clear()
# 更新公网服务端按钮状态(主站模式)
self.publicConnectButton.setEnabled(not isServerMode)
self.publicDisconnectButton.setEnabled(isServerMode)
self.statusLabel.setText(f'服务器模式: {mode}')
self.infoLabel.setText(f'连接信息: {info}')
@ -697,11 +747,20 @@ class DeviceSlaveWidget(QMainWindow):
serverLayout.addWidget(self.publicServerInput)
publicLayout.addLayout(serverLayout)
# 公网客户端连接按钮
# 公网客户端控制按钮
clientButtonLayout = QHBoxLayout()
self.publicConnectButton = QPushButton('连接公网服务器')
self.publicConnectButton.clicked.connect(self.connectToPublicServer)
self.publicConnectButton.setObjectName('setButton')
publicLayout.addWidget(self.publicConnectButton)
clientButtonLayout.addWidget(self.publicConnectButton)
self.publicDisconnectButton = QPushButton('断开公网连接')
self.publicDisconnectButton.clicked.connect(self.disconnectFromPublicServer)
self.publicDisconnectButton.setObjectName('setButton')
self.publicDisconnectButton.setEnabled(False)
clientButtonLayout.addWidget(self.publicDisconnectButton)
publicLayout.addLayout(clientButtonLayout)
publicGroup.setLayout(publicLayout)
mainLayout.addWidget(publicGroup)
@ -744,19 +803,37 @@ class DeviceSlaveWidget(QMainWindow):
QMessageBox.warning(self, '警告', '请输入服务器地址')
return
# try:
try:
# 获取客户端名称
from protocol.RPC.RpcClient import RpcClient
clientName = RpcClient.getNextClientNameFromRabbitMQ(serverIp)
print(f"获取到客户端名称: {clientName}")
# 设置为客户端模式
Globals.getValue('protocolManage').closeServer()
Globals.getValue('protocolManage').setClentMode(clientName, rabbitmqHost=serverIp)
QMessageBox.information(self, '连接成功', f'已成功连接到公网服务器 {serverIp}\n客户端名称: {clientName}')
# except Exception as e:
# QMessageBox.critical(self, '连接失败', f'连接公网服务器失败: {str(e)}')
from protocol.RPC.RpcClient import RpcClient
clientName = RpcClient.getNextClientNameFromRabbitMQ(serverIp)
print(f"获取到客户端名称: {clientName}")
# 设置为客户端模式
Globals.getValue('protocolManage').closeServer()
Globals.getValue('protocolManage').setClentMode(clientName, rabbitmqHost=serverIp)
# 更新按钮状态
self.publicConnectButton.setEnabled(False)
self.publicDisconnectButton.setEnabled(True)
QMessageBox.information(self, '连接成功', f'已成功连接到公网服务器 {serverIp}\n客户端名称: {clientName}')
except Exception as e:
QMessageBox.critical(self, '连接失败', f'连接公网服务器失败: {str(e)}')
def disconnectFromPublicServer(self):
"""断开公网服务器连接"""
try:
# 关闭客户端模式
Globals.getValue('protocolManage').closeClient()
# 更新按钮状态
self.publicConnectButton.setEnabled(True)
self.publicDisconnectButton.setEnabled(False)
QMessageBox.information(self, '成功', '已断开公网服务器连接')
except Exception as e:
QMessageBox.critical(self, '失败', f'断开公网连接失败: {str(e)}')
def toggleUdpServer(self):
if self.server.udpRunning:
@ -788,9 +865,14 @@ class DeviceSlaveWidget(QMainWindow):
protocolManage = Globals.getValue('protocolManage')
mode = ''
info = ''
# 重置按钮状态
isClientMode = False
if protocolManage:
if hasattr(protocolManage, 'RpcClient') and protocolManage.RpcClient:
mode = '客户端模式'
isClientMode = True
try:
clientName = protocolManage.RpcClient.clientName
serverInfo = protocolManage.RpcClient.rabbitHost
@ -804,5 +886,10 @@ class DeviceSlaveWidget(QMainWindow):
else:
mode = ''
info = ''
# 更新公网客户端按钮状态(从站模式)
self.publicConnectButton.setEnabled(not isClientMode)
self.publicDisconnectButton.setEnabled(isClientMode)
self.statusLabel.setText(f'服务器模式: {mode}')
self.infoLabel.setText(f'连接信息: {info}')

@ -7,6 +7,7 @@ from PyQt5.QtWidgets import (QApplication, QGridLayout, QListWidget, QListWidget
QCheckBox, QFrame, QSpacerItem, QSizePolicy, QHeaderView, QToolButton)
from PyQt5.QtWebEngineWidgets import QWebEngineView, QWebEnginePage
from utils import Globals
import qtawesome
import matplotlib.pyplot as plt
import matplotlib.dates as mdates
@ -71,7 +72,7 @@ class TrendWidgets(QWidget):
self.variableListGroup = QGroupBox("变量列表")
self.variableListGroup.setObjectName("trendVariableListGroup")
layout = QVBoxLayout(self.variableListGroup)
layout.setSpacing(8)
layout.setSpacing(5)
layout.setContentsMargins(8, 8, 8, 8)
# 搜索框
@ -79,14 +80,14 @@ class TrendWidgets(QWidget):
self.searchInput.setObjectName("trendSearchInput")
self.searchInput.setPlaceholderText("搜索变量...")
self.searchInput.textChanged.connect(self.filterVarList)
layout.addWidget(self.searchInput)
layout.addWidget(self.searchInput, 1)
# 变量列表
self.varListWidget = QListWidget()
self.varListWidget.setObjectName("trendVarListWidget")
self.varListWidget.itemDoubleClicked.connect(self.showVarTrend)
self.varListWidget.itemSelectionChanged.connect(self.onVarSelected)
layout.addWidget(self.varListWidget)
layout.addWidget(self.varListWidget, 10)
# 时间选择区域
timeGroupBox = QGroupBox("时间范围")
@ -125,7 +126,7 @@ class TrendWidgets(QWidget):
timeEditLayout.addWidget(self.endTimeEdit)
timeLayout.addLayout(timeEditLayout)
layout.addWidget(timeGroupBox)
layout.addWidget(timeGroupBox, 3)
# 按钮区域
buttonGroupBox = QGroupBox("操作")
@ -140,6 +141,9 @@ class TrendWidgets(QWidget):
self.queryBtn = QToolButton()
self.queryBtn.setObjectName("trendQueryBtn")
self.queryBtn.setText("查询数据")
self.queryBtn.setIcon(qtawesome.icon('fa.search', color='#FFFFFF'))
self.queryBtn.setToolButtonStyle(Qt.ToolButtonTextBesideIcon)
self.queryBtn.setIconSize(QSize(16, 16))
self.queryBtn.setToolTip("按时间范围查询变量数据")
self.queryBtn.clicked.connect(self.onTimeRangeQuery)
firstRowLayout.addWidget(self.queryBtn)
@ -147,8 +151,12 @@ class TrendWidgets(QWidget):
self.refreshBtn = QToolButton()
self.refreshBtn.setObjectName("trendRefreshBtn")
self.refreshBtn.setText("刷新列表")
self.refreshBtn.setIcon(qtawesome.icon('fa.refresh', color='#FFFFFF'))
self.refreshBtn.setToolButtonStyle(Qt.ToolButtonTextBesideIcon)
self.refreshBtn.setIconSize(QSize(16, 16))
self.refreshBtn.setToolTip("刷新变量列表")
self.refreshBtn.clicked.connect(self.refreshVarList)
firstRowLayout.addWidget(self.refreshBtn)
firstRowLayout.addWidget(self.refreshBtn, 2)
buttonLayout.addLayout(firstRowLayout)
@ -159,6 +167,9 @@ class TrendWidgets(QWidget):
self.addToTrendBtn = QToolButton()
self.addToTrendBtn.setObjectName("trendAddBtn")
self.addToTrendBtn.setText("添加变量")
self.addToTrendBtn.setIcon(qtawesome.icon('fa.plus', color='#FFFFFF'))
self.addToTrendBtn.setToolButtonStyle(Qt.ToolButtonTextBesideIcon)
self.addToTrendBtn.setIconSize(QSize(16, 16))
self.addToTrendBtn.setToolTip("将选中的变量添加到趋势图")
self.addToTrendBtn.clicked.connect(self.addSelectedVarsToTrend)
secondRowLayout.addWidget(self.addToTrendBtn)
@ -166,6 +177,9 @@ class TrendWidgets(QWidget):
self.clearAllBtn = QToolButton()
self.clearAllBtn.setObjectName("trendClearBtn")
self.clearAllBtn.setText("清除所有")
self.clearAllBtn.setIcon(qtawesome.icon('fa.trash', color='#FFFFFF'))
self.clearAllBtn.setToolButtonStyle(Qt.ToolButtonTextBesideIcon)
self.clearAllBtn.setIconSize(QSize(16, 16))
self.clearAllBtn.setToolTip("清除趋势图中的所有变量")
self.clearAllBtn.clicked.connect(self.clearAllVars)
secondRowLayout.addWidget(self.clearAllBtn)

@ -39,6 +39,7 @@ class UserTableView(QTableView):
self.setHorizontalHeader(self.header)
self.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
self.verticalHeader().setDefaultSectionSize(50)
self.verticalHeader().hide()
self.header.setSectionResizeMode(0, QHeaderView.Fixed)

@ -11,6 +11,7 @@ from UI.VarManages.TCRTDModel import *
from utils import Globals
class AnalogModel(VarTableModel):
def __init__(self, header, data: list, table = None):
'''
@ -63,10 +64,11 @@ class AnalogModel(VarTableModel):
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 role == Qt.BackgroundRole:
# 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'):
# print(111111)
return QtGui.QColor('#00FF7F')
if role == Qt.TextColorRole:
return QtGui.QColor('#1A1A1A')

@ -40,7 +40,7 @@ class HartModel(VarTableModel):
if not QModelIndex.isValid():
print("行或者列有问题")
return QVariant()
if role == Qt.BackgroundColorRole:
if role == Qt.BackgroundRole:
if QModelIndex.row() % 2 == 0 and self.datas[QModelIndex.row()][1] not in Globals.getValue('forceVars'):
return QtGui.QColor('#EFEFEF')
if self.datas[QModelIndex.row()][3] in Globals.getValue('forceVars'):

@ -43,7 +43,7 @@ class HartSimulateModel(VarTableModel):
if not QModelIndex.isValid():
print("行或者列有问题")
return QVariant()
if role == Qt.BackgroundColorRole:
if role == Qt.BackgroundRole:
if QModelIndex.row() % 2 == 0 and self.datas[QModelIndex.row()][1] not in Globals.getValue('forceVars'):
return QtGui.QColor('#EFEFEF')
if self.datas[QModelIndex.row()][1] in Globals.getValue('forceVars'):
@ -83,6 +83,17 @@ class HartSimulateButtonDelegate(BaseButtonDelegate):
super(HartSimulateButtonDelegate, 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):
button1 = QPushButton(
qtawesome.icon('fa.play', color='#1fbb6f'),
@ -91,13 +102,15 @@ class HartSimulateButtonDelegate(BaseButtonDelegate):
clicked=self.start_action
)
button1.setIconSize(QSize(15, 15))
button1.setStyleSheet("border:none;")
button1.setToolTip("启动仿真")
button2 = QPushButton(
qtawesome.icon('fa.pencil', color='#4c8cf2'),
"",
self.parent(),
clicked=self.edit_action
)
button2.setToolTip("编辑变量")
button1.clicked.connect(self.start_action)
button2.clicked.connect(self.edit_action)
@ -114,13 +127,41 @@ class HartSimulateButtonDelegate(BaseButtonDelegate):
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.setContentsMargins(2, 0, 0, 2)
h_box_layout.addWidget(button2)
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;
}
QPushButton {
background-color: rgba(255, 255, 255, 180);
border: 1px solid #E5E7EB;
border-radius: 3px;
padding: 3px;
margin: 1px;
min-height: 20px;
max-height: 24px;
min-width: 24px;
max-width: 28px;
}
QPushButton:hover {
background-color: rgba(255, 255, 255, 255);
border-color: #2277EF;
}
""")
self.parent().setIndexWidget(
index,
widget

@ -98,9 +98,8 @@ class VarTableModel(QAbstractTableModel):
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 role == Qt.BackgroundRole:
# 只有强制变量显示绿色背景,其他都是白色
if self.datas[QModelIndex.row()][3] in Globals.getValue('forceVars'):
return QtGui.QColor('#00FF7F')
if role == Qt.TextColorRole:
@ -181,14 +180,19 @@ class VarTableModel(QAbstractTableModel):
def refreshComboBox(self):
#功能类型的index是5通讯类型index是10
for i in range(len(self.datas)):
cbRow = str('cb' + str(i) + str(5))
index = self.index(i, int(5))
delegate = self.table.itemDelegate(index)
delegate.paint(self.table, QStyleOptionViewItem(), index)
# 不需要调用paint方法因为委托会在需要时自动创建控件
# 直接尝试获取已存在的comboBox
try:
comboBox = getattr(delegate, cbRow)
comboBox = getattr(delegate, cbRow, None)
if comboBox is None:
# 如果comboBox不存在跳过这一行
continue
# print(comboBox, i, num, cbRow)
except Exception as e:
continue
@ -219,35 +223,31 @@ class ModbusButtonDelegate(BaseButtonDelegate):
return self.trendWidgetDict[varName]
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))
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.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
)
button1 = QPushButton()
button1.setIcon(qtawesome.icon('fa.play', color='#1fbb6f'))
button1.setToolTip("启动强制")
button2 = QPushButton()
button2.setIcon(qtawesome.icon('fa.pencil', color='#4c8cf2'))
button2.setToolTip("编辑变量")
button3 = QPushButton()
button3.setIcon(qtawesome.icon('fa.trash', color='#ff6d6d'))
button3.setToolTip("删除变量")
button4 = QPushButton()
button4.setIcon(qtawesome.icon('fa.line-chart', color='#393c4e'))
button4.setToolTip("趋势图")
comboBox = QComboBox(self.parent())
comboBox.addItem('int', 0)
@ -255,9 +255,8 @@ class ModbusButtonDelegate(BaseButtonDelegate):
comboBox.addItem('CDAB', 2)
comboBox.addItem('BADC', 3)
comboBox.addItem('DCBA', 4)
comboBox.setCurrentText(str(self.parent().model.datas[index.row()][index.column()]))
# comboBox.setMinimumWidth(30)
comboBox.setCurrentText(str(self.parent().model.datas[index.row()][index.column()]))
comboBox.setToolTip("字节序")
comboBox.currentIndexChanged.connect(self.indexChange)
button1.clicked.connect(self.start_action)
@ -269,7 +268,6 @@ class ModbusButtonDelegate(BaseButtonDelegate):
button2.isEdit = True
button3.editButton = button2
# button4.setStyleSheet("border:none;")
button1.index = [index.row(), index.column()]
button2.index = [index.row(), index.column()]
button3.index = [index.row(), index.column()]
@ -283,21 +281,27 @@ class ModbusButtonDelegate(BaseButtonDelegate):
else:
button2.isEdit = False
button2.setIcon(qtawesome.icon('fa.save', color='#1fbb6f'))
button2.setToolTip("保存变量")
self.parent().model.editableList.append(button2.index[0])
hboxLayout = QHBoxLayout()
hboxLayout.addWidget(comboBox)
hboxLayout.addWidget(button1)
hboxLayout.addWidget(button2)
hboxLayout.addWidget(button3)
hboxLayout.addWidget(button4)
hboxLayout.setContentsMargins(2, 0, 0, 2)
hboxLayout.setContentsMargins(2, 2, 2, 2)
hboxLayout.setAlignment(Qt.AlignCenter)
hboxLayout.setSpacing(3)
widget = QWidget()
widget.setLayout(hboxLayout)
self.parent().setIndexWidget(
index,
widget
)
# 所有下拉框使用统一样式
widget.setObjectName('ModbusButtonWidget')
comboBox.setObjectName('ModbusOrderBox')
self.parent().setIndexWidget(index, widget)
def indexChange(self):
sender = self.sender()
@ -482,6 +486,15 @@ class ModbusTypeBox(QItemDelegate):
super(ModbusTypeBox, 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))
paint_rect.moveTop(top + 2)
painter.fillRect(paint_rect, index.data(Qt.BackgroundRole))
if (index.column() == 5) and index.row() not in self.parent().model.editableList:
data = self.parent().model.datas[index.row()]
comBox = str('cb' + str(index.row()) + str(index.column()))
@ -495,35 +508,31 @@ class ModbusTypeBox(QItemDelegate):
comboBox.setCurrentIndex(self.parent().model.datas[index.row()][index.column()] - 1)
else:
comboBox.setCurrentIndex(0)
comboBox.currentIndexChanged.connect( self.indexChange)
comboBox.currentIndexChanged.connect(self.indexChange)
comboBox.setObjectName('ModbusTypeBox')
comboBox.setEditable(True)
comboBox.lineEdit().setAlignment(Qt.AlignCenter)
# comboBox.setMinimumWidth(200)
# comboBox.setEnabled(False)
hboxLayout = QHBoxLayout()
hboxLayout.addWidget(comboBox)
hboxLayout.setContentsMargins(0, 0, 0, 0)
# hboxLayout.setAlignment(Qt.AlignCenter)
hboxLayout.setContentsMargins(2, 2, 2, 2)
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; }")
# 所有下拉框使用统一样式
comboBox.setObjectName('ModbusTypeBox')
if str(data[index.column()]):
comboBox.setEnabled(False)
comboBox.setProperty('disabled', True)
else:
comboBox.setEnabled(True)
comboBox.setProperty('disabled', False)
widget = QWidget()
# widget.setStyleSheet("QWidget { background-color: transparent; }")
widget.setLayout(hboxLayout)
self.parent().setIndexWidget(
index,
widget
)
self.parent().setIndexWidget(index, widget)
self.parent().openPersistentEditor(index)
def indexChange(self):
@ -539,9 +548,17 @@ class ModbusVarModelBox(QItemDelegate):
super(ModbusVarModelBox, self).__init__(parent)
self.comBoxColumn = comBoxColumn
def paint(self, painter, option, index):
#本地值、模拟值、远程值 对应 0, 1, 2
# 首先绘制背景颜色,与其他委托保持一致
if index.data(Qt.BackgroundRole):
height = option.rect.height()
top = option.rect.top()
paint_rect = option.rect
paint_rect.setHeight(max(46, height - 4))
paint_rect.moveTop(top + 2)
painter.fillRect(paint_rect, index.data(Qt.BackgroundRole))
# 本地值、模拟值、远程值 对应 0, 1, 2
if (index.column() == self.comBoxColumn) and not self.parent().indexWidget(index):
data = self.parent().model.datas[index.row()]
comBox = str('cb' + str(index.row()) + str(index.column()))
@ -552,27 +569,19 @@ class ModbusVarModelBox(QItemDelegate):
comboBox.addItems(items)
comboBox.setCurrentText(str(self.parent().model.datas[index.row()][index.column()]))
comboBox.currentIndexChanged.connect( self.indexChange)
comboBox.setObjectName('ModbusTypeBox')
comboBox.currentIndexChanged.connect(self.indexChange)
comboBox.setObjectName('ModbusVarModelBox')
comboBox.setEditable(True)
comboBox.lineEdit().setAlignment(Qt.AlignCenter)
hboxLayout = QHBoxLayout()
hboxLayout.addWidget(comboBox)
hboxLayout.setContentsMargins(0, 0, 0, 0)
hboxLayout.setContentsMargins(2, 2, 2, 2)
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; }")
widget = QWidget()
# widget.setStyleSheet("QWidget { background-color: transparent; }")
widget.setLayout(hboxLayout)
self.parent().setIndexWidget(
index,
widget
)
self.parent().setIndexWidget(index, widget)
self.parent().openPersistentEditor(index)
def indexChange(self):

@ -65,7 +65,7 @@ class TcRtdModel(VarTableModel):
if not QModelIndex.isValid():
print("行或者列有问题")
return QVariant()
if role == Qt.BackgroundColorRole:
if role == Qt.BackgroundRole:
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'):
@ -114,6 +114,17 @@ class TcRtdButtonDelegate(BaseButtonDelegate):
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'),
@ -122,13 +133,15 @@ class TcRtdButtonDelegate(BaseButtonDelegate):
clicked=self.start_action
)
button1.setIconSize(QSize(15, 15))
button1.setStyleSheet("border:none;")
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'),
@ -136,7 +149,7 @@ class TcRtdButtonDelegate(BaseButtonDelegate):
self.parent(),
clicked=self.trend_action
)
button3.setToolTip("趋势图")
button1.clicked.connect(self.start_action)
button2.clicked.connect(self.edit_action)
@ -149,7 +162,6 @@ class TcRtdButtonDelegate(BaseButtonDelegate):
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 != '':
@ -157,15 +169,42 @@ class TcRtdButtonDelegate(BaseButtonDelegate):
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, 0, 0, 2)
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;
}
QPushButton {
background-color: rgba(255, 255, 255, 180);
border: 1px solid #E5E7EB;
border-radius: 3px;
padding: 3px;
margin: 1px;
min-height: 20px;
max-height: 24px;
min-width: 24px;
max-width: 28px;
}
QPushButton:hover {
background-color: rgba(255, 255, 255, 255);
border-color: #2277EF;
}
""")
self.parent().setIndexWidget(
index,
widget
@ -333,10 +372,10 @@ class TcRtdTypeDelegate(TcRtdButtonDelegate):
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 }")
# if row % 2 == 0:
# comboBox.setStyleSheet("QComboBox { background-color: #EFEFEF }")
# else:
# comboBox.setStyleSheet("QComboBox { background-color: #e9e7e3 }")
self.parent().setIndexWidget(
index,
widget

@ -16,15 +16,38 @@ from .RpcVarModel import RpcVarModel, RpcVarButtonDelegate
from model.ProjectModel.VarManage import *
from UI.VarManages.Thread import RTDTCThread, AnalogThread, HartSimulateThread
# from UI.ProjectManages.ProjectModel import BackgroundDelegate
from utils import Globals
class BackgroundDelegate(QtWidgets.QStyledItemDelegate):
def __init__(self, *args):
super(BackgroundDelegate, self).__init__(*args)
self.setObjectName('item')
def sizeHint(self, option, index):
"""设置项目的尺寸提示,确保足够的高度"""
size = super().sizeHint(option, index)
size.setHeight(max(46, size.height())) # 最小高度60px
return size
def paint(self, painter, option, index):
# 确保绘制区域有足够的高度
if index.data(QtCore.Qt.BackgroundRole):
height = option.rect.height()
top = option.rect.top()
# 减少高度调整,保持更多的绘制区域
option.rect.setHeight(max(46, height - 4)) # 最小保持56px高度
option.rect.moveTop(top + 2)
painter.fillRect(option.rect, index.data(QtCore.Qt.BackgroundRole))
super().paint(painter, option, index)
class CheckBoxHeader(QHeaderView):
checkClicked = pyqtSignal(bool)
sectionClicked = pyqtSignal(int)
_x_offset = 4
_y_offset = 0
_x_offset = 15
_y_offset = 15
_width = 25
_height = 25
@ -40,7 +63,7 @@ class CheckBoxHeader(QHeaderView):
if self.changeY:
self._y_offset = int((rect.height()-self._width)/2.) + 4
self._y_offset = int((rect.height()-self._width)/2.)
else:
self._y_offset = int((rect.height()-self._width)/2.)
@ -83,14 +106,14 @@ class VarTableView(QTableView):
self.setItemDelegateForColumn(11, ModbusButtonDelegate(self))
self.setItemDelegateForColumn(5, ModbusTypeBox(self))
self.setItemDelegateForColumn(10, ModbusVarModelBox(self))
self.model = VarTableModel(['ID', '强制值', '当前值', '变量名', '变量描述', '变量类型',
self.model = VarTableModel([' ID', '强制值', '当前值', '变量名', '变量描述', '变量类型',
'从站地址', '寄存器地址', '工程量下限', '工程量上限', '值类型', '操作'],
[], modbusType = self.modbusType, table = self)
def setupUi(self):
self.setShowGrid(True)
self.setAlternatingRowColors(True)
self.setShowGrid(False)
# self.setAlternatingRowColors(True)
self.setSelectionBehavior(QAbstractItemView.SelectRows)
@ -107,9 +130,15 @@ class VarTableView(QTableView):
self.header.setSectionResizeMode(0, QHeaderView.Fixed)
self.header.resizeSection(0, 70)
# 设置行高
self.verticalHeader().setDefaultSectionSize(50)
self.verticalHeader().setMinimumSectionSize(50)
self.verticalHeader().hide()
def setupColumnWidths(self):
self.setCustomColumnWidths([0.9, 0.9, 1, 1, 1, 1.2, 1, 1, 1, 1, 1, 1.2])
self.setCustomColumnWidths([0.9, 0.9, 0.9, 1, 1, 1.4, 1, 1, 1, 1, 0.9, 1.3])
def setCustomColumnWidths(self, ratios):
# 计算总比例
@ -130,6 +159,8 @@ class HartTableView(VarTableView):
super(HartTableView, self).__init__(parent)
def setHeader(self):
self.delegate = BackgroundDelegate(self)
self.setItemDelegate(self.delegate)
self.setItemDelegateForColumn(9, HartButtonDelegate(self))
self.setItemDelegateForColumn(8, HartVarModelBox(self))
self.model = HartModel([' ID', '仪器名', '描述', '电流值', '参数1', '参数2','参数3', '参数4', '值类型','操作'], [], table=self)
@ -139,7 +170,10 @@ class HartTableView(VarTableView):
class TcRtdTableView(VarTableView):
def __init__(self, parent=None):
super(TcRtdTableView, self).__init__(parent)
self.delegate = BackgroundDelegate(self)
self.setItemDelegate(self.delegate)
self.setItemDelegateForColumn(6, TcRtdTypeDelegate(self))
self.valueList = [0] * 16
self.mvList = [0] * 16
# self.workThread = RTDTCThread(self)
@ -150,7 +184,7 @@ class TcRtdTableView(VarTableView):
def setHeader(self):
self.setItemDelegateForColumn(11, TcRtdButtonDelegate(self))
self.setItemDelegateForColumn(10, TcRtdVarModelBox(self))
self.model = TcRtdModel(['ID', '强制值', '当前值', '变量名', '通道序号', '变量描述', '变量类型', '工程量下限', '工程量上限', '补偿值', '值类型','操作'], [], table=self)
self.model = TcRtdModel([' ID', '强制值', '当前值', '变量名', '通道序号', '变量描述', '变量类型', '工程量下限', '工程量上限', '补偿值', '值类型','操作'], [], table=self)
class AnalogTableView(VarTableView):
def __init__(self, parent=None):
@ -159,6 +193,8 @@ class AnalogTableView(VarTableView):
# self.realList = [0] * 8 + [0] * 8 + [0] * 16 + [0] * 8 + [0] * 8 + [0] * 8
# self.workThread = AnalogThread(self)
# Globals.setValue('AnalogThread', self.workThread)
self.delegate = BackgroundDelegate(self)
self.setItemDelegate(self.delegate)
self.setupColumnWidths()
def setupColumnWidths(self):
@ -167,12 +203,14 @@ class AnalogTableView(VarTableView):
def setHeader(self):
self.setItemDelegateForColumn(10, AnalogButtonDelegate(self))
self.setItemDelegateForColumn(9, AnalogVarModelBox(self))
self.model = AnalogModel(['ID', '强制值', '当前值', '变量名', '通道序号', '变量描述', '变量类型', '工程量下限', '工程量上限', '值类型', '操作'], [], table=self)
self.model = AnalogModel([' ID', '强制值', '当前值', '变量名', '通道序号', '变量描述', '变量类型', '工程量下限', '工程量上限', '值类型', '操作'], [], table=self)
class HartSimulateTableView(VarTableView):
def __init__(self, parent=None):
super(HartSimulateTableView, self).__init__(parent)
self.delegate = BackgroundDelegate(self)
self.setItemDelegate(self.delegate)
self.valueList = []
# self.realList = [0] * 8 + [0] * 8 + [0] * 8
self.workThread = HartSimulateThread(self)
@ -189,8 +227,10 @@ class HartSimulateTableView(VarTableView):
class RpcVarTableView(QTableView):
def __init__(self, parent=None):
super(RpcVarTableView, self).__init__(parent)
self.setShowGrid(True)
self.setAlternatingRowColors(True)
self.delegate = BackgroundDelegate(self)
self.setItemDelegate(self.delegate)
self.setShowGrid(False)
# self.setAlternatingRowColors(True)
self.setSelectionBehavior(QAbstractItemView.SelectRows)
self.setItemDelegateForColumn(7, RpcVarButtonDelegate(self))
self.model = RpcVarModel(['客户端', '变量名', '类型', '下限', '上限', '当前值', '操作'], self)

@ -365,7 +365,7 @@ class HartWidgets(VarWidgets):
self.startProtocolBtn.clicked.connect(self.startProtocol)
self.varView = HartTableView()
self.varView.setObjectName('HartTable')
self.varView.setObjectName('varView')
self.proxy = QtCore.QSortFilterProxyModel(self)
self.proxy.setSourceModel(self.varView.model)
@ -417,7 +417,7 @@ class TcRtdWidgets(VarWidgets):
self.clearBtn.clicked.connect(self.clearColour)
self.varView = TcRtdTableView()
self.varView.setObjectName('TcRtdTable')
self.varView.setObjectName('varView')
self.proxy = QtCore.QSortFilterProxyModel(self)
self.proxy.setSourceModel(self.varView.model)
@ -510,7 +510,7 @@ class AnalogWidgets(VarWidgets):
self.clearBtn.clicked.connect(self.clearColour)
self.varView = AnalogTableView()
self.varView.setObjectName('AnalogTable')
self.varView.setObjectName('varView')
self.proxy = QtCore.QSortFilterProxyModel(self)
self.proxy.setSourceModel(self.varView.model)
@ -589,7 +589,7 @@ class HartSimulateWidgets(VarWidgets):
self.startProtocolBtn.clicked.connect(self.startProtocol)
self.varView = HartSimulateTableView()
self.varView.setObjectName('HartSimulateTable')
self.varView.setObjectName('varView')
self.proxy = QtCore.QSortFilterProxyModel(self)
self.proxy.setSourceModel(self.varView.model)

@ -548,7 +548,8 @@ class RpcServer:
if offlineClients:
print(f"本次检查移除了 {len(offlineClients)} 个离线客户端")
else:
print("所有客户端状态正常")
# print("所有客户端状态正常")
pass
except Exception as e:
print(f"自动检测客户端异常: {e}")

Loading…
Cancel
Save