PyQt5 使用 QLabel 实现图像 360度 不间断旋转

PyQt5 使用 QLabel 实现图像 360度 不间断旋转

当我们需要实现让一个图像 360度 旋转时,比如:音乐播放器中播放时,歌曲封面的旋转效果,你可以尝试使用下面的方法

代码结构

本文中全部代码全在test_QLabel_whirling.py这一个文件中编码,步骤中有变动的地方会注释标注,无改动的不会重复显示出来,需要看完整代码的,可直接移步到末尾。

一. 创建测试页面

创建一个测试页面,其中主要是放置了2个QLabel,一个QProgressBar,其中一个QLabel,用于实现图像旋转

#!/usr/bin/env python3
# -*- coding: UTF-8 -*-
"""
@ File        : test_QLabel_whirling.py
@ Author      : yqbao
@ Version     : V1.0.0
@ Description : 图像 360 度旋转
"""
from PyQt5.QtGui import QMovie
from PyQt5.QtWidgets import QApplication, QLabel, QWidget, QGridLayout, QFrame, QProgressBar
from PyQt5.QtGui import QPixmap, QTransform
from PyQt5.QtCore import QTimer, Qt, QMetaObject, QCoreApplication


class Ui_Whirling(object):
    def setupUi(self, Form):
        Form.setObjectName("Form")
        Form.resize(712, 76)
        self.gridLayout_2 = QGridLayout(Form)
        self.gridLayout_2.setObjectName("gridLayout_2")

        # 创建一个 QFrame,用于放置其余组件
        self.frame = QFrame(Form)
        self.frame.setFrameShape(QFrame.StyledPanel)
        self.frame.setFrameShadow(QFrame.Raised)
        self.frame.setObjectName("frame")

        # 网格布局
        self.gridLayout = QGridLayout(self.frame)
        self.gridLayout.setObjectName("gridLayout")

        # 创建一个 QLabel,其实这个没啥用
        self.label_2 = QLabel(self.frame)
        self.label_2.setObjectName("label_2")
        self.gridLayout.addWidget(self.label_2, 0, 1, 1, 1)

        # 创建一个 QProgressBar,其实这个没啥用
        self.progressBar = QProgressBar(self.frame)
        self.progressBar.setProperty("value", 24)
        self.progressBar.setObjectName("progressBar")
        self.gridLayout.addWidget(self.progressBar, 1, 1, 1, 1)

        # 创建一个 QLabel,用于实现图片旋转
        self.label = QLabel(self.frame)
        self.label.setObjectName("label")
        self.gridLayout.addWidget(self.label, 0, 0, 2, 1)

        self.gridLayout_2.addWidget(self.frame, 0, 0, 1, 1)

        self.retranslateUi(Form)
        QMetaObject.connectSlotsByName(Form)

    def retranslateUi(self, Form):
        _translate = QCoreApplication.translate
        Form.setWindowTitle(_translate("Form", "图片 360° 旋转"))
        self.label_2.setText(_translate("Form", "<<--- 左侧图片 360° 旋转"))
        self.label.setText(_translate("Form", "图片"))


class GIFRotatingLabel(QWidget, Ui_Whirling):
    def __init__(self):
        super().__init__()
        self.setupUi(self)


if __name__ == "__main__":
    import sys

    app = QApplication(sys.argv)
    w = GIFRotatingLabel()
    w.show()
    sys.exit(app.exec_())

测试页面如图:
image

二. 实现方式

方式一:直接使用一个 旋转的gif实现

这种方式代码量最小,如这样的gif图,用QMovie 来实现 QLabel 中图像的 360度 旋转效果
image

#!/usr/bin/env python3
# -*- coding: UTF-8 -*-
"""
@ File        : test_QLabel_whirling.py
@ Author      : yqbao
@ Version     : V1.0.0
@ Description : 图像 360 度旋转
"""

class Ui_Whirling(object):
    ...  # 忽略,无改动


class GIFRotatingLabel(QWidget, Ui_Whirling):
    """GIF实现"""

    def __init__(self):
        super().__init__()
        self.setupUi(self)

        movie = QMovie(r"image\34.gif")  # 替换为你的图像路径
        self.label.setMovie(movie)
        movie.start()

效果如下,此效果图中的抖动是截图导致的,实际是平滑的:
image

方式二:使用QTransform重新创建对象并应用

我们使用 QTimer 定期调用 rotate_image 方法来更新图像的旋转角度。每次调用时,创建一个新的 QTransform 对象并应用旋转,然后更新 QLabel 中的图像。调整定时器的间隔和角度增量,就可以改变旋转速度。

代码中使用的create_rounded_pixmap方法,是将正方形图片通过设置圆角的方式,修改为圆形,具体代码详情看这里

#!/usr/bin/env python3
# -*- coding: UTF-8 -*-
"""
@ File        : test_QLabel_whirling.py
@ Author      : yqbao
@ Version     : V1.0.0
@ Description : 图像 360 度旋转
"""

class Ui_Whirling(object):
    ...  # 忽略,无改动


class RotatingLabel(QWidget, Ui_Whirling):
    """QTransform"""

    def __init__(self):
        super().__init__()
        self.setupUi(self)

        pixmap = QPixmap(r'image\20.png')  # 替换为你的图像路径,且必须是正方形

        # 创建圆形图像
        self.rounded_pixmap = create_rounded_pixmap(pixmap, pixmap.height() / 2)
        self.label.setPixmap(self.rounded_pixmap)  # 设置图像

        self.label.setFixedSize(pixmap.width(), pixmap.height())  # 设置 QLabel 的固定大小
        self.label.setAlignment(Qt.AlignCenter)  # 中心对齐

        self.angle = 0  # 初始角度

        # 创建定时器
        self.timer = QTimer(self)
        self.timer.timeout.connect(self.rotate_image)
        self.timer.start(10)  # 每10毫秒更新一次

    def rotate_image(self):
        self.angle = (self.angle + 1) % 360  # 每次增加1度
        # transform = QTransform().rotate(self.angle)
        # 始终保持几何中心旋转
        transform = QTransform().translate(self.rounded_pixmap.width() / 2, self.rounded_pixmap.height() / 2) \
            .rotate(self.angle) \
            .translate(-self.rounded_pixmap.width() / 2, -self.rounded_pixmap.height() / 2)
        rotated_pixmap = self.rounded_pixmap.transformed(transform, mode=1)  # 使用平滑缩放
        self.label.setPixmap(rotated_pixmap)

效果如下,此效果图中的抖动是截图导致的,实际是平滑的:
image

四. 完整代码

使用时,只使用self.label相关的设置即可,完整代码如下:

#!/usr/bin/env python3
# -*- coding: UTF-8 -*-
"""
@ File        : test_QLabel_whirling.py
@ Author      : yqbao
@ Version     : V1.0.0
@ Description : 图像 360 度旋转
"""
from PyQt5.QtGui import QMovie
from PyQt5.QtWidgets import QApplication, QLabel, QWidget, QGridLayout, QFrame, QProgressBar
from PyQt5.QtGui import QPixmap, QTransform
from PyQt5.QtCore import QTimer, Qt, QMetaObject, QCoreApplication

from lib.rounded_pixmap import create_rounded_pixmap


class Ui_Whirling(object):
    def setupUi(self, Form):
        Form.setObjectName("Form")
        Form.resize(712, 76)
        self.gridLayout_2 = QGridLayout(Form)
        self.gridLayout_2.setObjectName("gridLayout_2")

        # 创建一个 QFrame,用于放置其余组件
        self.frame = QFrame(Form)
        self.frame.setFrameShape(QFrame.StyledPanel)
        self.frame.setFrameShadow(QFrame.Raised)
        self.frame.setObjectName("frame")

        # 网格布局
        self.gridLayout = QGridLayout(self.frame)
        self.gridLayout.setObjectName("gridLayout")

        # 创建一个 QLabel,其实这个没啥用
        self.label_2 = QLabel(self.frame)
        self.label_2.setObjectName("label_2")
        self.gridLayout.addWidget(self.label_2, 0, 1, 1, 1)

        # 创建一个 QProgressBar,其实这个没啥用
        self.progressBar = QProgressBar(self.frame)
        self.progressBar.setProperty("value", 24)
        self.progressBar.setObjectName("progressBar")
        self.gridLayout.addWidget(self.progressBar, 1, 1, 1, 1)

        # 创建一个 QLabel,用于实现图片旋转
        self.label = QLabel(self.frame)
        self.label.setObjectName("label")
        self.gridLayout.addWidget(self.label, 0, 0, 2, 1)

        self.gridLayout_2.addWidget(self.frame, 0, 0, 1, 1)

        self.retranslateUi(Form)
        QMetaObject.connectSlotsByName(Form)

    def retranslateUi(self, Form):
        _translate = QCoreApplication.translate
        Form.setWindowTitle(_translate("Form", "图片 360° 旋转"))
        self.label_2.setText(_translate("Form", "<<--- 左侧图片 360° 旋转"))
        self.label.setText(_translate("Form", "图片"))


class GIFRotatingLabel(QWidget, Ui_Whirling):
    """GIF实现"""

    def __init__(self):
        super().__init__()
        self.setupUi(self)

        movie = QMovie(r"image\34.gif")  # 替换为你的图像路径
        self.label.setMovie(movie)
        movie.start()


class RotatingLabel(QWidget, Ui_Whirling):
    """QTransform"""

    def __init__(self):
        super().__init__()
        self.setupUi(self)

        pixmap = QPixmap(r'image\20.png')  # 替换为你的图像路径,且必须是正方形

        # 创建圆形图像
        self.rounded_pixmap = create_rounded_pixmap(pixmap, pixmap.height() / 2)
        self.label.setPixmap(self.rounded_pixmap)  # 设置图像

        self.label.setFixedSize(pixmap.width(), pixmap.height())  # 设置 QLabel 的固定大小
        self.label.setAlignment(Qt.AlignCenter)  # 中心对齐

        self.angle = 0  # 初始角度

        # 创建定时器
        self.timer = QTimer(self)
        self.timer.timeout.connect(self.rotate_image)
        self.timer.start(10)  # 每10毫秒更新一次

    def rotate_image(self):
        self.angle = (self.angle + 1) % 360  # 每次增加1度
        # transform = QTransform().rotate(self.angle)
        # 始终保持几何中心旋转
        transform = QTransform().translate(self.rounded_pixmap.width() / 2, self.rounded_pixmap.height() / 2) \
            .rotate(self.angle) \
            .translate(-self.rounded_pixmap.width() / 2, -self.rounded_pixmap.height() / 2)
        rotated_pixmap = self.rounded_pixmap.transformed(transform, mode=1)  # 使用平滑缩放
        self.label.setPixmap(rotated_pixmap)


if __name__ == '__main__':
    import sys

    app = QApplication(sys.argv)
    window = RotatingLabel()
    # window = GIFRotatingLabel()
    window.show()
    sys.exit(app.exec_())


本文章的原文地址
GitHub主页

posted @ 2024-10-08 18:05  星尘的博客  阅读(1)  评论(0编辑  收藏  举报