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.

448 lines
18 KiB
Python

7 months ago
import sys
from PyQt5 import QtWidgets
from PyQt5.QtCore import Qt
from PyQt5.Qt import *
from PyQt5.QtWidgets import QApplication, QMainWindow, QStackedWidget, QMessageBox, QStackedWidget, QWidget, QTabWidget
from ctypes import POINTER, cast
from ctypes.wintypes import MSG
from win32 import win32api, win32gui
from win32.lib import win32con
from windoweffect import WindowEffect, MINMAXINFO, NCCALCSIZE_PARAMS
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
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
6 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
7 months ago
class CommonHelper:
def __init__(self):
pass
@staticmethod
def readQss(style):
with open(style,"r") as f:
return f.read()
class MainWindow(QMainWindow):
BORDER_WIDTH = 5 #设圆角
def __init__(self):
super(MainWindow, self).__init__()
6 months ago
InitParameterDB()
7 months ago
self.setupUi()
# self.setStyleSheet(CommonHelper.readQss('static/main.qss'))
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)
#初始化接口
self.windowEffect = WindowEffect()
# 添加DWM阴影效果
self.windowEffect.addWindowAnimation(self.winId())
self.windowEffect.addShadowEffect(self.winId())
# 解决报错
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()
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()
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模拟')
6 months ago
self.varManageTabWidget.addTab(self.profibusWidget,'PROFIBUS')
7 months ago
4 months ago
#添加导入变量按钮
self.importVarButton = QPushButton(QIcon(':/static/import.png'), '导入变量')
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)
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())
7 months ago
self.setCentralWidget(self.centralwidget)
self.setWindowOpacity(0.995) # 设置窗口透明度
self.topWidget = MainTop(self)
self.topWidget.setObjectName('topWidget')
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)
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()
self.exButtonClicked(2)
4 months ago
def initProcedureDB(self):
if Globals.getValue('currentPro') == -1:
return
self.procedureManagerWidget.initDB()
self.procedureManagerWidget.initUI()
self.exButtonClicked(5)
7 months ago
4 months ago
def loadVar(self):
pass
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()
def nativeEvent(self, eventType, message):
""" 接受windows发送的信息 """
msg = MSG.from_address(message.__int__())
if msg.message == win32con.WM_NCHITTEST:
# 解决 issue #2 and issue #7
r = self.devicePixelRatioF()
xPos = (win32api.LOWORD(msg.lParam) -
self.frameGeometry().x()*r) % 65536
yPos = win32api.HIWORD(msg.lParam) - self.frameGeometry().y()*r
w, h = self.width()*r, self.height()*r
lx = xPos < self.BORDER_WIDTH
rx = xPos + 9 > w - self.BORDER_WIDTH
ty = yPos < self.BORDER_WIDTH
by = yPos > h - self.BORDER_WIDTH
if lx and ty:
return True, win32con.HTTOPLEFT
elif rx and by:
return True, win32con.HTBOTTOMRIGHT
elif rx and ty:
return True, win32con.HTTOPRIGHT
elif lx and by:
return True, win32con.HTBOTTOMLEFT
elif ty:
return True, win32con.HTTOP
elif by:
return True, win32con.HTBOTTOM
elif lx:
return True, win32con.HTLEFT
elif rx:
return True, win32con.HTRIGHT
elif msg.message == win32con.WM_NCCALCSIZE:
if self.__isWindowMaximized(msg.hWnd):
self.__monitorNCCALCSIZE(msg)
return True, 0
elif msg.message == win32con.WM_GETMINMAXINFO:
if self.__isWindowMaximized(msg.hWnd):
window_rect = win32gui.GetWindowRect(msg.hWnd)
if not window_rect:
return False, 0
# get the monitor handle
monitor = win32api.MonitorFromRect(window_rect)
if not monitor:
return False, 0
# get the monitor info
__monitorInfo = win32api.GetMonitorInfo(monitor)
monitor_rect = __monitorInfo['Monitor']
work_area = __monitorInfo['Work']
# convert lParam to MINMAXINFO pointer
info = cast(msg.lParam, POINTER(MINMAXINFO)).contents
# adjust the size of window
info.ptMaxSize.x = work_area[2] - work_area[0]
info.ptMaxSize.y = work_area[3] - work_area[1]
info.ptMaxTrackSize.x = info.ptMaxSize.x
info.ptMaxTrackSize.y = info.ptMaxSize.y
# modify the upper left coordinate
info.ptMaxPosition.x = abs(window_rect[0] - monitor_rect[0])
info.ptMaxPosition.y = abs(window_rect[1] - monitor_rect[1])
return True, 1
return QWidget.nativeEvent(self, eventType, message)
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:
Client.close()
except:
pass
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'))
# print(QtWidgets.QStyleFactory.keys())
ex = MainWindow()
ex.show()
sys.exit(app.exec_())