PyQt窗口FramelessWindowHint模式下自定义窗口缩放与移动功能

背景
众所周知,PyQt的窗口支持隐藏系统默认的窗口,实现自定义窗口的样式 。
【PyQt窗口FramelessWindowHint模式下自定义窗口缩放与移动功能】但是,启用这种模式的窗口随之而来的问题是:无法使用系统默认的窗口缩放,窗口移动等功能 。因此,今天博主带来自己编写的一个自定义窗口类,需要使用的小伙伴可以直接下载此代码,将您自己的窗口类继承该类即可拥有以下功能 。
self.setWindowFlags(Qt.FramelessWindowHint)
功能部分功能演示
原理源代码 1、定制窗口基类
from PyQt5.QtWidgets import *from PyQt5.QtCore import *from PyQt5.QtGui import *from PyQt5.QtCore import Qt'''定制窗口基类@Author: 浅若清风cyf@Date: 2023/06/16@Description: 支持窗口缩放,标题栏双击最大最小化,解决了依赖mouseMoveEvent识别鼠标位置导致鼠标样式更新不及时的问题'''class MainWinCustom(QMainWindow):def __init__(self, titleHeight: int = 20):super(MainWinCustom, self).__init__()# 鼠标拖拽缩放窗口的识别区域宽度self._padding = 20# 设置标题栏的高度,作为双击标题栏的识别区域范围self.titleHeight = titleHeight# 隐藏系统默认框架self.setWindowFlags(Qt.FramelessWindowHint)# 一些鼠标状态self.is_mousePressed = Falseself.is_resizing = Falseself.resize_direction = 'right'# 一些功能启用状态self.support_resize = Trueself.support_double_max = Trueself.timer_cursorUpdater = QTimer(self)def set_mouse_tracking(self):self.ui.frame.setMouseTracking(True)self.ui.centralwidget.setMouseTracking(True)self.setMouseTracking(True)# / 设置widget鼠标跟踪def disable_window_resize(self):self.support_resize = Falseself.stop_cursorUpdater()def disable_double_max(self):self.support_double_max = Falsedef set_titleHeight(self, height: int):self.titleHeight = heightdef set_frame_style(self, frame: QFrame):frame.setFrameStyle(QFrame.Panel)def set_comboBoxView(self):comboBoxes = self.findChildren(QComboBox)for comboBox in comboBoxes:comboBox.setView(QListView())def set_max_button(self, btn: QToolButton or QPushButton):btn.clicked.connect(self.change_window_size)def set_min_button(self, btn: QToolButton or QPushButton):btn.clicked.connect(self.showMinimized)def set_close_button(self, btn: QToolButton or QPushButton):btn.clicked.connect(self.close)'''以下重写窗口拖拽事件'''def resizeEvent(self, QResizeEvent):# 获取有效识别区域self.right_l = self.width() - self._paddingself.right_r = self.width() + 1self.bottom_u = self.height() - self._paddingself.bottom_d = self.height() + 1# # 识别区域# print('x识别区间:', self.right_l, ',', self.right_r)# print('y识别区间:', self.bottom_u, ',', self.bottom_d)def get_mouse_pos_of_window(self) -> QPoint:global_pos = QCursor.pos()window_pos = self.mapFromGlobal(global_pos)return window_posdef get_mouse_global_pos(self) -> QPoint:return QCursor.pos()def check_pos_status(self):'''获取鼠标相对于窗口的坐标,根据鼠标所处的位置返回鼠标的状态'''pos: QPoint = self.get_mouse_pos_of_window()if pos.x() >= self.right_l and pos.x() < self.right_r:if pos.y() >= 0:if pos.y() <= self.bottom_u:return pos, "right"# 右边界elif pos.y() < self.bottom_d:return pos, "corner"# 右下角if pos.y() >= self.bottom_u and pos.y() < self.bottom_d:if pos.x() >= 0:if pos.x() <= self.right_l:return pos, 'bottom'# 下边界if pos.x() >= 0 and pos.x() <= self.right_l and pos.y() >= 0 and pos.y() <= self.titleHeight:return pos, 'title'return pos, Falsedef start_cursorUpdater(self):'''启动计时器更新鼠标样式'''if self.timer_cursorUpdater:self.timer_cursorUpdater.timeout.connect(self.update_cursor)self.timer_cursorUpdater.start(100)# 每隔1秒触发一次鼠标移动事件def stop_cursorUpdater(self):'''停止计时器更新鼠标样式'''if self.timer_cursorUpdater:self.timer_cursorUpdater.stop()def update_cursor(self):'''根据鼠标坐标获取状态,设定鼠标样式'''pos, status = self.check_pos_status()if status is False:self.setCursor(Qt.ArrowCursor)elif status == 'right':self.setCursor(Qt.SizeHorCursor)elif status == 'bottom':self.setCursor(Qt.SizeVerCursor)elif status == 'corner':self.setCursor(Qt.SizeFDiagCursor)else:self.setCursor(Qt.ArrowCursor)def change_window_size(self):if not self.isMaximized():self.showMaximized()self.stop_cursorUpdater()elif self.isMaximized():self.showNormal()self.start_cursorUpdater()return self.isMaximized()def mousePressEvent(self, event: QMouseEvent):self.is_mousePressed = Trueself.mouse_pos = self.get_mouse_global_pos()def mouseReleaseEvent(self, event: QMouseEvent):self.is_mousePressed = Falseself.is_resizing = Falsedef mouseDoubleClickEvent(self, *args, **kwargs):'''检测标题栏的双击状态,切换最大化与正常窗口'''if self.check_pos_status()[1] == 'title' and self.support_double_max:self.change_window_size()def mouseMoveEvent(self, event: QMouseEvent):if self.is_resizing:pos = self.get_mouse_pos_of_window()if self.resize_direction == 'right' and self.support_resize:self.resize(pos.x(), self.height())elif self.resize_direction == 'down' and self.support_resize:self.resize(self.width(), pos.y())elif self.resize_direction == 'right-down' and self.support_resize:self.resize(pos.x(), pos.y())elif self.resize_direction == 'move':current_pos = self.get_mouse_global_pos()self.move(self.pos() + current_pos - self.mouse_pos)self.mouse_pos = current_poselse:if self.is_mousePressed:pos, status = self.check_pos_status()if status is False:self.is_resizing = Falseif status == 'right':# self.resize(pos.x(), self.height())self.is_resizing = Trueself.resize_direction = 'right'elif status == 'bottom':self.is_resizing = Trueself.resize_direction = 'down'elif status == 'corner':self.is_resizing = Trueself.resize_direction = 'right-down'elif status == 'title':self.is_resizing = Trueself.resize_direction = 'move'def hideEvent(self, *args, **kwargs):self.stop_cursorUpdater()def showEvent(self, *args, **kwargs):if self.support_resize:self.start_cursorUpdater()