I’m following a YouTube tutorial on creating animated toggle button. here is the code but it’s not working. I guess there is a problem with @property but I’m not sure.
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.label = ToggleButton()
self.container = QFrame()
self.layout = QVBoxLayout()
self.layout.addWidget(self.label, 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()
Thank you for your help
>Solution :
If you run the code you will get the following warning:
QPropertyAnimation: you're trying to animate a non-existing property circle_position of your QObject
QPropertyAnimation only applies to Qt Properties, not python properties so it fails and we get that warning. In addition there are other errors in the handling of the transition, there is also a typo since instead of using duration direction is used.
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)