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.

450 lines
18 KiB
Python

from csv import excel
7 months ago
import sys
import pandas as pd
7 months ago
from PyQt5 import QtWidgets
from PyQt5.QtCore import Qt
from PyQt5.Qt import *
3 months ago
from PyQt5.QtWidgets import QApplication, QMainWindow, QStackedWidget, QMessageBox, QStackedWidget, QWidget, QTabWidget, QFileDialog, QPushButton, QGraphicsDropShadowEffect
4 months ago
from PyQt5.QtGui import QIcon
from PyQt5.QtCore import QSize
3 months ago
from PyQt5.QtGui import QPainter, QBrush, QColor
from PyQt5.QtCore import QEvent
7 months ago
from ctypes import POINTER, cast
from ctypes.wintypes import MSG
from win32 import win32api, win32gui
from win32.lib import win32con
from model.ProjectModel.VarManage import GlobalVarManager
7 months ago
from UI.Main.MainLeft import MainLeft
from UI.Main.MainTop import MainTop
from ..ProjectManages.ProjectWidget import ProjectWidgets
from ..VarManages.VarWidget import VarWidgets, HartWidgets, TcRtdWidgets, AnalogWidgets, HartSimulateWidgets
4 months ago
from UI.VarManages.VarTable import RpcVarTableView
7 months ago
from ..UserManage.UserWidget import UserWidgets
from ..TrendManage.TrendWidget import TrendWidgets
from ..Setting.Setting import SettingWidget
from model.ClientModel.Client import Client
from utils import Globals
5 months ago
from utils.DBModels.InitParameterDB import InitParameterDB
5 months ago
from UI.ProfibusWidgets.ProfibusWindow import ProfibusWidgets
4 months ago
from UI.ProcedureManager.ProcedureManager import ProcedureManager
from UI.ControlManage.ControlWidget import getControlWidget
7 months ago
class CommonHelper:
def __init__(self):
pass
@staticmethod
def readQss(style):
with open(style, "r", encoding='utf-8') as f:
7 months ago
return f.read()
class MainWindow(QMainWindow):
BORDER_WIDTH = 5 #设圆角
def __init__(self):
super(MainWindow, self).__init__()
5 months ago
InitParameterDB()
7 months ago
self.setupUi()
# self.setStyleSheet(CommonHelper.readQss('Static/main.qss'))
7 months ago
self.setWindowFlags(Qt.FramelessWindowHint|Qt.WindowSystemMenuHint)
self.SHADOW_WIDTH = 0 #边框距离
self.isLeftPressDown = False #鼠标左键是否按下
self.dragPosition = 0 #拖动时坐标
self.padding = 4
self.Numbers = self.enum(UP=0, DOWN=1, LEFT=2, RIGHT=3, LEFTTOP=4, LEFTBOTTOM=5, RIGHTBOTTOM=6, RIGHTTOP=7, NONE=8) #枚举参数
self.setMinimumHeight(900) #窗体最小高度
self.setMinimumWidth(1600) #窗体最小宽度
self.dir = self.Numbers.NONE #初始鼠标状态
#开启鼠标追踪
self.setMouseTracking(True)
self.centralwidget.setMouseTracking(True)
self.leftWidget.setMouseTracking(True)
self.rightWidget.setMouseTracking(True)
self.topWidget.setMouseTracking(True)
#初始化接口
3 months ago
# self.windowEffect = WindowEffect()
# # 添加DWM阴影效果
# self.windowEffect.addWindowAnimation(self.winId())
# self.windowEffect.addShadowEffect(self.winId())
7 months ago
# 解决报错
self.windowHandle().screenChanged.connect(self.__onScreenChanged)
def setupUi(self):
self.showMaximized()
self.centralwidget = QtWidgets.QWidget(self)
self.centralwidget.setObjectName("centralwidget")
self.leftWidget = MainLeft()
self.leftWidget.setObjectName("leftWidget")
self.projectWidget = ProjectWidgets()
self.userWidget = UserWidgets()
4 months ago
self.procedureManagerWidget = ProcedureManager()
self.controlWidget = getControlWidget()
7 months ago
self.ModbusTcpMasterWidget = VarWidgets('ModbusTcpMaster')
self.ModbusTcpSlaveWidget = VarWidgets('ModbusTcpSlave')
self.ModbusRtuMasterWidget = VarWidgets('ModbusRtuMaster')
self.ModbusRtuSlaveWidget = VarWidgets('ModbusRtuSlave')
modbusWidgetList = [self.ModbusTcpMasterWidget, self.ModbusTcpSlaveWidget, self.ModbusRtuMasterWidget, self.ModbusRtuSlaveWidget]
modbusNameList = ['MODBUSTCP主站', 'MODBUSTCP从站', 'MODBUSRTU主站', 'MODBUSRTU从站',]
5 months ago
self.profibusWidget = ProfibusWidgets()
7 months ago
self.trendWidget = TrendWidgets()
self.SettingWidget = SettingWidget()
self.hartWidget = HartWidgets()
self.tcrtdWidget = TcRtdWidgets()
self.analogWidget = AnalogWidgets()
self.hartsimulateWidget = HartSimulateWidgets()
4 months ago
self.rpcVarTableWidget = RpcVarTableView()
7 months ago
self.userWidget.setObjectName('userWidget')
self.projectWidget.setObjectName('projectWidget')
self.trendWidget.setObjectName('trendWidget')
7 months ago
# self.ModBusWidget.setObjectName('varWidget')
7 months ago
self.analogWidget.setObjectName('analogWidget')
self.hartsimulateWidget.setObjectName('hartsimulateWidget')
4 months ago
7 months ago
self.varManageTabWidget = QTabWidget()
6 months ago
self.varManageTabWidget.setObjectName("varManageTabWidget")
5 months ago
self.varManageTabWidget.tabBar().setObjectName('varManageTabBar')
7 months ago
self.rightWidget = QStackedWidget()
self.rightWidget.setObjectName("rightWidget")
self.rightWidget.addWidget(self.projectWidget)
7 months ago
for widget, name in zip(modbusWidgetList, modbusNameList):
widget.setObjectName('varWidget')
self.varManageTabWidget.addTab(widget, name)
self.varManageTabWidget.addTab(self.analogWidget,'IO')
7 months ago
self.varManageTabWidget.addTab(self.tcrtdWidget,'TCRTD')
self.varManageTabWidget.addTab(self.hartWidget,'HART读取')
self.varManageTabWidget.addTab(self.hartsimulateWidget,'HART模拟')
5 months ago
self.varManageTabWidget.addTab(self.profibusWidget,'PROFIBUS')
4 months ago
self.varManageTabWidget.addTab(self.rpcVarTableWidget, '远程通讯')
7 months ago
4 months ago
#添加导入变量按钮
self.importVarButton = QPushButton(QIcon('./Static/import.png'), '导入变量')
4 months ago
self.importVarButton.setObjectName('importBtn')
self.importVarButton.setIconSize(QSize(22, 22))
self.importVarButton.setFlat(True)
self.importVarButton.clicked.connect(self.loadVar)
self.varManageTabWidget.setCornerWidget(self.importVarButton)
7 months ago
self.rightWidget.addWidget(self.varManageTabWidget)
self.rightWidget.addWidget(self.trendWidget)
self.rightWidget.addWidget(self.userWidget)
self.rightWidget.addWidget(self.SettingWidget)
4 months ago
self.rightWidget.addWidget(self.procedureManagerWidget)
self.rightWidget.addWidget(self.controlWidget)
7 months ago
self.rightWidget.widget(1)
self.leftWidget.createProject.clicked.connect(lambda: self.exButtonClicked(0))
self.leftWidget.varMag.clicked.connect(self.varShow)
self.leftWidget.trendMag.clicked.connect(self.reFreshTrendWidget)
self.leftWidget.userMag.clicked.connect(lambda: self.exButtonClicked(3))
self.leftWidget.protocolMag.clicked.connect(self.showSetting)
4 months ago
self.leftWidget.procedureMag.clicked.connect(lambda: self.initProcedureDB())
self.leftWidget.controlMag.clicked.connect(lambda: self.showControlSystem())
7 months ago
self.setCentralWidget(self.centralwidget)
self.setWindowOpacity(0.995) # 设置窗口透明度
self.topWidget = MainTop(self)
self.topWidget.setObjectName('topWidget')
# 初始化搜索框状态在topWidget创建后
self.topWidget.updateSearchPlaceholder()
7 months ago
self.verticalLayout = QtWidgets.QVBoxLayout(self.centralwidget)
self.horizontalLayout = QtWidgets.QHBoxLayout()
self.horizontalLayout.setObjectName("horizontalLayout")
self.verticalLayout.setObjectName("verticalLayout")
self.horizontalLayout.addWidget(self.leftWidget)
self.horizontalLayout.addWidget(self.rightWidget)
self.horizontalLayout.setStretch(0, 1)
self.horizontalLayout.setStretch(1, 7)
self.horizontalLayout.setContentsMargins(0, 0, 0, 0)
self.horizontalLayout.setSpacing(5)
self.verticalLayout.setContentsMargins(0, 0, 0, 0)
self.verticalLayout.addWidget(self.topWidget)
self.verticalLayout.addLayout(self.horizontalLayout)
self.verticalLayout.setStretch(0, 1)
self.verticalLayout.setStretch(1, 18)
self.verticalLayout.setSpacing(0)
# self.setAttribute(Qt.WA_TranslucentBackground) # 设置窗口背景透明
self.setWindowFlag(Qt.FramelessWindowHint)
3 months ago
# 添加阴影效果接近Windows原生
# 添加圆角QSS
# self.centralwidget.setStyleSheet("")
7 months ago
def exButtonClicked(self, index):
4 months ago
if Globals.getValue('currentPro') == -1 and index not in [0, 3]:
7 months ago
return -1
4 months ago
print(index, Globals.getValue('currentPro'))
7 months ago
self.rightWidget.setCurrentIndex(index)
def showSetting(self):
4 months ago
if Globals.getValue('currentPro') == -1:
7 months ago
return
self.SettingWidget.setupUI()
self.rightWidget.setCurrentIndex(4)
5 months ago
7 months ago
def varShow(self):
self.exButtonClicked(1)
Globals.setValue('SearchWidget', 1)
5 months ago
7 months ago
def reFreshTrendWidget(self):
4 months ago
if Globals.getValue('currentPro') == -1:
7 months ago
return
# self.trendWidget.getMems()
7 months ago
self.exButtonClicked(2)
4 months ago
def initProcedureDB(self):
if Globals.getValue('currentPro') == -1:
return
self.procedureManagerWidget.initDB()
self.procedureManagerWidget.initUI()
self.exButtonClicked(5)
def showControlSystem(self):
"""显示控制系统界面"""
if Globals.getValue('currentPro') == -1:
return
# 重新加载控制系统(确保规则正确加载)
self.controlWidget.reloadControlSystem()
self.exButtonClicked(6)
7 months ago
4 months ago
def loadVar(self):
file_path, _ = QFileDialog.getOpenFileName(self, '选择Excel文件', '', 'Excel Files (*.xlsx *.xls)')
if not file_path:
return
excelData = pd.read_excel(file_path, sheet_name=None)
allVarNames = []
for sheet_name, data in excelData.items():
if '变量名' in data.columns:
# 确保所有变量名转换为字符串
allVarNames.extend(data['变量名'].astype(str).tolist())
if len(allVarNames) != len(set(allVarNames)):
# 确保重复名称列表中的元素都是字符串
repeated_names = [str(name) for name in set(allVarNames) if allVarNames.count(name) > 1]
QMessageBox.warning(self, '警告', f'发现重复的变量名: {", ".join(repeated_names)}')
return
4 months ago
allErrInfo = []
for sheet_name, data in excelData.items():
if '变量名' in data.columns:
4 months ago
importInfo = GlobalVarManager.importVar(sheet_name, data)
allErrInfo.append(importInfo)
if allErrInfo:
# 过滤掉空字符串
allErrInfo = [info for info in allErrInfo if info]
if not allErrInfo:
QMessageBox.information(self, '导入信息', '所有变量导入成功')
else:
errorMessages = '\n'.join(allErrInfo)
QMessageBox.information(self, '导入信息', errorMessages)
4 months ago
7 months ago
def enum(self,**enums):
return type('Enum', (), enums)
def region(self,cursorGlobalPoint):
#获取窗体在屏幕上的位置区域tl为topleft点rb为rightbottom点
rect = self.rect()
tl = self.mapToGlobal(rect.topLeft())
rb = self.mapToGlobal(rect.bottomRight())
x = cursorGlobalPoint.x()
y = cursorGlobalPoint.y()
if(tl.x() + self.padding >= x and tl.x() <= x and tl.y() + self.padding >= y and tl.y() <= y):
#左上角
self.dir = self.Numbers.LEFTTOP
self.setCursor(QCursor(Qt.SizeFDiagCursor)) #设置鼠标形状
elif(x >= rb.x() - self.padding and x <= rb.x() and y >= rb.y() - self.padding and y <= rb.y()):
#右下角
self.dir = self.Numbers.RIGHTBOTTOM
self.setCursor(QCursor(Qt.SizeFDiagCursor))
elif(x <= tl.x() + self.padding and x >= tl.x() and y >= rb.y() - self.padding and y <= rb.y()):
#左下角
self.dir = self.Numbers.LEFTBOTTOM
self.setCursor(QCursor(Qt.SizeBDiagCursor))
elif(x <= rb.x() and x >= rb.x() - self.padding and y >= tl.y() and y <= tl.y() + self.padding):
#右上角
self.dir = self.Numbers.RIGHTTOP
self.setCursor(QCursor(Qt.SizeBDiagCursor))
elif(x <= tl.x() + self.padding and x >= tl.x()):
#左边
self.dir = self.Numbers.LEFT
self.setCursor(QCursor(Qt.SizeHorCursor))
elif( x <= rb.x() and x >= rb.x() - self.padding):
#右边
self.dir = self.Numbers.RIGHT
self.setCursor(QCursor(Qt.SizeHorCursor))
elif(y >= tl.y() and y <= tl.y() + self.padding):
#上边
self.dir = self.Numbers.UP
self.setCursor(QCursor(Qt.SizeVerCursor))
elif(y <= rb.y() and y >= rb.y() - self.padding):
#下边
self.dir = self.Numbers.DOWN
self.setCursor(QCursor(Qt.SizeVerCursor))
else:
#默认
self.dir = self.Numbers.NONE
self.setCursor(QCursor(Qt.ArrowCursor))
def mouseReleaseEvent(self,event):
if(event.button() == Qt.LeftButton):
self.isLeftPressDown = False
if(self.dir != self.Numbers.NONE):
self.releaseMouse()
self.setCursor(QCursor(Qt.ArrowCursor))
def mousePressEvent(self,event):
if(event.button()==Qt.LeftButton):
self.isLeftPressDown=True
if(self.dir != self.Numbers.NONE):
self.mouseGrabber()
else:
self.dragPosition = event.globalPos() - self.frameGeometry().topLeft()
def mouseMoveEvent(self,event):
gloPoint = event.globalPos()
rect = self.rect()
tl = self.mapToGlobal(rect.topLeft())
rb = self.mapToGlobal(rect.bottomRight())
if(not self.isLeftPressDown):
self.region(gloPoint)
else:
if(self.dir != self.Numbers.NONE):
rmove=QRect(tl, rb)
if(self.dir==self.Numbers.LEFT):
if(rb.x() - gloPoint.x() <= self.minimumWidth()):
rmove.setX(tl.x())
else:
rmove.setX(gloPoint.x())
elif(self.dir==self.Numbers.RIGHT):
rmove.setWidth(gloPoint.x() - tl.x())
elif(self.dir==self.Numbers.UP):
if(rb.y() - gloPoint.y() <= self.minimumHeight()):
rmove.setY(tl.y())
else:
rmove.setY(gloPoint.y())
elif(self.dir==self.Numbers.DOWN):
rmove.setHeight(gloPoint.y() - tl.y())
elif(self.dir==self.Numbers.LEFTTOP):
if(rb.x() - gloPoint.x() <= self.minimumWidth()):
rmove.setX(tl.x())
else:
rmove.setX(gloPoint.x())
if(rb.y() - gloPoint.y() <= self.minimumHeight()):
rmove.setY(tl.y())
else:
rmove.setY(gloPoint.y())
elif(self.dir==self.Numbers.RIGHTTOP):
rmove.setWidth(gloPoint.x() - tl.x())
rmove.setY(gloPoint.y())
elif(self.dir==self.Numbers.LEFTBOTTOM):
rmove.setX(gloPoint.x())
rmove.setHeight(gloPoint.y() - tl.y())
elif(self.dir==self.Numbers.RIGHTBOTTOM):
rmove.setWidth(gloPoint.x() - tl.x())
rmove.setHeight(gloPoint.y() - tl.y())
else:
pass
self.setGeometry(rmove)
else:
self.move(event.globalPos() - self.dragPosition)
event.accept()
3 months ago
3 months ago
7 months ago
def __isWindowMaximized(self, hWnd) -> bool:
""" Determine whether the window is maximized """
# GetWindowPlacement() returns the display state of the window and the restored,
# maximized and minimized window position. The return value is tuple
windowPlacement = win32gui.GetWindowPlacement(hWnd)
if not windowPlacement:
return False
return windowPlacement[1] == win32con.SW_MAXIMIZE
def __monitorNCCALCSIZE(self, msg: MSG):
""" 调整窗口大小 """
monitor = win32api.MonitorFromWindow(msg.hWnd)
# If the display information is not saved, return directly
if monitor is None and not self.__monitorInfo:
return
elif monitor is not None:
self.__monitorInfo = win32api.GetMonitorInfo(monitor)
# adjust the size of window
params = cast(msg.lParam, POINTER(NCCALCSIZE_PARAMS)).contents
params.rgrc[0].left = self.__monitorInfo['Work'][0]
params.rgrc[0].top = self.__monitorInfo['Work'][1]
params.rgrc[0].right = self.__monitorInfo['Work'][2]
params.rgrc[0].bottom = self.__monitorInfo['Work'][3]
def __onScreenChanged(self):
hWnd = int(self.windowHandle().winId())
win32gui.SetWindowPos(hWnd, None, 0, 0, 0, 0, win32con.SWP_NOMOVE |
win32con.SWP_NOSIZE | win32con.SWP_FRAMECHANGED)
def closeEvent(self, event):
reply = QMessageBox.question(self,
'Quit',
"是否要退出程序?",
QMessageBox.Yes | QMessageBox.No,
QMessageBox.No)
if reply == QMessageBox.Yes:
try:
# 保存控制系统配置
if hasattr(self, 'controlWidget') and self.controlWidget:
self.controlWidget.controlManager.shutdown()
7 months ago
Client.close()
except Exception as e:
print(f"关闭程序时出错: {e}")
7 months ago
event.accept()
else:
event.ignore()
if __name__ == '__main__':
app = QApplication(sys.argv)
app.setStyle(QtWidgets.QStyleFactory.create('Fusion'))
app.setStyleSheet(CommonHelper.readQss('Static/main.qss'))
7 months ago
# print(QtWidgets.QStyleFactory.keys())
ex = MainWindow()
ex.show()
sys.exit(app.exec_())