PyQt/Demo/NewFramelessWindow.py

176 lines
5.9 KiB
Python
Raw Normal View History

2021-04-21 22:58:30 +08:00
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
Created on 2018年4月30日
@author: Irony
@site: https://pyqt.site , https://github.com/PyQt5
@email: 892768447@qq.com
@file: NewFramelessWindow
@description:
"""
from Lib.ui_frameless import Ui_FormFrameless
from PyQt5.QtCore import QTimer, Qt, QEvent, QObject
from PyQt5.QtGui import QWindow, QPainter, QPen, QColor
from PyQt5.QtWidgets import QApplication, QWidget, QMessageBox
class FramelessObject(QObject):
@staticmethod
def _get_edges(pos):
"""根据坐标获取方向
:param pos: QPoint
:return: Qt::Edges
"""
edge = 0
x, y = pos.x(), pos.y()
widget = QApplication.instance().activeWindow()
if not widget:
return edge
left, top, right, bottom = widget.layout().getContentsMargins()
if y <= top:
edge |= Qt.TopEdge
if x <= left:
edge |= Qt.LeftEdge
if x >= widget.width() - right:
edge |= Qt.RightEdge
if y >= widget.height() - bottom:
edge |= Qt.BottomEdge
return edge
@staticmethod
def _adjust_cursor(edges):
"""调整鼠标样式
:param edges: int or None
"""
# print('edges', edges)
widget = QApplication.instance().activeWindow()
if not widget:
return
if edges == Qt.LeftEdge | Qt.TopEdge or edges == Qt.RightEdge | Qt.BottomEdge:
widget.setCursor(Qt.SizeFDiagCursor)
elif edges == Qt.RightEdge | Qt.TopEdge or edges == Qt.LeftEdge | Qt.BottomEdge:
widget.setCursor(Qt.SizeBDiagCursor)
elif edges == Qt.LeftEdge or edges == Qt.RightEdge:
widget.setCursor(Qt.SizeHorCursor)
elif edges == Qt.TopEdge or edges == Qt.BottomEdge:
widget.setCursor(Qt.SizeVerCursor)
else:
widget.setCursor(Qt.ArrowCursor)
def eventFilter(self, obj, event):
# 鼠标移动改变光标
if event.type() == QEvent.MouseMove:
widget = QApplication.instance().activeWindow()
if widget and event.buttons() == Qt.NoButton and not (
widget.isMaximized() or widget.isFullScreen()):
# 鼠标移动变更光标样式
# print('MouseMove', event.pos())
self._adjust_cursor(self._get_edges(event.pos()))
if event.type() == QEvent.MouseButtonPress and obj.objectName() == 'FramelessWindow':
# 鼠标按下
edges = self._get_edges(event.pos())
# 标题栏高度
try:
height = obj.titleHeight()
except AttributeError:
height = 36
# 优先判断边缘
widget = QApplication.instance().activeWindow()
if edges != 0 and not (widget.isMaximized() or widget.isFullScreen()):
# 按下窗口边缘边距位置
self._adjust_cursor(edges)
# 交给系统去调整大小
print('startSystemResize')
obj.windowHandle().startSystemResize(edges)
elif event.y() <= height:
# 标题栏交给系统去移动
print('startSystemMove')
obj.windowHandle().startSystemMove()
elif event.type() == QEvent.MouseButtonRelease:
# 鼠标释放
self._adjust_cursor(None)
return False
class FramelessWindow(QWidget, Ui_FormFrameless):
def __init__(self, *args, **kwargs):
super(FramelessWindow, self).__init__(*args, **kwargs)
self.setupUi(self)
self.setObjectName('FramelessWindow') # 过滤器中的名字一致
# 无边框
self.setWindowFlags(self.windowFlags() | Qt.FramelessWindowHint)
self.setAttribute(Qt.WA_TranslucentBackground, True)
self.setMouseTracking(True)
# 隐藏还原按钮
self.buttonNormal.setVisible(False)
# 标题栏按钮信号
self.buttonMinimum.clicked.connect(self.showMinimized)
self.buttonMaximum.clicked.connect(self.showMaximized)
self.buttonNormal.clicked.connect(self.showNormal)
self.buttonClose.clicked.connect(self.close)
self.setStyleSheet('#widgetTitleBar{background: rgb(232, 232, 232);}')
def titleHeight(self):
"""标题栏高度
:return: int
"""
return self.widgetTitleBar.height()
def mouseDoubleClickEvent(self, event):
"""双击最大化还原
:param event: QMouseEvent
"""
if self.isMaximized():
self.showNormal()
else:
self.showMaximized()
event.accept()
def changeEvent(self, event):
"""窗口状态改变
:param event:
"""
super(FramelessWindow, self).changeEvent(event)
# 窗口状态改变时修改标题栏控制按钮
visible = self.isMaximized()
self.buttonMaximum.setVisible(not visible)
self.buttonNormal.setVisible(visible)
if visible:
self.layout().setContentsMargins(0, 0, 0, 0)
else:
# TODO 与UI文件中的布局边距一致
self.layout().setContentsMargins(3, 3, 3, 3)
def paintEvent(self, event):
# 透明背景但是需要留下一个透明度用于鼠标捕获
painter = QPainter(self)
painter.fillRect(self.rect(), QColor(255, 255, 255, 1))
if __name__ == '__main__':
import sys
import cgitb
cgitb.enable(format='text')
app = QApplication(sys.argv)
if not hasattr(QWindow, 'startSystemMove'):
QWindow.startSystemResize()
# 不支持
QMessageBox.critical(None, '错误', '当前Qt版本不支持该例子')
QTimer.singleShot(100, app.quit)
else:
# 安装全局事件过滤器
fo = FramelessObject()
app.installEventFilter(fo)
w = FramelessWindow()
w.show()
sys.exit(app.exec_())