如何创建不规则窗口
在一些应用中,使用不规则的窗口会使应用外观显得更有个性,更符合应用所要表达的功能特点,比如一个炫酷的播放器,一个圆形的模拟时钟等。在QWidget中提供函数setMask()可以方便地实现不规则窗口的功能。
setMask()的作用是为调用它的Widget增加一个遮罩,在遮罩所选区域之外的部分是透明的,Widget显示出来的区域就是遮罩所控制的区域。setMask()有两种形式:
- setMask(self, rgn: QRegiom), 它使用一个QRegion对象来确定遮罩区域。
- setMask(self, bmp: QBitmap), 它是一个QBitmap对象,其中像素值为0的部分表示是透明的,在实际使用中,常常使用QPixmap.mask()函数从一个PNG格式的图像中的透明度部分获得遮罩。
实现一个不规则窗口的大致步骤是:
1. 创建一个窗口,并将其设置成无边框模式
2. 使用setMask方法设置遮罩
3. 重载其mousePressEvent()和mouseMoveEvent()方法实现对窗口的移动操作
4. 重载paintEvent()方法实现窗口的绘制
测试代码
在PyQt样例代码shapedclock.py的基础上,实现一个圆形的模拟时钟,在时钟绘制上,增添了秒针支持。 完整代码如下:
import sys
from PyQt5.QtCore import Qt, QPoint, QSize, QTime, QTimer
from PyQt5.QtGui import QColor, QPainter, QPolygon, QRegion, QPainterPath
from PyQt5.QtWidgets import QAction, QApplication, QWidget
class MyShapedClock(QWidget):
#时针形状
hourHand = QPolygon([
QPoint(7, 8),
QPoint(-7, 8),
QPoint(0, -40)
])
#分针形状
minuteHand = QPolygon([
QPoint(7, 8),
QPoint(-7, 8),
QPoint(0, -70)
])
#时针颜色
hourColor = QColor(127, 0, 127)
minuteColor = QColor(0, 127, 127, 191)
secondColor = QColor(255, 0, 0, 191)
def __init__(self, parent=None):
#创建一个无边框的窗口
super(MyShapedClock, self).__init__(parent, Qt.FramelessWindowHint | Qt.WindowSystemMenuHint)
# 设置窗口标题
self.setWindowTitle('实战PyQt5: 圆形模拟时针')
#定时器,每秒刷新
timer = QTimer(self)
timer.timeout.connect(self.update)
timer.start(1000)
#右键退出菜单
aQuit = QAction('退出(&X)', self, shortcut='Ctrl+Q',
triggered=QApplication.instance().quit)
self.addAction(aQuit)
self.setContextMenuPolicy(Qt.ActionsContextMenu)
self.setToolTip('使用鼠标左键拖动时钟。\n'
'使用鼠标右键打开上下文菜单。')
def mousePressEvent(self, event):
if event.button() == Qt.LeftButton:
#计算拖动位置
self.dragPosition = event.globalPos() - self.frameGeometry().topLeft()
event.accept()
def mouseMoveEvent(self, event):
if event.buttons() == Qt.LeftButton:
#移动时钟
self.move(event.globalPos() - self.dragPosition)
event.accept()
def paintEvent(self, event):
side = min(self.width(), self.height())
time = QTime.currentTime()
painter = QPainter(self)
#启动抗锯齿操作
painter.setRenderHint(QPainter.Antialiasing)
#平移到窗口中心点
painter.translate(self.width()/2, self.height()/2)
#缩放比例
painter.scale(side / 200.0, side / 200.0)
#==== 绘制时针 ====#
painter.setPen(Qt.NoPen)
painter.setBrush(MyShapedClock.hourColor)
painter.save()
#旋转时针到正确位置
painter.rotate(30.0 * ((time.hour() + time.minute() / 60.0)))
painter.drawConvexPolygon(MyShapedClock.hourHand)
painter.restore()
#==== 绘制小时刻度 ====#
painter.setPen(MyShapedClock.hourColor)
for i in range(12):
painter.drawLine(88, 0, 96, 0)
painter.rotate(30.0)
#==== 绘制分针 ====#
painter.setPen(Qt.NoPen)
painter.setBrush(MyShapedClock.minuteColor)
painter.save()
painter.rotate(6.0 * (time.minute() + time.second() / 60.0))
painter.drawConvexPolygon(MyShapedClock.minuteHand)
painter.restore()
#==== 绘制分针刻度 ====#
painter.setPen(MyShapedClock.minuteColor)
for j in range(60):
if(j % 5) != 0:
painter.drawLine(94, 0, 96, 0)
painter.rotate(6.0)
#==== 绘制秒针 ====#
painter.setPen(Qt.NoPen)
painter.setBrush(MyShapedClock.secondColor)
painter.drawEllipse(-4, -4, 8, 8)
path = QPainterPath()
path.addRoundedRect(-1, -1, 80, 2, 1, 1)
painter.save()
painter.rotate(6.0 * time.second())
painter.fillPath(path, MyShapedClock.secondColor)
painter.restore()
def resizeEvent(self, event):
w = self.width()
h = self.height()
side = min(w, h)
#为窗口设置一个圆形遮罩
maskedRegion = QRegion(w/2 - side/2, h/2 - side/2, side, side, QRegion.Ellipse)
#关键函数!!!!!!
self.setMask(maskedRegion)
def sizeHint(self):
return QSize(320, 320)
if __name__ == '__main__':
app = QApplication(sys.argv)
windows = MyShapedClock()
windows.show()
sys.exit(app.exec())
运行结果如下图:
不规则窗口:圆盘时钟
本文知识点
- setMask()两种方式实现不规则窗口的绘制;
- QPainter的空间变换函数translate, scale, rotate的使用方法;
- 无边框窗口移动功能的实现;
- 使用QPainterPath绘制填充的圆角矩形。
前一篇: 实战PyQt5: 107-设置窗口背景