PyQt QPropertyAnimation
最后修改于 2023 年 8 月 24 日
在本文中,我们将展示如何使用 QPropertyAnimation
在 PyQt 中创建动画。在示例中,我们将对对象的大小、颜色和位置进行动画处理。
访问 PyQt6 教程,或列出所有 PyQt 教程。
,阅读QPropertyAnimation
QPropertyAnimation
对 PyQt 属性进行插值。声明属性的类*必须*是 QObject
。
QPropertyAnimation 方法
下表显示了一些重要的 QPropertyAnimation
方法。
名称 | 描述 |
---|---|
start | 启动动画 |
stop | 终止动画 |
setStartValue | 设置动画的起始值 |
setEndValue | 设置动画的结束值 |
setDuration | 设置动画的持续时间,单位为毫秒 |
setKeyValueAt | 在给定的步骤创建具有给定值的关键帧 |
setLoopCount | 设置动画的重复次数 |
使用 QPropertyAnimation 对大小进行动画处理
在第一个示例中,我们对一个控件的大小进行动画处理。
#!/usr/bin/python from PyQt6.QtWidgets import QWidget, QApplication, QFrame, QPushButton from PyQt6.QtCore import QRect, QPropertyAnimation import sys class Example(QWidget): def __init__(self): super().__init__() self.initUI() def initUI(self): self.button = QPushButton("Start", self) self.button.clicked.connect(self.doAnim) self.button.move(30, 30) self.frame = QFrame(self) self.frame.setFrameStyle(QFrame.Shape.Panel | QFrame.Shadow.Raised) self.frame.setGeometry(150, 30, 100, 100) self.setGeometry(300, 300, 380, 300) self.setWindowTitle('Animation') self.show() def doAnim(self): self.anim = QPropertyAnimation(self.frame, b"geometry") self.anim.setDuration(10000) self.anim.setStartValue(QRect(150, 30, 100, 100)) self.anim.setEndValue(QRect(150, 30, 200, 200)) self.anim.start() def main(): app = QApplication([]) ex = Example() sys.exit(app.exec()) if __name__ == "__main__": main()
该示例对 QFrame
控件的大小进行动画处理。
self.button = QPushButton("Start", self) self.button.clicked.connect(self.doAnim) self.button.move(30, 30)
动画通过一个 QPushButton
启动。
self.anim = QPropertyAnimation(self.frame, b"geometry")
创建了 QPropertyAnimation
。第一个参数是要进行动画处理的目标对象;在我们的例子中,我们对一个 QFrame
控件进行动画处理。第二个参数是将要改变的属性。
self.anim.setDuration(10000)
setDuration
设置动画的持续时间,单位为毫秒。
self.anim.setStartValue(QRect(150, 30, 100, 100)) self.anim.setEndValue(QRect(150, 30, 200, 200))
通过 setStartValue
和 setEndValue
,我们分别定义动画的起始值和结束值。
self.anim.start()
动画通过 start
方法开始。
使用 QPropertyAnimation 对颜色进行动画处理
下面的示例对一个控件的颜色进行动画处理。由于没有颜色属性,我们必须创建一个。
#!/usr/bin/python from PyQt6.QtWidgets import (QWidget, QApplication, QPushButton, QLabel, QHBoxLayout, QSizePolicy) from PyQt6.QtGui import QColor from PyQt6.QtCore import QPropertyAnimation, pyqtProperty import sys class MyLabel(QLabel): def __init__(self, text): super().__init__(text) def _set_color(self, col): palette = self.palette() palette.setColor(self.foregroundRole(), col) self.setPalette(palette) color = pyqtProperty(QColor, fset=_set_color) class Example(QWidget): def __init__(self): super().__init__() self.initUI() def initUI(self): hbox = QHBoxLayout(self) self.button = QPushButton("Start", self) self.button.setSizePolicy(QSizePolicy.Policy.Fixed, QSizePolicy.Policy.Fixed) hbox.addWidget(self.button) hbox.addSpacing(40) self.label = MyLabel("Summer") font = self.label.font() font.setPointSize(35) self.label.setFont(font) hbox.addWidget(self.label) self.anim = QPropertyAnimation(self.label, b"color") self.anim.setDuration(2500) self.anim.setLoopCount(2) self.anim.setStartValue(QColor(0, 0, 0)) self.anim.setEndValue(QColor(0, 110, 150)) self.button.clicked.connect(self.anim.start) self.setGeometry(300, 300, 380, 250) self.setWindowTitle('Color anim') self.show() def main(): app = QApplication([]) ex = Example() sys.exit(app.exec()) if __name__ == "__main__": main()
该示例逐渐改变 QLabel
的颜色值。
class MyLabel(QLabel): def __init__(self, text): super().__init__(text) def _set_color(self, col): palette = self.palette() palette.setColor(self.foregroundRole(), col) self.setPalette(palette) color = pyqtProperty(QColor, fset=_set_color)
QLabel
没有颜色属性;因此,我们用 pyqtProperty
定义了一个。改变这个属性会更新标签的颜色。
self.anim = QPropertyAnimation(self.label, b"color")
QPropertyAnimation
改变标签控件的 color
属性。
self.anim.setLoopCount(2)
通过 setLoopCount
方法,我们可以改变动画将运行多少次。
self.anim.setStartValue(QColor(0, 0, 0)) self.anim.setEndValue(QColor(0, 110, 150))
我们设置了起始和结束的颜色值。
使用 QPropertyAnimation 沿曲线动画
下面的示例使一个小球沿贝塞尔曲线动画。
#!/usr/bin/python from PyQt6.QtWidgets import QApplication, QWidget, QLabel from PyQt6.QtGui import QPainter, QPixmap, QPainterPath from PyQt6.QtCore import QPoint, QPropertyAnimation, pyqtProperty import sys class Ball(QLabel): def __init__(self, parent): super().__init__(parent) pix = QPixmap("ball.png") self.h = pix.height() self.w = pix.width() self.setPixmap(pix) def _set_pos(self, pos): self.move(pos.x() - self.w//2, pos.y() - self.h//2) pos = pyqtProperty(QPoint, fset=_set_pos) class Example(QWidget): def __init__(self): super().__init__() self.initView() self.initAnimation() def initView(self): self.path = QPainterPath() self.path.moveTo(30, 30) self.path.cubicTo(30, 30, 200, 350, 350, 30) self.ball = Ball(self) self.ball.pos = QPoint(30, 30) self.setWindowTitle("Animation along curve") self.setGeometry(300, 300, 400, 300) self.show() def paintEvent(self, e): qp = QPainter() qp.begin(self) qp.setRenderHint(QPainter.RenderHint.Antialiasing) qp.drawPath(self.path) qp.end() def initAnimation(self): self.anim = QPropertyAnimation(self.ball, b'pos') self.anim.setDuration(7000) self.anim.setStartValue(QPoint(30, 30)) vals = [p/100 for p in range(0, 101)] for i in vals: self.anim.setKeyValueAt(i, self.path.pointAtPercent(i)) self.anim.setEndValue(QPoint(350, 30)) self.anim.start() def main(): app = QApplication(sys.argv) ex = Example() sys.exit(app.exec()) if __name__ == '__main__': main()
该示例在窗口上绘制一条曲线。它使一个小球对象沿着绘制的曲线进行动画。
class Ball(QLabel): def __init__(self, parent): super().__init__(parent) pix = QPixmap("ball.png") self.h = pix.height() self.w = pix.width() self.setPixmap(pix)
小球显示在一个 QLabel
控件中。
def _set_pos(self, pos): self.move(pos.x() - self.w//2, pos.y() - self.h//2) pos = pyqtProperty(QPoint, fset=_set_pos)
我们调整小球的位置;我们希望将标签的中心放在曲线上。
self.path = QPainterPath() self.path.moveTo(30, 30) self.path.cubicTo(30, 30, 200, 350, 350, 30)
贝塞尔曲线是用 QPainterPath
创建的。它的 cubicTo
方法将起点、控制点和终点作为参数。
def paintEvent(self, e): qp = QPainter() qp.begin(self) qp.setRenderHint(QPainter.RenderHint.Antialiasing) qp.drawPath(self.path) qp.end()
曲线在 paintEvent
方法中用 drawPath
方法绘制。
self.anim = QPropertyAnimation(self.ball, b'pos')
我们使用 QPropertyAnimation
对小球的 pos
属性进行动画处理。
vals = [p/100 for p in range(0, 101)]
通过 Python 的列表推导式,我们创建了一个动画步骤的列表。这些步骤是介于 0 和 1 之间的值。
for i in vals: self.anim.setKeyValueAt(i, self.path.pointAtPercent(i))
通过 setKeyValueAt
,我们定义了小球在给定步骤的位置。通过 pointAtPercent
,我们得到路径上给定百分比处的 QPoint
。

图形视图框架中的 QPropertyAnimation
QPropertyAnimation
可以在图形视图框架中对图形项进行动画处理。被动画处理的对象*必须*继承自 QObject
和 QGraphicsItem
。
#!/usr/bin/python from PyQt6.QtWidgets import (QApplication, QGraphicsView, QGraphicsPixmapItem, QGraphicsScene) from PyQt6.QtGui import QPainter, QPixmap from PyQt6.QtCore import (QObject, QPointF, QPropertyAnimation, pyqtProperty) import sys class Ball(QObject): def __init__(self): super().__init__() self.pixmap_item = QGraphicsPixmapItem(QPixmap('ball.png')) def _set_pos(self, pos): self.pixmap_item.setPos(pos) pos = pyqtProperty(QPointF, fset=_set_pos) class Example(QGraphicsView): def __init__(self): super().__init__() self.initView() def initView(self): self.ball = Ball() self.anim = QPropertyAnimation(self.ball, b'pos') self.anim.setDuration(8000) self.anim.setStartValue(QPointF(5, 30)) self.anim.setKeyValueAt(0.3, QPointF(80, 30)) self.anim.setKeyValueAt(0.5, QPointF(200, 30)) self.anim.setKeyValueAt(0.8, QPointF(250, 250)) self.anim.setEndValue(QPointF(290, 30)) self.scene = QGraphicsScene(self) self.scene.setSceneRect(0, 0, 300, 300) self.scene.addItem(self.ball.pixmap_item) self.setScene(self.scene) self.setWindowTitle('Ball animation') self.setRenderHint(QPainter.RenderHint.Antialiasing) self.setGeometry(400, 300, 500, 350) self.anim.start() self.show() def main(): app = QApplication(sys.argv) ex = Example() sys.exit(app.exec()) if __name__ == '__main__': main()
该示例在图形视图框架中使用 QPropertyAnimation
对一个小球对象进行动画处理。
class Ball(QObject): def __init__(self): super().__init__() self.pixmap_item = QGraphicsPixmapItem(QPixmap('ball.png')) def _set_pos(self, pos): self.pixmap_item.setPos(pos) pos = pyqtProperty(QPointF, fset=_set_pos)
由于 PyQt 不支持多重继承,我们使用组合技术来满足前面提到的条件。
class Example(QGraphicsView): def __init__(self): super().__init__() self.initView()
QGraphicsView
在一个可滚动的视口中可视化 QGraphicsScene
的内容。
self.anim = QPropertyAnimation(self.ball, b'pos')
我们将使用 QPropertyAnimation
对小球对象的位置属性进行动画处理。
self.anim.setDuration(8000)
动画持续八秒。
self.anim.setKeyValueAt(0.3, QPointF(80, 30)) self.anim.setKeyValueAt(0.5, QPointF(200, 30)) self.anim.setKeyValueAt(0.8, QPointF(250, 250))
通过 setKeyValueAt
方法,我们在给定的步骤创建具有给定值的关键帧。换句话说,我们定义了在动画的给定步骤中,小球位于何处。
self.scene = QGraphicsScene(self) self.scene.setSceneRect(0, 0, 300, 300) self.scene.addItem(self.ball.pixmap_item)
创建了 QGraphicsScene
并将小球添加到场景中。它提供了一个用于管理大量 2D 图形项的表面。请注意,我们将小球的属性添加到场景中,而不是小球对象本身。
在本文中,我们使用 QPropertyAnimation
创建了动画。
作者
列出所有 PyQt 教程。