import sys import re from PyQt5 import QtCore, QtGui, QtWidgets from PyQt5.QtCore import QSize, Qt from PyQt5.Qt import * from PyQt5.QtGui import QPixmap, QIcon from PyQt5.QtWidgets import QHBoxLayout, QAbstractItemView, QVBoxLayout, QSplitter, \ QApplication, QLabel, QGridLayout, QLineEdit, QComboBox, QTextEdit, QCheckBox,QVBoxLayout,QListView, QMainWindow, QStackedWidget, QMessageBox from PyQt5.QtWidgets import QSizePolicy, QWidget 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 windoweffect.window_effect import WindowEffect from windoweffect.c_structures import MINMAXINFO, NCCALCSIZE_PARAMS from utils.DBModels.DeviceModels import DeviceDB from model.ConfigModel.GSDManage import GsdParser from UI.ProfibusWidgets.SoftKeyBoardEdit import * from protocol.ModBus.DPV1Master import DPV1Master class EditAddressWidget(QDialog): BORDER_WIDTH = 5 #设圆角 def __init__(self): super().__init__() self.initUI() def initUI(self): self.resize(306, 350) self.setObjectName('deviceDialog') self.newAddressEdit = SoftKeyBoardEdit() self.newAddressEdit.setPlaceholderText("请输入目标站地址") self.newAddressEdit.setSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Preferred) self.newAddressEdit.setObjectName('deviceMesEdit') self.oldAddressEdit = SoftKeyBoardEdit() self.oldAddressEdit.setPlaceholderText("请输入原站地址") self.oldAddressEdit.setSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Preferred) self.oldAddressEdit.setObjectName('deviceMesEdit') # self.oldAddressLabel = QLabel(' 请输入原站地址: ' + str(self.address)) # self.oldAddressLabel.setSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Preferred) # self.oldAddressLabel.setObjectName('oldAddressLabel') # self.pvLowerEdit = QLineEdit() # self.pvLowerEdit.setPlaceholderText("量程下限") # self.pvLowerEdit.setSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Preferred) # self.pvLowerEdit.setObjectName('deviceMesEdit') # self.pvUnitEdit = QLineEdit() # self.pvUnitEdit.setPlaceholderText("单位") # self.pvUnitEdit.setSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Preferred) # self.pvUnitEdit.setObjectName('deviceMesEdit') self.confirmButton = QPushButton('确定') self.confirmButton.setObjectName('confirmButton') self.confirmButton.clicked.connect(self.checkInput) enterShortcut = QtWidgets.QShortcut(QtGui.QKeySequence(QtCore.Qt.Key_Return), self) enterShortcut.activated.connect(self.confirmButton.click) self.deviceTypeCombox = QComboBox() self.deviceTypeCombox.setObjectName('deviceTypeCombox') # self.deviceTypeCombox.addItems(['1', '2']) self.addCheckItem() # self.deviceTypeCombox.currentIndexChanged.connect(lambda index: self.changeDeviceType(index = index)) self.exitButton = QPushButton('取消') self.exitButton.clicked.connect(self.close) self.exitButton.setObjectName('exitButton') self.horizontalLayout = QHBoxLayout() self.horizontalLayout.addWidget(self.confirmButton) self.horizontalLayout.addWidget(self.exitButton) self.horizontalLayout.setSpacing(10) self.horizontalLayout.setContentsMargins(0, 0, 0, 0) self.verticalLayout = QVBoxLayout(self) self.conVerLayout = QVBoxLayout() self.conVerLayout.addWidget(QSplitter(), 1) self.conVerLayout.addWidget(self.oldAddressEdit, 2) self.conVerLayout.addWidget(self.newAddressEdit, 2) self.conVerLayout.addWidget(self.deviceTypeCombox, 2) # self.conVerLayout.addWidget(self.pvLowerEdit, 1) # self.conVerLayout.addWidget(self.pvUnitEdit, 1) # self.conVerLayout.addWidget(QSplitter(), 1) self.conVerLayout.addLayout(self.horizontalLayout, 2) self.conVerLayout.setSpacing(32) self.conVerLayout.setContentsMargins(34, 26, 34, 50) # self.verticalLayout.addWidget(self.picLabel) self.verticalLayout.addLayout(self.conVerLayout) self.verticalLayout.setSpacing(10) self.verticalLayout.setContentsMargins(0, 0, 0, 0) self.setLayout(self.verticalLayout) # 设置模态窗口 self.setWindowFlags(self.windowFlags() | Qt.Window) self.setWindowModality(Qt.ApplicationModal) 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(350) #窗体最小高度 self.setMinimumWidth(306) #窗体最小宽度 self.dir = self.Numbers.NONE #初始鼠标状态 #开启鼠标追踪 self.setMouseTracking(True) #初始化接口 self.windowEffect = WindowEffect() # 添加DWM阴影效果 self.windowEffect.addWindowAnimation(self.winId()) self.windowEffect.addShadowEffect(self.winId()) # 解决报错 self.windowHandle().screenChanged.connect(self.__onScreenChanged) self.setWindowOpacity(0.995) # 设置窗口透明度 self.setWindowFlag(Qt.FramelessWindowHint) self.DPV1Master = DPV1Master('192.168.3.10', 502) self.exec_() # def changeDeviceType(self, index): # print(index) def addCheckItem(self): self.GSDData = GsdParser.parseGsdFiles() # deviceTypeCombox for GSDDict in self.GSDData: self.deviceTypeCombox.addItem(GSDDict['modelName']) def checkInput(self): oldAddress = self.oldAddressEdit.text() newAddress = self.newAddressEdit.text() if newAddress and oldAddress: pattern = re.compile(r'^(?:[1-9]|[1-9][0-9]|1[0-1][0-9]|12[0-6])$') oldmatch = pattern.match(oldAddress) newmatch = pattern.match(newAddress) if not oldmatch: QMessageBox.warning(self, '提示', '请输入2 - 126。') return if not newmatch: QMessageBox.warning(self, '提示', '请输入2 - 126。') return if oldAddress == newAddress: reply = QMessageBox.question(self.parent(), '警告', "站地址重复", QMessageBox.Yes) return else: reply = QMessageBox.question(self.parent(), '警告', "请输入从站地址", QMessageBox.Yes) return identNumber = self.GSDData[self.deviceTypeCombox.currentIndex()]['identNumber'] print(identNumber) oldAddress = int(oldAddress) newAddress = int(newAddress) result = self.DPV1Master.editDevAddress(oldAddress, newAddress, identNumber) reply = QMessageBox.question(self.parent(), '提示', result, QMessageBox.Yes) self.accept() 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) if __name__ == '__main__': app = QApplication(sys.argv) app.setStyle(QtWidgets.QStyleFactory.create('Fusion')) # print(QtWidgets.QStyleFactory.keys()) ex = LoginWidget() ex.show() sys.exit(app.exec_())