![91ff871763503f38cab89111933d3dc1.png](https://img-blog.csdnimg.cn/img_convert/91ff871763503f38cab89111933d3dc1.png)
如何创建不规则窗口
在一些应用中,使用不规则的窗口会使应用外观显得更有个性,更符合应用所要表达的功能特点,比如一个炫酷的播放器,一个圆形的模拟时钟等。在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 sysfrom PyQt5.QtCore import Qt, QPoint, QSize, QTime, QTimerfrom PyQt5.QtGui import QColor, QPainter, QPolygon, QRegion, QPainterPathfrom 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('使用鼠标左键拖动时钟。' '使用鼠标右键打开上下文菜单。') 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())
运行结果如下图:
![9a7e9c40094cc72f7ceeed9edf20caa1.gif](https://img-blog.csdnimg.cn/img_convert/9a7e9c40094cc72f7ceeed9edf20caa1.gif)
不规则窗口:圆盘时钟
本文知识点
- setMask()两种方式实现不规则窗口的绘制;
- QPainter的空间变换函数translate, scale, rotate的使用方法;
- 无边框窗口移动功能的实现;
- 使用QPainterPath绘制填充的圆角矩形。
喜欢本文内容就多多关注,评论,收藏,点赞,和转发。