0325更新

main
parent c9c1a15bdb
commit 3bc89aa785

@ -132,7 +132,6 @@ QPushButton#initAddDeviceButton:hover, QPushButton#initAreaAddButton:hover, QPus
QLabel#wirteDIDOareaMessLabel, QLabel#wirteDIDOareaValueLabel{
font-size: 16px;
@ -189,6 +188,13 @@ QLabel#areaValueLabel{
}
QLabel#deviceNameLabel, QLabel#pvUpperLimitLabel, QLabel#pvLowerLimitLabel, QLabel#pvUnitLabel{
font:28px;
}
QLineEdit#byteLineEdit{
font-size: 20px;
@ -245,7 +251,19 @@ QLineEdit#areaLineEdit {
}
QLineEdit#deviceName, QLineEdit#pvUpperLimit, QLineEdit#pvLowerLimit, QLineEdit#pvUnit{
font: 28px;
border-top: none;
border-left: none;
border-right: none;
border-bottom: 2px solid gary;
}
QComboBox#dataTypeCombox, QComboBox#orderCombox{

@ -25,6 +25,8 @@ QTabBar{
background-color: #D3E3FD;
font:28px;
}
@ -74,7 +76,7 @@ QTabBar#areaTabBar::tab:selected {
QDockWidget{
font: 18px;
font: 28px;
font: bold;
@ -82,6 +84,7 @@ QDockWidget{
border: none;
color: white;
}
@ -95,13 +98,12 @@ QDockWidget::title{
text-align: center;
}
QPushButton#startProtocolBtn, QPushButton#switchBtn, QPushButton#switchTouchBtn{
font-size: 20px;
font-size: 25px;
border: none;
@ -111,7 +113,7 @@ QPushButton#startProtocolBtn, QPushButton#switchBtn, QPushButton#switchTouchBtn{
QPushButton#startProtocolBtn:hover, QPushButton#switchBtn:hover, QPushButton#switchTouchBtn::hover{
font-size: 20px;
font-size: 25px;
font: bold;
@ -125,12 +127,89 @@ QPushButton#startProtocolBtn:hover, QPushButton#switchBtn:hover, QPushButton#swi
QPushButton#startProtocolBtn:checked, QPushButton#switchBtn:checked, QPushButton#switchTouchBtn:checked{
font-size: 25px;
border: none;
}
QPushButton#okButton{
width: 54.75px;
height: 40px;
background-color: #09F738;
border-radius: 5px;
color: #FFFFFF;
font-family: ".SFNSDisplay-Medium";
font-size: 20px;
font-weight: 520;
}
QPushButton#cancelButton{
width: 54.75px;
height: 40px;
background-color: #EE1169;
border-radius: 5px;
color: white;
font-family: ".SFNSDisplay-Medium";
font-size: 20px;
font-weight: 520;
}
QPushButton#okButton:hover, QPushButton#cancelButton:hover{
font: bold;
border: none;
margin-bottom: -1px;
}
QPushButton#closeButton, QPushButton#minButton{
border: none;
}
QPushButton#confirmButton, QPushButton#exitButton{
width: 54.75px;
height: 40px;
background-color: #5b8cff;
border-radius: 5px;
color: #FFFFFF;
font-family: ".SFNSDisplay-Medium";
font-size: 17px;
font-weight: 520;
}
QWidget#MainWindow{
@ -138,16 +217,25 @@ QWidget#MainWindow{
border: none;
font: 20px;
}
QWidget#deviceWidget{
background-color: white;
}
QDialog#deviceDialog{
background-color: #FFFFFF;
}
QTabWidget#areaTabWidget{
border: none;
@ -159,7 +247,7 @@ QTabWidget#areaTabWidget{
QLabel#batteryLabel{
font-size: 20px;
font-size: 23px;
font: bold;
@ -223,3 +311,27 @@ QRadioButton#valueRadio::indicator:disabled:checked{
image: url(Static/radioDisableOn.png);
}
QLineEdit#deviceMesEdit{
background-color: #f5f8f9;
border: none;
width: 239px;
height: 40px;
border-radius: 5px;
padding-left : 10px;
color: #889399;
font-family: ".SFNSDisplay-Regular";
font-size: 20px;
font-weight: 520;
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 242 B

After

Width:  |  Height:  |  Size: 764 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 166 B

@ -1,10 +1,8 @@
import re
from socket import AI_ADDRCONFIG
import sys
import json
import qtawesome
from tkinter import N
from functools import partial
from PyQt5.QtWidgets import QApplication, QMainWindow, QTabWidget, QWidget, QVBoxLayout, QLabel, QPushButton, QLayout, \
QHBoxLayout, QComboBox, QLineEdit, QSpacerItem, QSizePolicy, QGridLayout, QMessageBox, QSplitter, QFrame

@ -1,62 +1,143 @@
import sys
import re
from PyQt5.QtWidgets import QDialog, QFormLayout, QLineEdit, QDialogButtonBox, QMessageBox
from PyQt5.QtGui import QIcon
from PyQt5.QtCore import Qt
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
class DeviceDialog(QDialog):
BORDER_WIDTH = 5 #设圆角
def __init__(self,dataTypeAndModel,parent=None):
super().__init__(parent)
self.dataTypeAndModel = dataTypeAndModel
self.initUI()
def initUI(self):
layout = QFormLayout()
self.resize(306, 451)
self.setObjectName('deviceDialog')
self.deviceNameEdit = QLineEdit()
self.deviceNameEdit.setPlaceholderText("设备名称")
self.deviceNameEdit.setSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Preferred)
self.deviceNameEdit.setObjectName('deviceMesEdit')
self.pvUpperEdit = QLineEdit()
self.pvUpperEdit.setPlaceholderText("量程上限")
self.pvUpperEdit.setSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Preferred)
self.pvUpperEdit.setObjectName('deviceMesEdit')
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')
deviceName = QLineEdit()
deviceName.setObjectName('deviceName')
pvUpperLimit = QLineEdit()
pvUpperLimit.setObjectName('pvUpperLimit')
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)
pvLowerLimit = QLineEdit()
pvLowerLimit.setObjectName('pvLowerLimit')
pvUnit = QLineEdit()
pvUnit.setObjectName('pvUnit')
self.exitButton = QPushButton('取消')
self.exitButton.clicked.connect(self.close)
self.exitButton.setObjectName('exitButton')
layout.addRow("设备名:", deviceName)
layout.addRow("量程上限:", pvUpperLimit)
layout.addRow("量程下限:", pvLowerLimit)
layout.addRow("单位:", pvUnit)
self.horizontalLayout = QHBoxLayout()
self.horizontalLayout.addWidget(self.confirmButton)
self.horizontalLayout.addWidget(self.exitButton)
self.horizontalLayout.setSpacing(10)
self.horizontalLayout.setContentsMargins(0, 0, 0, 0)
button_box = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel)
ok_button = button_box.button(QDialogButtonBox.Ok)
ok_button.setText("确定") # 设置Ok按钮的文本
self.verticalLayout = QVBoxLayout(self)
cancel_button = button_box.button(QDialogButtonBox.Cancel)
cancel_button.setText("取消") # 设置Cancel按钮的文本
self.conVerLayout = QVBoxLayout()
self.conVerLayout.addWidget(QWidget(), 1)
self.conVerLayout.addWidget(self.deviceNameEdit, 1)
self.conVerLayout.addWidget(self.pvUpperEdit, 1)
self.conVerLayout.addWidget(self.pvLowerEdit, 1)
self.conVerLayout.addWidget(self.pvUnitEdit, 1)
self.conVerLayout.addLayout(self.horizontalLayout, 1)
self.conVerLayout.setSpacing(32)
self.conVerLayout.setContentsMargins(34, 26, 34, 50)
button_box.accepted.connect(self.checkInput)
button_box.rejected.connect(self.reject)
# self.verticalLayout.addWidget(self.picLabel)
self.verticalLayout.addLayout(self.conVerLayout)
layout.addRow(button_box)
self.verticalLayout.setSpacing(0)
self.verticalLayout.setContentsMargins(0, 0, 0, 0)
self.setWindowIcon(QIcon('Static/zhjt.ico'))
self.setWindowFlags(self.windowFlags() & ~Qt.WindowContextHelpButtonHint) # 去掉标题栏的问号
self.setLayout(layout)
self.setWindowTitle("设备信息")
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(451) #窗体最小高度
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)
def getParameters(self):
deviceName = self.findChild(QLineEdit, "deviceName").text()
pvUpperLimit = self.findChild(QLineEdit, "pvUpperLimit").text()
pvLowerLimit = self.findChild(QLineEdit, "pvLowerLimit").text()
pvUnit = self.findChild(QLineEdit, "pvUnit").text()
deviceName = self.deviceNameEdit.text() + self.dataTypeAndModel
pvUpperLimit = self.pvUpperEdit.text()
pvLowerLimit = self.pvLowerEdit.text()
pvUnit = self.pvUnitEdit.text()
return deviceName, pvUpperLimit, pvLowerLimit, pvUnit
def checkInput(self):
titleName, pvUpperLimit, pvLowerLimit, pvUnit = self.getParameters()
deviceName = titleName + self.dataTypeAndModel
deviceName, pvUpperLimit, pvLowerLimit, pvUnit = self.getParameters()
if not pvUpperLimit and not pvLowerLimit and not pvUnit:
pass
else:
@ -80,3 +161,228 @@ class DeviceDialog(QDialog):
return
else:
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_())

@ -254,14 +254,13 @@ class DeviceTab(QTabWidget):
if deviceName is None:
dialog = DeviceDialog(self.dataTypeAndModel)
if dialog.exec_() == QDialog.Accepted:
self.titleName, pvUpperLimit, pvLowerLimit, pvUnit = dialog.getParameters()
self.deviceName = self.titleName + self.dataTypeAndModel
self.deviceName, pvUpperLimit, pvLowerLimit, pvUnit = dialog.getParameters()
DeviceDB().addDevice(deviceName = self.deviceName, proType = self.proType , masterSlaveModel = self.masterSlaveModel, pvUpperLimit=pvUpperLimit, pvLowerLimit=pvLowerLimit, pvUnit=pvUnit)
if init:
self.removeTab(0)
tabIndex = self.count()
self.tabBar().setHidden(False)
self.addTab(AreaTabWidget(self),str(self.titleName))
self.addTab(AreaTabWidget(self),str(self.deviceName[:-4]))
self.setCurrentIndex(tabIndex)
self.devicesManange.addDevice(proType=self.proType, masterSlaveModel = self.masterSlaveModel, deviceName = self.deviceName)
else:

@ -10,7 +10,7 @@ import qtawesome
from PyQt5.QtWidgets import QApplication, QPushButton, QMainWindow, QDockWidget, QToolBar, QAction, QTabWidget, QGridLayout, QWidget, QHBoxLayout, QStackedWidget\
,QVBoxLayout, QProgressBar, QLabel
from PyQt5.QtCore import Qt, QTimer, QSize
from PyQt5.QtGui import QIcon, QWindow
from PyQt5.QtGui import QIcon, QWindow, QPixmap
from utils.DBModels.BaseModel import *
from model.ClientModel.Client import Client
from UI.DeviceWidget import DeviceTab
@ -99,14 +99,14 @@ class MainWindow(QWidget):
# self.startProtocolBtn.setIcon(QIcon('Static/startProtocol.png'))
self.startProtocolBtn.setText('开始通讯')
self.startProtocolBtn.setIcon(QIcon('Static/start.png'))
self.startProtocolBtn.setIconSize(QSize(18, 18))
self.startProtocolBtn.setIconSize(QSize(23, 23))
self.startProtocolBtn.setCheckable(True)
self.startProtocolBtn.clicked.connect(self.startProtocol)
self.switchBtn = QPushButton('通讯组态')
self.switchBtn.setObjectName("switchBtn")
self.switchBtn.setIcon(qtawesome.icon('fa.exchange', color='#1fbb6f'))
self.switchBtn.setIconSize(QSize(20, 20))
self.switchBtn.setIconSize(QSize(25, 25))
self.switchBtn.setCheckable(True)
self.switchBtn.clicked.connect(self.switchWidget)
@ -117,12 +117,33 @@ class MainWindow(QWidget):
self.batteryStateLabel.setObjectName('batteryLabel')
self.switchTouchBtn = QPushButton("触控模式")
self.switchTouchBtn.setIconSize(QSize(20, 20))
self.switchTouchBtn.setIconSize(QSize(25, 25))
self.switchTouchBtn.setObjectName('switchTouchBtn')
self.switchTouchBtn.setIcon(qtawesome.icon('fa.keyboard-o', color='#1fbb6f'))
self.switchTouchBtn.clicked.connect(self.switchTouchMode)
self.switchTouchBtn.setCheckable(True)
# 创建按钮
self.minimizeButton = QPushButton(QIcon('Static/min.png'), "")
self.minimizeButton.setObjectName('minButton')
self.closeButton = QPushButton(QIcon('Static/close.png'), "")
self.closeButton.setObjectName('closeButton')
# 按钮点击事件连接
self.minimizeButton.clicked.connect(self.showMinimized)
self.closeButton.clicked.connect(self.close)
hLayout = QHBoxLayout()
hLayout.addWidget(self.minimizeButton)
hLayout.addWidget(self.closeButton)
iconLabel = QLabel()
pix = QPixmap('Static/Hicent.png')
scaledPixmap = pix.scaled(168, 28, Qt.KeepAspectRatio)
iconLabel.setPixmap(scaledPixmap)
iconLabel.setScaledContents(True)
toolbarLayout.addWidget(iconLabel, 1)
toolbarLayout.addWidget(QWidget(), 1)
toolbarLayout.addWidget(self.startProtocolBtn, 1)
toolbarLayout.addWidget(self.switchBtn, 1)
toolbarLayout.addWidget(self.switchTouchBtn, 1)
@ -130,6 +151,9 @@ class MainWindow(QWidget):
# toolbarLayout.addWidget(QLabel('电量:'), 1)
toolbarLayout.addWidget(self.batteryProBar, 1)
toolbarLayout.addWidget(self.batteryStateLabel, 1)
toolbarLayout.addWidget(QWidget(), 1)
toolbarLayout.addLayout(hLayout, 1)
toolbarLayout.setSpacing(20)
toolbarLayout.setContentsMargins(0, 0, 0, 0)
@ -167,13 +191,16 @@ class MainWindow(QWidget):
self.setLayout(self.mainLayout)
# self.setCentralWidget(self.stackWidget)
self.setWindowIcon(QIcon('Static/zhjt.ico'))
self.setWindowTitle("PROFIBUS")
self.setWindowIcon(QIcon('Static/Hicent.jpg'))
self.setWindowTitle("PROFIBUS总线测试工具")
self.refreshProgressBar()
self.devicesManange.connect()
self.setWindowFlags(Qt.FramelessWindowHint)
# self.resize(800, 600)
# self.showMaximized()
@ -295,6 +322,13 @@ class MainWindow(QWidget):
Globals.setValue('_touchMode', 0)
self.switchTouchBtn.setText('触控模式')
def toggleMaximize(self):
if self.isMaximized():
self.showNormal()
self.maxRestoreButton.setIcon(QIcon('maximizeIcon.png'))
else:
self.showMaximized()
self.maxRestoreButton.setIcon(QIcon('restoreIcon.png')) # 替换为合适的还原图标路径

@ -15,7 +15,7 @@ if __name__ == '__main__':
Globals._init()
Client.initDB()
window = MainWindow()
window.showMaximized()
window.showFullScreen()
Globals.setValue('MainWindow', window)
# window.show()
sys.exit(app.exec_())

@ -1,4 +1,4 @@
modbus_tk==1.1.3
numpy==1.26.4
peewee==3.17.1
PyQt5==5.15.10
qtawesome

@ -0,0 +1,2 @@
from .window_effect import WindowEffect
from .c_structures import *

@ -0,0 +1,135 @@
# coding:utf-8
from ctypes import POINTER, Structure, c_int
from ctypes.wintypes import DWORD, HWND, ULONG, POINT, RECT, UINT
from enum import Enum
class WINDOWCOMPOSITIONATTRIB(Enum):
WCA_UNDEFINED = 0
WCA_NCRENDERING_ENABLED = 1
WCA_NCRENDERING_POLICY = 2
WCA_TRANSITIONS_FORCEDISABLED = 3
WCA_ALLOW_NCPAINT = 4
WCA_CAPTION_BUTTON_BOUNDS = 5
WCA_NONCLIENT_RTL_LAYOUT = 6
WCA_FORCE_ICONIC_REPRESENTATION = 7
WCA_EXTENDED_FRAME_BOUNDS = 8
WCA_HAS_ICONIC_BITMAP = 9
WCA_THEME_ATTRIBUTES = 10
WCA_NCRENDERING_EXILED = 11
WCA_NCADORNMENTINFO = 12
WCA_EXCLUDED_FROM_LIVEPREVIEW = 13
WCA_VIDEO_OVERLAY_ACTIVE = 14
WCA_FORCE_ACTIVEWINDOW_APPEARANCE = 15
WCA_DISALLOW_PEEK = 16
WCA_CLOAK = 17
WCA_CLOAKED = 18
WCA_ACCENT_POLICY = 19
WCA_FREEZE_REPRESENTATION = 20
WCA_EVER_UNCLOAKED = 21
WCA_VISUAL_OWNER = 22
WCA_LAST = 23
class ACCENT_STATE(Enum):
""" Client area status enumeration class """
ACCENT_DISABLED = 0
ACCENT_ENABLE_GRADIENT = 1
ACCENT_ENABLE_TRANSPARENTGRADIENT = 2
ACCENT_ENABLE_BLURBEHIND = 3 # Aero effect
ACCENT_ENABLE_ACRYLICBLURBEHIND = 4 # Acrylic effect
ACCENT_ENABLE_HOSTBACKDROP = 5 # Mica effect
ACCENT_INVALID_STATE = 6
class ACCENT_POLICY(Structure):
""" Specific attributes of client area """
_fields_ = [
("AccentState", DWORD),
("AccentFlags", DWORD),
("GradientColor", DWORD),
("AnimationId", DWORD),
]
class WINDOWCOMPOSITIONATTRIBDATA(Structure):
_fields_ = [
("Attribute", DWORD),
# Pointer() receives any ctypes type and returns a pointer type
("Data", POINTER(ACCENT_POLICY)),
("SizeOfData", ULONG),
]
class DWMNCRENDERINGPOLICY(Enum):
DWMNCRP_USEWINDOWSTYLE = 0
DWMNCRP_DISABLED = 1
DWMNCRP_ENABLED = 2
DWMNCRP_LAS = 3
class DWMWINDOWATTRIBUTE(Enum):
DWMWA_NCRENDERING_ENABLED = 1
DWMWA_NCRENDERING_POLICY = 2
DWMWA_TRANSITIONS_FORCEDISABLED = 3
DWMWA_ALLOW_NCPAINT = 4
DWMWA_CAPTION_BUTTON_BOUNDS = 5
DWMWA_NONCLIENT_RTL_LAYOUT = 6
DWMWA_FORCE_ICONIC_REPRESENTATION = 7
DWMWA_FLIP3D_POLICY = 8
DWMWA_EXTENDED_FRAME_BOUNDS = 9
DWMWA_HAS_ICONIC_BITMAP = 10
DWMWA_DISALLOW_PEEK = 11
DWMWA_EXCLUDED_FROM_PEEK = 12
DWMWA_CLOAK = 13
DWMWA_CLOAKED = 14
DWMWA_FREEZE_REPRESENTATION = 15
DWMWA_PASSIVE_UPDATE_MODE = 16
DWMWA_USE_HOSTBACKDROPBRUSH = 17
DWMWA_USE_IMMERSIVE_DARK_MODE = 18
DWMWA_WINDOW_CORNER_PREFERENCE = 19
DWMWA_BORDER_COLOR = 20
DWMWA_CAPTION_COLOR = 21
DWMWA_TEXT_COLOR = 22
DWMWA_VISIBLE_FRAME_BORDER_THICKNESS = 23
DWMWA_LAST = 24
class MARGINS(Structure):
_fields_ = [
("cxLeftWidth", c_int),
("cxRightWidth", c_int),
("cyTopHeight", c_int),
("cyBottomHeight", c_int),
]
class MINMAXINFO(Structure):
_fields_ = [
("ptReserved", POINT),
("ptMaxSize", POINT),
("ptMaxPosition", POINT),
("ptMinTrackSize", POINT),
("ptMaxTrackSize", POINT),
]
class PWINDOWPOS(Structure):
_fields_ = [
('hWnd', HWND),
('hwndInsertAfter', HWND),
('x', c_int),
('y', c_int),
('cx', c_int),
('cy', c_int),
('flags', UINT)
]
class NCCALCSIZE_PARAMS(Structure):
_fields_ = [
('rgrc', RECT*3),
('lppos', POINTER(PWINDOWPOS))
]

@ -0,0 +1,222 @@
# coding:utf-8
import sys
from ctypes import POINTER, c_bool, c_int, pointer, sizeof, WinDLL, byref
from ctypes.wintypes import DWORD, LONG, LPCVOID
from win32 import win32api, win32gui
from win32.lib import win32con
from .c_structures import (
ACCENT_POLICY,
ACCENT_STATE,
MARGINS,
DWMNCRENDERINGPOLICY,
DWMWINDOWATTRIBUTE,
WINDOWCOMPOSITIONATTRIB,
WINDOWCOMPOSITIONATTRIBDATA,
)
class WindowEffect:
""" A class that calls Windows API to realize window effect """
def __init__(self):
# Declare the function signature of the API
self.user32 = WinDLL("user32")
self.dwmapi = WinDLL("dwmapi")
self.SetWindowCompositionAttribute = self.user32.SetWindowCompositionAttribute
self.DwmExtendFrameIntoClientArea = self.dwmapi.DwmExtendFrameIntoClientArea
self.DwmSetWindowAttribute = self.dwmapi.DwmSetWindowAttribute
self.SetWindowCompositionAttribute.restype = c_bool
self.DwmExtendFrameIntoClientArea.restype = LONG
self.DwmSetWindowAttribute.restype = LONG
self.SetWindowCompositionAttribute.argtypes = [
c_int,
POINTER(WINDOWCOMPOSITIONATTRIBDATA),
]
self.DwmSetWindowAttribute.argtypes = [c_int, DWORD, LPCVOID, DWORD]
self.DwmExtendFrameIntoClientArea.argtypes = [c_int, POINTER(MARGINS)]
# Initialize structure
self.accentPolicy = ACCENT_POLICY()
self.winCompAttrData = WINDOWCOMPOSITIONATTRIBDATA()
self.winCompAttrData.Attribute = WINDOWCOMPOSITIONATTRIB.WCA_ACCENT_POLICY.value
self.winCompAttrData.SizeOfData = sizeof(self.accentPolicy)
self.winCompAttrData.Data = pointer(self.accentPolicy)
def setAcrylicEffect(self, hWnd, gradientColor: str = "F2F2F299", isEnableShadow: bool = True, animationId: int = 0):
""" Add the acrylic effect to the window
Parameters
----------
hWnd: int or `sip.voidptr`
Window handle
gradientColor: str
Hexadecimal acrylic mixed color, corresponding to four RGBA channels
isEnableShadow: bool
Enable window shadows
animationId: int
Turn on matte animation
"""
hWnd = int(hWnd)
# Acrylic mixed color
gradientColor = (
gradientColor[6:]
+ gradientColor[4:6]
+ gradientColor[2:4]
+ gradientColor[:2]
)
gradientColor = DWORD(int(gradientColor, base=16))
# matte animation
animationId = DWORD(animationId)
# window shadow
accentFlags = DWORD(0x20 | 0x40 | 0x80 |
0x100) if isEnableShadow else DWORD(0)
self.accentPolicy.AccentState = ACCENT_STATE.ACCENT_ENABLE_ACRYLICBLURBEHIND.value
self.accentPolicy.GradientColor = gradientColor
self.accentPolicy.AccentFlags = accentFlags
self.accentPolicy.AnimationId = animationId
# enable acrylic effect
self.SetWindowCompositionAttribute(hWnd, pointer(self.winCompAttrData))
def setMicaEffect(self, hWnd):
""" Add the mica effect to the window (Win11 only)
Parameters
----------
hWnd: int or `sip.voidptr`
Window handle
"""
if sys.getwindowsversion().build < 22000:
raise Exception("The mica effect is only available on Win11")
hWnd = int(hWnd)
margins = MARGINS(-1, -1, -1, -1)
self.DwmExtendFrameIntoClientArea(hWnd, byref(margins))
self.DwmSetWindowAttribute(hWnd, 1029, byref(c_int(1)), 4)
self.accentPolicy.AccentState = ACCENT_STATE.ACCENT_ENABLE_HOSTBACKDROP.value
self.SetWindowCompositionAttribute(hWnd, pointer(self.winCompAttrData))
def setAeroEffect(self, hWnd):
""" Add the aero effect to the window
Parameters
----------
hWnd: int or `sip.voidptr`
Window handle
"""
hWnd = int(hWnd)
self.accentPolicy.AccentState = ACCENT_STATE.ACCENT_ENABLE_BLURBEHIND.value
self.SetWindowCompositionAttribute(hWnd, pointer(self.winCompAttrData))
def removeBackgroundEffect(self, hWnd):
""" Remove background effect
Parameters
----------
hWnd: int or `sip.voidptr`
Window handle
"""
hWnd = int(hWnd)
self.accentPolicy.AccentState = ACCENT_STATE.ACCENT_DISABLED.value
self.SetWindowCompositionAttribute(hWnd, pointer(self.winCompAttrData))
@staticmethod
def moveWindow(hWnd):
""" Move the window
Parameters
----------
hWnd: int or `sip.voidptr`
Window handle
"""
hWnd = int(hWnd)
win32gui.ReleaseCapture()
win32api.SendMessage(
hWnd, win32con.WM_SYSCOMMAND, win32con.SC_MOVE + win32con.HTCAPTION, 0
)
def addShadowEffect(self, hWnd):
""" Add DWM shadow to window
Parameters
----------
hWnd: int or `sip.voidptr`
Window handle
"""
hWnd = int(hWnd)
margins = MARGINS(-1, -1, -1, -1)
self.DwmExtendFrameIntoClientArea(hWnd, byref(margins))
def addMenuShadowEffect(self, hWnd):
""" Add DWM shadow to menu
Parameters
----------
hWnd: int or `sip.voidptr`
Window handle
"""
hWnd = int(hWnd)
self.DwmSetWindowAttribute(
hWnd,
DWMWINDOWATTRIBUTE.DWMWA_NCRENDERING_POLICY.value,
byref(c_int(DWMNCRENDERINGPOLICY.DWMNCRP_ENABLED.value)),
4,
)
margins = MARGINS(-1, -1, -1, -1)
self.DwmExtendFrameIntoClientArea(hWnd, byref(margins))
def removeShadowEffect(self, hWnd):
""" Remove DWM shadow from the window
Parameters
----------
hWnd: int or `sip.voidptr`
Window handle
"""
hWnd = int(hWnd)
self.DwmSetWindowAttribute(
hWnd,
DWMWINDOWATTRIBUTE.DWMWA_NCRENDERING_POLICY.value,
byref(c_int(DWMNCRENDERINGPOLICY.DWMNCRP_DISABLED.value)),
4,
)
@staticmethod
def removeMenuShadowEffect(hWnd):
""" Remove shadow from pop-up menu
Parameters
----------
hWnd: int or `sip.voidptr`
Window handle
"""
hWnd = int(hWnd)
style = win32gui.GetClassLong(hWnd, win32con.GCL_STYLE)
style &= ~0x00020000 # CS_DROPSHADOW
win32api.SetClassLong(hWnd, win32con.GCL_STYLE, style)
@staticmethod
def addWindowAnimation(hWnd):
""" Enables the maximize and minimize animation of the window
Parameters
----------
hWnd : int or `sip.voidptr`
Window handle
"""
hWnd = int(hWnd)
style = win32gui.GetWindowLong(hWnd, win32con.GWL_STYLE)
win32gui.SetWindowLong(
hWnd,
win32con.GWL_STYLE,
style
| win32con.WS_MAXIMIZEBOX
| win32con.WS_CAPTION
| win32con.CS_DBLCLKS
| win32con.WS_THICKFRAME,
)
Loading…
Cancel
Save