import sys import time # sys.setrecursionlimit(10000) from PyQt5 import QtCore, QtGui, QtWidgets from PyQt5.QtCore import QSize, Qt from PyQt5.Qt import * from PyQt5 import QtGui, QtCore, QtWidgets from PyQt5.QtGui import QPixmap, QIcon from PyQt5.QtWidgets import QHBoxLayout, QAbstractItemView, QTableView, QVBoxLayout, QSplitter, \ QApplication, QGroupBox, QLabel, QGridLayout, QLineEdit, QComboBox, QTextEdit, QCheckBox,QVBoxLayout,QListView, QMainWindow, QStackedWidget, QMessageBox from PyQt5.QtWidgets import QListWidget, QStackedWidget, QFrame from PyQt5.QtWidgets import QListWidgetItem, QSizePolicy from PyQt5.QtWidgets import QWidget, QSpacerItem, QHeaderView from ctypes import POINTER, cast from ctypes.wintypes import MSG from PyQt5.QtWinExtras import QtWin from win32 import win32api, win32gui from win32.lib import win32con from UI.VarManages.FFWidget import FFWidget 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, FFSimulateWidgets, \ HartSimulateWidgets from ..UserManage.UserWidget import UserWidgets from ..TrendManage.TrendWidget import TrendWidgets from ..Setting.RTUSetting import RTUSettingWidget from ..Setting.TCPSetting import TCPSettingWidget from model.ClientModel.Client import Client from utils import Globals import qtawesome 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__() 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) # 窗体半透明模式 # QtWin.enableBlurBehindWindow(self) # self.setWindowFlags(Qt.FramelessWindowHint | # Qt.WindowMinMaxButtonsHint) # self.windowEffect.addWindowAnimation(self.winId()) # self.windowEffect.setAcrylicEffect(self.winId()) # self.setStyleSheet("background:transparent") 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() self.varWidget = VarWidgets() self.trendWidget = TrendWidgets() self.TcpSettingWidget = TCPSettingWidget() self.RtuSettingWidget = RTUSettingWidget() self.hartWidget = HartWidgets() self.tcrtdWidget = TcRtdWidgets() self.analogWidget = AnalogWidgets() self.ffWidget = FFWidget() self.ffsimulateWidget = FFSimulateWidgets() self.hartsimulateWidget = HartSimulateWidgets() self.userWidget.setObjectName('userWidget') self.projectWidget.setObjectName('projectWidget') self.trendWidget.setObjectName('trendWidget') self.varWidget.setObjectName('varWidget') self.analogWidget.setObjectName('analogWidget') self.ffWidget.setObjectName('ffWidget') self.ffsimulateWidget.setObjectName('ffsimulateWidget') self.hartsimulateWidget.setObjectName('hartsimulateWidget') self.rightWidget = QStackedWidget() # self.rightWidget.setAttribute(Qt.WA_StyledBackground, True) self.rightWidget.setObjectName("rightWidget") self.rightWidget.addWidget(self.projectWidget) self.rightWidget.addWidget(self.varWidget) self.rightWidget.addWidget(self.trendWidget) self.rightWidget.addWidget(self.userWidget) self.rightWidget.addWidget(self.TcpSettingWidget) self.rightWidget.addWidget(self.RtuSettingWidget) self.rightWidget.addWidget(self.hartWidget) self.rightWidget.addWidget(self.tcrtdWidget) self.rightWidget.addWidget(self.analogWidget) self.rightWidget.addWidget(self.ffWidget) self.rightWidget.addWidget(self.ffsimulateWidget) self.rightWidget.addWidget(self.hartsimulateWidget) 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) 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): if not Globals.getValue('currentPro') and index != 0: return -1 self.rightWidget.setCurrentIndex(index) if index in [4, 5]: return Globals.setValue('SearchWidget', index) def showSetting(self): proType = Globals.getValue('currentProType') if proType == -1: return elif proType in ['0', '1']: if self.exButtonClicked(4) != -1: self.TcpSettingWidget.setupUI() elif proType in ['2', '3']: if self.exButtonClicked(5) != -1: self.RtuSettingWidget.setupUI() def varShow(self): proType = Globals.getValue('currentProType') if proType == -1: return elif proType in ['0', '1', '2', '3']: self.exButtonClicked(1) Globals.setValue('SearchWidget', 1) elif proType in ['4']: self.exButtonClicked(6) Globals.setValue('SearchWidget', 6) elif proType in ['5']: self.exButtonClicked(7) Globals.setValue('SearchWidget', 7) elif proType in ['6']: self.exButtonClicked(8) Globals.setValue('SearchWidget', 8) elif proType in ['7']: self.exButtonClicked(9) self.ffWidget.initDevView() Globals.setValue('SearchWidget', 9) elif proType in ['8']: self.exButtonClicked(10) Globals.setValue('SearchWidget', 10) elif proType in ['9']: self.exButtonClicked(11) Globals.setValue('SearchWidget', 11) #枚举参数 def reFreshTrendWidget(self): self.trendWidget.getMems() self.exButtonClicked(2) 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_())