切换按钮动画在 PyQt 中不起作用?

Toggle button animation not working in PyQt?

我正在关注有关创建动画切换按钮的 YouTube 教程。这是代码,但它不起作用。我想 @property 有问题,但我不确定。

import sys
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *

class ToggleButton(QCheckBox):
    def __init__(self, 
        width = 70, 
        bgColor = '#777', 
        circleColor = '#DDD', 
        activeColor = '#00BCff', 
        animationCurve = QEasingCurve.OutBounce
    ):
        QCheckBox.__init__(self)
        self.setFixedSize(width, 40)
        self.setCursor(Qt.PointingHandCursor)

        self._bg_color = bgColor
        self._circle_color = circleColor
        self._active_color = activeColor
        self._circle_position = 3
        self.animation = QPropertyAnimation(self, b"circle_position")
        self.animation.setEasingCurve(animationCurve)
        self.animation.setDirection(500)
        self.stateChanged.connect(self.start_transition)

    @property
    def circle_position(self):
        return self._circle_position

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

    def start_transition(self, value):
        print(self.isChecked())
        self.animation.stop()
        if value:
            self.animation.setEndValue(self.width() - 26)
        else:
            self.animation.setEndValue(3)

        self.animation.start()

    def hitButton(self, pos: QPoint):
        return self.contentsRect().contains(pos)


    def paintEvent(self, e):
        p = QPainter(self)
        p.setRenderHint(QPainter.Antialiasing)

        p.setPen(Qt.NoPen)

        rect = QRect(0, 0, self.width(), self.height())

        if not self.isChecked():
            p.setBrush(QColor(self._bg_color))
            p.drawRoundedRect(0, 0, rect.width(), self.height(), self.height() / 2, self.height() / 2)

            p.setBrush(QColor(self._circle_color))
            p.drawEllipse(self._circle_position, 3, 32, 32)
        
        else:
            p.setBrush(QColor(self._active_color))
            p.drawRoundedRect(0, 0, rect.width(), self.height(), self.height() / 2, self.height() / 2)

            p.setBrush(QColor(self._circle_color))
            p.drawEllipse(self._circle_position, 3, 32, 32)

        p.end()


class window(QMainWindow):
   def __init__(self, parent = None):
      super(window, self).__init__(parent)
      self.resize(500,500)
      self.setWindowTitle("PyQt5")
      self.toggleBtn = ToggleButton()
      self.container = QFrame()
      self.layout = QVBoxLayout()
      self.layout.addWidget(self.toggleBtn, Qt.AlignCenter, Qt.AlignCenter)
      self.container.setLayout(self.layout)
      self.setCentralWidget(self.container)


def main():
   app = QApplication(sys.argv)
   ex = window()
   ex.show()
   sys.exit(app.exec_())

if __name__ == '__main__':
   main()

感谢您的帮助

如果您 运行 代码,您将收到以下警告:

QPropertyAnimation: you're trying to animate a non-existing property circle_position of your QObject

QPropertyAnimation 仅适用于 Qt 属性,不适用于 python 属性,因此它会失败,我们会收到该警告。此外,在处理过渡时还有其他错误,还有一个错字,因为使用了方向而不是持续时间。

class ToggleButton(QCheckBox):
    def __init__(
        self,
        width=70,
        bgColor="#777",
        circleColor="#DDD",
        activeColor="#00BCff",
        animationCurve=QEasingCurve.OutBounce,
    ):
        QCheckBox.__init__(self)
        self.setFixedSize(width, 40)
        self.setCursor(Qt.PointingHandCursor)

        self._bg_color = bgColor
        self._circle_color = circleColor
        self._active_color = activeColor
        self._circle_position = 3
        self.animation = QPropertyAnimation(self, b"circle_position")

        self.animation.setEasingCurve(animationCurve)
        self.animation.setDuration(500)
        self.stateChanged.connect(self.start_transition)

    @pyqtProperty(int)
    def circle_position(self):
        return self._circle_position

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

    def start_transition(self, value):
        self.animation.setStartValue(self.circle_position)
        if value:
            self.animation.setEndValue(self.width() - 35)
        else:
            self.animation.setEndValue(3)
        self.animation.start()

    def hitButton(self, pos: QPoint):
        return self.contentsRect().contains(pos)

    def paintEvent(self, e):
        p = QPainter(self)
        p.setRenderHint(QPainter.Antialiasing)

        p.setPen(Qt.NoPen)

        rect = QRect(0, 0, self.width(), self.height())

        if not self.isChecked():
            p.setBrush(QColor(self._bg_color))
            p.drawRoundedRect(
                0, 0, rect.width(), self.height(), self.height() / 2, self.height() / 2
            )

            p.setBrush(QColor(self._circle_color))
            p.drawEllipse(self._circle_position, 3, 32, 32)
        else:
            p.setBrush(QColor(self._active_color))
            p.drawRoundedRect(
                0, 0, rect.width(), self.height(), self.height() / 2, self.height() / 2
            )

            p.setBrush(QColor(self._circle_color))
            p.drawEllipse(self._circle_position, 3, 32, 32)