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 教程。