原文: http://zetcode.com/pyqt/qpropertyanimation/

PyQt 中的 QPropertyAnimation 显示了如何使用QPropertyAnimation在 PyQt 中创建动画。 在示例中,我们对对象的大小,颜色和位置进行了动画处理。 来源和球图像可以在作者的 Github 仓库中找到。

QPropertyAnimation

QPropertyAnimation内插 PyQt 属性。 声明属性的类必须为为QObject

QPropertyAnimation方法

下表显示了一些重要的QPropertyAnimation方法:

名称 描述
start() 开始动画
stop() 终止动画
setStartValue() 设置动画的起始值
setEndValue() 设置动画的结束值
setDuration() 设置动画的持续时间,以毫秒为单位
setKeyValueAt() 在给定步骤以给定值创建关键帧
setLoopCount() 设置动画的重复次数

使用QPropertyAnimation设置动画大小

在第一个示例中,我们为小部件的大小设置动画。

size_anim.py

  1. #!/usr/bin/python3
  2. # -*- coding: utf-8 -*-
  3. '''
  4. ZetCode Advanced PyQt5 tutorial
  5. This program animates the size of a
  6. widget with QPropertyAnimation.
  7. Author: Jan Bodnar
  8. Website: zetcode.com
  9. Last edited: August 2017
  10. '''
  11. from PyQt5.QtWidgets import QWidget, QApplication, QFrame, QPushButton
  12. from PyQt5.QtCore import QRect, QPropertyAnimation
  13. import sys
  14. class Example(QWidget):
  15. def __init__(self):
  16. super().__init__()
  17. self.initUI()
  18. def initUI(self):
  19. self.button = QPushButton("Start", self)
  20. self.button.clicked.connect(self.doAnim)
  21. self.button.move(30, 30)
  22. self.frame = QFrame(self)
  23. self.frame.setFrameStyle(QFrame.Panel | QFrame.Raised)
  24. self.frame.setGeometry(150, 30, 100, 100)
  25. self.setGeometry(300, 300, 380, 300)
  26. self.setWindowTitle('Animation')
  27. self.show()
  28. def doAnim(self):
  29. self.anim = QPropertyAnimation(self.frame, b"geometry")
  30. self.anim.setDuration(10000)
  31. self.anim.setStartValue(QRect(150, 30, 100, 100))
  32. self.anim.setEndValue(QRect(150, 30, 200, 200))
  33. self.anim.start()
  34. if __name__ == "__main__":
  35. app = QApplication([])
  36. ex = Example()
  37. ex.show()
  38. app.exec_()

该示例对QFrame小部件的大小进行动画处理。

  1. self.button = QPushButton("Start", self)
  2. self.button.clicked.connect(self.doAnim)
  3. self.button.move(30, 30)

动画以QPushButton开始。

  1. self.anim = QPropertyAnimation(self.frame, b"geometry")

QPropertyAnimation已创建。 第一个参数是要动画的目标对象; 在我们的例子中,我们为QFrame小部件设置了动画。 第二个参数是将要更改的属性。

  1. self.anim.setDuration(10000)

setDuration()设置动画的持续时间(以毫秒为单位)。

  1. self.anim.setStartValue(QRect(150, 30, 100, 100))
  2. self.anim.setEndValue(QRect(150, 30, 200, 200))

使用setStartValue()setEndValue()分别定义动画的开始和结束值。

  1. self.anim.start()

动画从start()方法开始。

使用QPropertyAnimation设置颜色的动画

下面的示例对小部件的颜色进行动画处理。 由于没有颜色属性,因此我们必须创建一个。

color_anim.py

  1. #!/usr/bin/python3
  2. # -*- coding: utf-8 -*-
  3. '''
  4. ZetCode Advanced PyQt5 tutorial
  5. This programs animates the color of a QLabel.
  6. Author: Jan Bodnar
  7. Website: zetcode.com
  8. Last edited: August 2017
  9. '''
  10. from PyQt5.QtWidgets import (QWidget, QApplication, QPushButton,
  11. QLabel, QHBoxLayout, QSizePolicy)
  12. from PyQt5.QtGui import QColor
  13. from PyQt5.QtCore import QPropertyAnimation, pyqtProperty
  14. import sys
  15. class MyLabel(QLabel):
  16. def __init__(self, text):
  17. super().__init__(text)
  18. def _set_color(self, col):
  19. palette = self.palette()
  20. palette.setColor(self.foregroundRole(), col)
  21. self.setPalette(palette)
  22. color = pyqtProperty(QColor, fset=_set_color)
  23. class Example(QWidget):
  24. def __init__(self):
  25. super().__init__()
  26. self.initUI()
  27. def initUI(self):
  28. hbox = QHBoxLayout(self)
  29. self.button = QPushButton("Start", self)
  30. self.button.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
  31. hbox.addWidget(self.button)
  32. hbox.addSpacing(40)
  33. self.label = MyLabel("Summer")
  34. font = self.label.font()
  35. font.setPointSize(35)
  36. self.label.setFont(font)
  37. hbox.addWidget(self.label)
  38. self.anim = QPropertyAnimation(self.label, b"color")
  39. self.anim.setDuration(2500)
  40. self.anim.setLoopCount(2)
  41. self.anim.setStartValue(QColor(0, 0, 0))
  42. self.anim.setEndValue(QColor(255, 255, 255))
  43. self.button.clicked.connect(self.anim.start)
  44. self.setGeometry(300, 300, 380, 250)
  45. self.setWindowTitle('Color anim')
  46. self.show()
  47. if __name__ == "__main__":
  48. app = QApplication([])
  49. ex = Example()
  50. ex.show()
  51. app.exec_()

该示例逐渐更改QLabel的颜色值。

  1. class MyLabel(QLabel):
  2. def __init__(self, text):
  3. super().__init__(text)
  4. def _set_color(self, col):
  5. palette = self.palette()
  6. palette.setColor(self.foregroundRole(), col)
  7. self.setPalette(palette)
  8. color = pyqtProperty(QColor, fset=_set_color)

QLabel没有颜色属性; 因此,我们用pyqtProperty定义一个。 更改此属性将更新标签的颜色。

  1. self.anim = QPropertyAnimation(self.label, b"color")

QPropertyAnimation更改标签窗口小部件的color属性。

  1. self.anim.setLoopCount(2)

使用setLoopCount()方法,我们可以更改动画运行的次数。

  1. self.anim.setStartValue(QColor(0, 0, 0))
  2. self.anim.setEndValue(QColor(255, 255, 255))

我们设置开始和结束颜色值。

使用QPropertyAnimation沿曲线动画

以下示例使球沿贝塞尔曲线动画。

anim_along_curve.py

  1. #!/usr/bin/python3
  2. # -*- coding: utf-8 -*-
  3. '''
  4. ZetCode Advanced PyQt5 tutorial
  5. This programs animates a ball object
  6. along a curve.
  7. Author: Jan Bodnar
  8. Website: zetcode.com
  9. Last edited: August 2017
  10. '''
  11. from PyQt5.QtWidgets import QApplication, QWidget, QLabel
  12. from PyQt5.QtGui import QPainter, QPixmap, QPainterPath
  13. from PyQt5.QtCore import QObject, QPointF, QPropertyAnimation, pyqtProperty
  14. import sys
  15. class Ball(QLabel):
  16. def __init__(self, parent):
  17. super().__init__(parent)
  18. pix = QPixmap("ball.png")
  19. self.h = pix.height()
  20. self.w = pix.width()
  21. self.setPixmap(pix)
  22. def _set_pos(self, pos):
  23. self.move(pos.x() - self.w/2, pos.y() - self.h/2)
  24. pos = pyqtProperty(QPointF, fset=_set_pos)
  25. class Example(QWidget):
  26. def __init__(self):
  27. super().__init__()
  28. self.initView()
  29. self.initAnimation()
  30. def initView(self):
  31. self.path = QPainterPath()
  32. self.path.moveTo(30, 30)
  33. self.path.cubicTo(30, 30, 200, 350, 350, 30)
  34. self.ball = Ball(self)
  35. self.ball.pos = QPointF(30, 30)
  36. self.setWindowTitle("Animation along curve")
  37. self.setGeometry(300, 300, 400, 300)
  38. self.show()
  39. def paintEvent(self, e):
  40. qp = QPainter()
  41. qp.begin(self)
  42. qp.setRenderHint(QPainter.Antialiasing)
  43. qp.drawPath(self.path)
  44. qp.end()
  45. def initAnimation(self):
  46. self.anim = QPropertyAnimation(self.ball, b'pos')
  47. self.anim.setDuration(7000)
  48. self.anim.setStartValue(QPointF(30, 30))
  49. vals = [p/100 for p in range(0, 101)]
  50. for i in vals:
  51. self.anim.setKeyValueAt(i, self.path.pointAtPercent(i))
  52. self.anim.setEndValue(QPointF(350, 30))
  53. self.anim.start()
  54. if __name__ == '__main__':
  55. app = QApplication(sys.argv)
  56. ex = Example()
  57. sys.exit(app.exec_())

该示例在窗口上绘制一条曲线。 沿绘制的曲线为球对象设置动画。

  1. class Ball(QLabel):
  2. def __init__(self, parent):
  3. super().__init__(parent)
  4. pix = QPixmap("ball.png")
  5. self.h = pix.height()
  6. self.w = pix.width()
  7. self.setPixmap(pix)

球显示在QLabel小部件中。

  1. def _set_pos(self, pos):
  2. self.move(pos.x() - self.w/2, pos.y() - self.h/2)
  3. pos = pyqtProperty(QPointF, fset=_set_pos)

我们调整球的位置; 我们希望将标签的中间放置在曲线上。

  1. self.path = QPainterPath()
  2. self.path.moveTo(30, 30)
  3. self.path.cubicTo(30, 30, 200, 350, 350, 30)

贝塞尔曲线是用QPainterPath创建的。 其cubicTo()方法以起点,控制点和终点为参数。

  1. def paintEvent(self, e):
  2. qp = QPainter()
  3. qp.begin(self)
  4. qp.setRenderHint(QPainter.Antialiasing)
  5. qp.drawPath(self.path)
  6. qp.end()

paintEvent()方法中使用drawPath()方法绘制曲线。

  1. self.anim = QPropertyAnimation(self.ball, b'pos')

我们用QPropertyAnimation为球的pos属性设置动画。

  1. vals = [p/100 for p in range(0, 101)]

通过 Python 列表推导式,我们创建了动画步骤列表。 步长是介于 0 和 1 之间的值。

  1. for i in vals:
  2. self.anim.setKeyValueAt(i, self.path.pointAtPercent(i))

使用setKeyValueAt(),我们定义给定步骤中球的位置。 使用pointAtPercent(),我们可以在路径的给定百分比处获得QPointF

PyQt 中的`QPropertyAnimation` - 图1

图:沿曲线的动画

图形视图框架中的QPropertyAnimation

QPropertyAnimation可以在 Graphics View Framework 中为图形项目设置动画。 动画对象必须继承自QObjectQGraphicsItem

gvf_anim.py

  1. #!/usr/bin/python3
  2. # -*- coding: utf-8 -*-
  3. '''
  4. ZetCode Advanced PyQt5 tutorial
  5. This programs animates a ball object.
  6. Author: Jan Bodnar
  7. Website: zetcode.com
  8. Last edited: August 2017
  9. '''
  10. from PyQt5.QtWidgets import (QApplication, QGraphicsView,
  11. QGraphicsPixmapItem, QGraphicsScene)
  12. from PyQt5.QtGui import QPainter, QPixmap
  13. from PyQt5.QtCore import (QObject, QPointF,
  14. QPropertyAnimation, pyqtProperty)
  15. import sys
  16. class Ball(QObject):
  17. def __init__(self):
  18. super().__init__()
  19. self.pixmap_item = QGraphicsPixmapItem(QPixmap("ball.png"))
  20. def _set_pos(self, pos):
  21. self.pixmap_item.setPos(pos)
  22. pos = pyqtProperty(QPointF, fset=_set_pos)
  23. class Example(QGraphicsView):
  24. def __init__(self):
  25. super().__init__()
  26. self.initView()
  27. def initView(self):
  28. self.ball = Ball()
  29. self.anim = QPropertyAnimation(self.ball, b'pos')
  30. self.anim.setDuration(8000)
  31. self.anim.setStartValue(QPointF(5, 30))
  32. self.anim.setKeyValueAt(0.3, QPointF(80, 30))
  33. self.anim.setKeyValueAt(0.5, QPointF(200, 30))
  34. self.anim.setKeyValueAt(0.8, QPointF(250, 250))
  35. self.anim.setEndValue(QPointF(290, 30))
  36. self.scene = QGraphicsScene(self)
  37. self.scene.setSceneRect(0, 0, 300, 300)
  38. self.scene.addItem(self.ball.pixmap_item)
  39. self.setScene(self.scene)
  40. self.setWindowTitle("Ball animation")
  41. self.setRenderHint(QPainter.Antialiasing)
  42. self.setGeometry(300, 300, 500, 350)
  43. self.anim.start()
  44. self.show()
  45. if __name__ == '__main__':
  46. app = QApplication(sys.argv)
  47. ex = Example()
  48. sys.exit(app.exec_())

该示例在 Graphics View Framework 中使用QPropertyAnimation为球对象设置动画。

  1. class Ball(QObject):
  2. def __init__(self):
  3. super().__init__()
  4. self.pixmap_item = QGraphicsPixmapItem(QPixmap("ball.png"))
  5. def _set_pos(self, pos):
  6. self.pixmap_item.setPos(pos)
  7. pos = pyqtProperty(QPointF, fset=_set_pos)

Sice PyQt 不支持多重继承,我们使用合成技术来满足前面提到的条件。

  1. class Example(QGraphicsView):
  2. def __init__(self):
  3. super().__init__()
  4. self.initView()

QGraphicsView在可滚动视口中可视化QGraphicsScene的内容。

  1. self.anim = QPropertyAnimation(self.ball, b'pos')

我们将使用QPropertyAnimation为球对象的position属性设置动画。

  1. self.anim.setDuration(8000)

动画持续八秒钟。

  1. self.anim.setKeyValueAt(0.3, QPointF(80, 30))
  2. self.anim.setKeyValueAt(0.5, QPointF(200, 30))
  3. self.anim.setKeyValueAt(0.8, QPointF(250, 250))

使用setKeyValueAt()方法,我们在给定步骤创建具有给定值的关键帧。 换句话说,我们定义了动画给定步骤中球的位置。

  1. self.scene = QGraphicsScene(self)
  2. self.scene.setSceneRect(0, 0, 300, 300)
  3. self.scene.addItem(self.ball.pixmap_item)

创建QGraphicsScene并将球添加到场景中。 它提供了一个用于管理大量 2D 图形项目的界面。 注意,我们将ball属性添加到场景中,而不是ball对象。

在本教程中,我们使用QPropertyAnimation创建了动画。

您可能也对以下相关教程感兴趣: PyQt5 教程QNetworkAccessManager教程Python 教程