PySide2:利用checkBox+QPropertyAnimation实现开关UI

Qt QPropertyAnimation

官方说明

QPropertyAnimation interpolates over Qt properties. As property values are stored in QVariants, the class inherits QVariantAnimation, and supports animation of the same meta types as its super class.
A class declaring properties must be a QObject. To make it possible to animate a property, it must provide a setter (so that QPropertyAnimation can set the property’s value). Note that this makes it possible to animate many of Qt’s widgets.
原文链接

QPropertyAnimation 对 Qt 属性进行插值。由于属性值存储在 QVariants(PySide 中不支持 QVariant 类型)中,因此该类继承了 QVariantAnimation,并支持与其超类相同的元类型动画。
声明属性的类必须是 QObject。为使属性动画成为可能,它必须提供一个设置器(以便 QPropertyAnimation 可以设置属性的值)。这使得许多 Qt 小工具的动画成为可能。
简单来说,利用 QPropertyAnimation 来制作一些小动画(类似前端),比如一些单点开关(在 Qt 中并没有对应支持,qtWidget 第三方库支持,本文章利用 QPropertyAnimation 动画实现)。
关闭状态
开启状态

参数

QPropertyAnimation(self, target: PySide2.QtCore.QObject, propertyName: PySide2.QtCore.QByteArray, parent: typing.Union[PySide2.QtCore.QObject, NoneType] = None) -> None

target:需要实现的动画对象
property:给该动画设置的属性名称(可利用该方法来设置动画位置)
parent:父类对象

其他关于 QPropertyAnimation 的相关参数可在官方文档中查阅

实例

这里实现的动画效果只是普通的直线效果,需要其他效果可以更改animation_curve属性

import PySide2
from PySide2.QtCore import Qt, QRect, QPropertyAnimation, QEasingCurve, Property
from PySide2.QtGui import QPainter, QColor
from PySide2.QtWidgets import  QCheckBox


class RToggleSwitch(QCheckBox):
    def __init__(
            self,
            width: int = 70,
            button_height: int = 28,
            bg_color: str = "#777",
            circle_color: str = "#000",
            active_color: str = "00BCff",

            # Change animations here: 按钮动画
            animation_curve=QEasingCurve.Custom
            # Change the Bouncing of Round Ball
    ):
        QCheckBox.__init__(self)

        # Set Detail Paramenter: 设置详细数据
        self.setFixedSize(width, button_height)
        self.setCursor(Qt.PointingHandCursor)

        # Color
        self._bg_color = bg_color  # Background Color: 背景颜色
        self._circle_color = circle_color  # Circle Color: 圆圈颜色
        self._active_color = active_color  # Active Color: 选中颜色

        # Create Animation: 创建动画事件
        self._circle_to_border = 4  # Circle Border: 圆圈默认距边框位置
        self._circle_position = 4  # Circle position: 圆圈目前所处位置,由 Qt.Property 控制
        self.animation = QPropertyAnimation(self, b"circle_position", self)
        self.animation.setEasingCurve(animation_curve)

        # Duration of Button Transition: 按钮转换的持续时间
        self.animation.setDuration(300)

        # Connect State Changed
        self.stateChanged.connect(self.start_transition)

    @Property(float)
    def circle_position(self):
        return self._circle_position

    @circle_position.setter
    def circle_position(self, pos_x: int):
        self._circle_position = pos_x
        self.update()

    @property
    def _circle_diameter(self):
        return self.height() - (self._circle_to_border * 2)

    def start_transition(self, state: bool):
        """
        利用按钮状态改变来定义动画滑动
        Args:
            state: bool

        Returns:

        """
        # Stop animation
        self.animation.stop()
        if state:
            # Circle animation left to right
            _circle_position = self.height() - self._circle_to_border
            self.animation.setEndValue(self.width() - _circle_position)
        else:
            # Circle animation right to left
            self.animation.setEndValue(self._circle_to_border)

        # Start animation
        self.animation.start()

    def hitButton(self, pos: PySide2.QtCore.QPoint) -> bool:
        """
        设置 Nes 的命中区域
        Args:
            pos:

        Returns:

        """
        return self.contentsRect().contains(pos)

    def paintEvent(self, event: PySide2.QtGui.QPaintEvent) -> None:
        rect = QRect(0, 0, self.width(), self.height())
        painter = QPainter(self)
        # setting anti-aliasing
        painter.setRenderHint(QPainter.Antialiasing)
        # Unchecked
        if not self.isChecked():

            # SET Background for night mode here
            painter.setBrush((QColor("#D9D9D9")))
            painter.setPen(Qt.NoPen)
            painter.drawRoundedRect(0, 0,
                                    rect.width(),
                                    self.height(),
                                    self.height() / 2,
                                    self.height() / 2)
            # Set Circle here
            painter.setBrush(QColor("#3B3B3B"))
            painter.drawEllipse(self._circle_position,
                                self._circle_to_border,
                                self._circle_diameter,
                                self._circle_diameter)

        else:

            # SET Background for Day mode here
            painter.setBrush(QColor("#188DB1"))
            painter.setPen(Qt.NoPen)
            painter.drawRoundedRect(0, 0,
                                    rect.width(),
                                    self.height(),
                                    self.height() / 2,
                                    self.height() / 2)
            # Set Circle here
            painter.setBrush(QColor("#FFFFFF"))
            painter.drawEllipse(self._circle_position,
                                self._circle_to_border,
                                self._circle_diameter,
                                self._circle_diameter)

:此处的函数装饰器一定要用 Qt 的 Property ,否则无法实现动画效果。
代码测试


import sys
from PySide2.QtWidgets import QApplication, QWidget, QHBoxLayout
class Example(QWidget):
    def __init__(self):
        super().__init__()
        self.initUI()

    def initUI(self):
        self.setLayout(QHBoxLayout())
        switch = RToggleSwitch()
        self.layout().addWidget(switch)
        switch.stateChanged.connect(self.onStateChanged)

    def onStateChanged(self, state):
        if state:
            print("功能已启用")
        else:
            print("功能已关闭")


if __name__ == '__main__':
    app = QApplication(sys.argv)
    ex = Example()
    ex.setGeometry(300, 300, 250, 150)
    ex.setWindowTitle('Toggle Switch')
    ex.show()
    sys.exit(app.exec_())

原文链接:https://github.com/Shumail-Abbasi/Pyqt-Animated-Toggle-Button/blob/main/py_toggle.py

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Ctr+Alt+Del

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值