原创声明:本文系作者授权CSDN平台发表,未经许可,不得转载。
代码已上传到 gitee 仓库,文章浏览完毕后方可获取仓库地址
提示:如有错误或更好的建议请在评论区指出或私信
如果把系统自带边框去掉后,窗口移动和调整大小以及最大化、最小化等功能就消失了。网上有很多无边框设计的模板,但是大多都是通过各种计算来判断位置以及各种计算来改变窗口大小和移动窗口,代码量很长而且略复杂。所以本次对无边框设计做个优化,来简化代码量和代码逻辑。
setWindowFlags()
(Qt.Window | Qt.FramelessWindowHint | Qt.WindowSystemMenuHint | Qt.WindowMinimizeButtonHint| Qt.WindowMaximizeButtonHint)
setAttribute(Qt.WA_TranslucentBackground)
代码如下(示例):
class CustomWindow(QMainWindow):
def __init__(self):
super().__init__()
self.set_window() # 定制窗口
def set_window(self):
# 关闭系统标题栏
self.setWindowFlags(Qt.Window | Qt.FramelessWindowHint | Qt.WindowSystemMenuHint | Qt.WindowMinimizeButtonHint
| Qt.WindowMaximizeButtonHint)
# 透明背景
self.setAttribute(Qt.WA_TranslucentBackground)
因为背景透明,如若不添加阴影那么定位窗口边缘时无法定位(透明的,相当于窗口没有这一部分了)
代码如下(示例):
class CustomWindow(QMainWindow):
def __init__(self):
super().__init__()
# 边界以透明,设置边框阴影效果,否则无法定位边界
self.shadow = QGraphicsDropShadowEffect(self)
self.shadow.setBlurRadius(15)
self.shadow.setColor(QColor(0, 0, 0, 150))
self.shadow.setOffset(0, 0)
self.setGraphicsEffect(self.shadow)
窗口调整大小主要用到QT的鼠标事件功能,结合窗口调整大小内置函数来实现;
窗口需要开启鼠标跟踪self.setMouseTracking(True)
备注:控件的父类也开启跟踪,否则只有在按下鼠标左键的时候才跟踪
QRect
来圈定窗口边界范围,QRect
的参数为(左上角x, 左上角y, 右下角x, 右下角y);event.pos()
返回当前鼠标位置;QRect.contains(event.pos())
返回bool值;所以当鼠标在矩形范围内返回True
时,更改鼠标的 调整大小的样式,并且给类定义一个方向属性,返回当前所在哪个矩形范围内。
代码如下(示例):
# 窗口边缘设置鼠标手势(右侧、底部、右下角)
def mouseMoveEvent(self, event):
# QRect边界范围(左上角x, 左上角y, 右下角x, 右下角y)
# 右侧边缘(窗口宽度减去边框宽度,0, 窗口宽度, 窗口高度)
self.right_edge = QRect(self.width() - 10, 0, self.width(), self.height())
# 底部边缘(不在具体说明)
self.bottom_edge = QRect(0, self.height() - 10, self.width() - 25, self.height())
# 右下角边缘(不在具体说明)
self.right_bottom_edge = QRect(self.width() - 25, self.height() - 10, self.width(), self.height())
# 根据鼠标在窗口的位置 改变鼠标手势
if not self.isMaximized():
if self.bottom_edge.contains(event.pos()):
self.setCursor(Qt.SizeVerCursor) # 改变鼠标样式为上下调整大小样式
self.direction = "bottom" # 方向属性为下
elif self.right_edge.contains(event.pos()):
self.setCursor(Qt.SizeHorCursor)
self.direction = "right"
elif self.right_bottom_edge.contains(event.pos()):
self.setCursor(Qt.SizeFDiagCursor)
self.direction = "right_bottom"
startSystemResize()
内置函数来调整窗口大小# 窗口边缘调整窗口大小(右侧、底部、右下角)
def mousePressEvent(self, event):
if event.button() == Qt.LeftButton:
# 鼠标左键点击下边界区域 调整大小
if self.direction == 'bottom':
self.windowHandle().startSystemResize(Qt.BottomEdge)
# 鼠标左键点击右边界区域 调整大小
elif self.direction == 'right':
self.windowHandle().startSystemResize(Qt.RightEdge)
elif self.direction == 'right_bottom':
self.windowHandle().startSystemResize(Qt.RightEdge | Qt.BottomEdge)
self.ui.xxxx.installEventFilter(self)
xxxx建议是整个窗口的QFrame
控件 def eventFilter(self, obj, event):
if isinstance(event, QEnterEvent):
self.setCursor(Qt.ArrowCursor)
self.direction = None
return super().eventFilter(obj, event)
使用startSystemMove()
内置函数来完成功能
结合控件的内置鼠标事件绑定即可
# 自定义标题栏
def custom_titlebar(self):
# 窗口移动
def move_titlebar(_event):
self.windowHandle().startSystemMove()
self.ui.AppDes.mouseMoveEvent = move_titlebar # 标题栏移动信号绑定窗口移动事件
# 标题栏双击最大化|还原
def doubleclick_titlebar(event):
if event.button() == Qt.LeftButton:
self.max_restore()
self.ui.AppDes.mouseDoubleClickEvent = doubleclick_titlebar # 标题栏双击信号绑定窗口最大化|还原事件
# 按钮[最小化, 最大化|还原, 关闭程序]
self.ui.BtnMin.clicked.connect(self.showMinimized) # 最小化
self.ui.BtnMaxRestore.clicked.connect(self.max_restore) # 最大化|还原
self.ui.BtnClose.clicked.connect(self.close) # 关闭程序
主要使用了startSystemMove()
和 startSystemResize()
这两个内置方法来完成复杂的计算和功能的实现。
这两个内置函数是QT在5.15版本在QWindow
中提供了两个新的方法。
"""
取消系统标题栏, 定制窗口.
1. 关闭系统标题栏, 窗口透明
2. 调整窗口大小(右下角, 右|下边缘), 边缘鼠标样式
3. 事件过滤器
4. 窗体添加边缘阴影
"""
from PySide2.QtCore import Qt, QRect
from PySide2.QtGui import QColor, QEnterEvent
from PySide2.QtWidgets import QMainWindow, QDialog, QGraphicsDropShadowEffect
class CustomWindow(QMainWindow, QDialog):
# 初始化
def __init__(self):
super().__init__()
self.shadow = None # 阴影
self.direction = None # 调整方向
self.right_edge = None # 右边缘
self.bottom_edge = None # 下边缘
self.right_bottom_edge = None # 右下边缘
self.set_window() # 定制窗口
# 取消系统标题栏, 给窗口添加阴影
def set_window(self):
# 关闭系统标题栏
self.setWindowFlags(Qt.Window | Qt.FramelessWindowHint | Qt.WindowSystemMenuHint | Qt.WindowMinimizeButtonHint
| Qt.WindowMaximizeButtonHint)
# 透明背景
self.setAttribute(Qt.WA_TranslucentBackground)
# 边界以透明,设置边框阴影效果,否则无法定位边界
self.shadow = QGraphicsDropShadowEffect(self)
self.shadow.setBlurRadius(15)
self.shadow.setColor(QColor(0, 0, 0, 150))
self.shadow.setOffset(0, 0)
self.setGraphicsEffect(self.shadow)
# 窗口边缘调整窗口大小(右侧和底部)
def mousePressEvent(self, event):
if event.button() == Qt.LeftButton:
# 鼠标左键点击下边界区域 调整大小
if self.direction == 'bottom':
self.windowHandle().startSystemResize(Qt.BottomEdge)
# 鼠标左键点击右边界区域 调整大小
elif self.direction == 'right':
self.windowHandle().startSystemResize(Qt.RightEdge)
elif self.direction == 'right_bottom':
self.windowHandle().startSystemResize(Qt.RightEdge | Qt.BottomEdge)
# 窗口边缘设置鼠标手势(右侧和底部)
def mouseMoveEvent(self, event):
# 边界范围(x, y, x1, y1)
self.right_edge = QRect(self.width() - 10, 0, self.width(), self.height())
self.bottom_edge = QRect(0, self.height() - 10, self.width() - 25, self.height())
self.right_bottom_edge = QRect(self.width() - 25, self.height() - 10, self.width(), self.height())
# 根据鼠标在窗口的位置 改变鼠标手势
if not self.isMaximized():
if self.bottom_edge.contains(event.pos()):
self.setCursor(Qt.SizeVerCursor)
self.direction = "bottom"
elif self.right_edge.contains(event.pos()):
self.setCursor(Qt.SizeHorCursor)
self.direction = "right"
elif self.right_bottom_edge.contains(event.pos()):
self.setCursor(Qt.SizeFDiagCursor)
self.direction = "right_bottom"
# 事件过滤器, 鼠标进入其它控件后还原为标准鼠标样式, 方向属性变为None
def eventFilter(self, obj, event):
if isinstance(event, QEnterEvent):
self.setCursor(Qt.ArrowCursor)
self.direction = None
return super().eventFilter(obj, event)
"""
加载UI文、定制UI界面.
备注:
需要给主窗口和主Widget窗口开启鼠标跟踪, 用来定位边缘位置
需要给主Frame添加事件过滤器, 过滤鼠标样式
模块功能:
1. 标题栏窗口移动,标题栏双击最大化|还原
2. 自定义按钮(最大化|还原, 最小化, 关闭窗口)
"""
from PySide2.QtGui import QIcon, Qt
import ui_1.qtui.res_rc # type: ignore
from lib.custom_window import CustomWindow
from ui_1.qtui.main_ui import Ui_MainWindow
class CustomUI(CustomWindow):
def __init__(self):
super().__init__()
self.ui = Ui_MainWindow()
self.ui.setupUi(self)
self.setMouseTracking(True) # 父窗口也开启跟踪,否则只有在按下鼠标左键的时候才跟踪
self.ui.AppWindow.setMouseTracking(True) # 设置子窗口鼠标跟踪
self.ui.AppBg.installEventFilter(self) # 事件过滤器, 鼠标进入AppBg控件 过滤事件
self.custom_titlebar() # 定制标题栏
# 最大化|还原
def max_restore(self):
if self.isMaximized():
self.showNormal() # 取消最大化, 正常展示
self.ui.AppMargins.setContentsMargins(10, 10, 10, 10) # 添加外边框
self.ui.BtnMaxRestore.setIcon(QIcon(u":/icons/pictures/icons/最大化.png")) # 更换最大化图标
else:
self.showMaximized() # 窗口最大化
self.ui.AppMargins.setContentsMargins(0, 0, 0, 0) # 取消外边框
self.ui.BtnMaxRestore.setIcon(QIcon(u":/icons/pictures/icons/还原.png")) # 更换还原图标
# 自定义标题栏
def custom_titlebar(self):
# 窗口移动
def move_titlebar(_event):
if self.isMaximized():
self.max_restore()
else:
self.windowHandle().startSystemMove()
self.ui.AppDes.mouseMoveEvent = move_titlebar # 标题栏移动信号绑定窗口移动事件
# 标题栏双击最大化|还原
def doubleclick_titlebar(event):
if event.button() == Qt.LeftButton:
self.max_restore()
self.ui.AppDes.mouseDoubleClickEvent = doubleclick_titlebar # 标题栏双击信号绑定窗口最大化|还原事件
# 按钮[最小化, 最大化|还原, 关闭程序]
self.ui.BtnMin.clicked.connect(self.showMinimized) # 最小化
self.ui.BtnMaxRestore.clicked.connect(self.max_restore) # 最大化|还原
self.ui.BtnClose.clicked.connect(self.close) # 关闭程序
如果这篇文章对你有帮助,那就点个赞呗!
项目gitee地址
项目刚开始建立,更新完善中…