实战PyQt5: 108-创建不规则窗口

如何创建不规则窗口

在一些应用中,使用不规则的窗口会使应用外观显得更有个性,更符合应用所要表达的功能特点,比如一个炫酷的播放器,一个圆形的模拟时钟等。在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())

运行结果如下图:

实战PyQt5: 108-创建不规则窗口

不规则窗口:圆盘时钟

本文知识点

  • setMask()两种方式实现不规则窗口的绘制;
  • QPainter的空间变换函数translate, scale, rotate的使用方法;
  • 无边框窗口移动功能的实现;
  • 使用QPainterPath绘制填充的圆角矩形。

前一篇: 实战PyQt5: 107-设置窗口背景

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值