在本章中,您将学习如何将运动应用于给定的图形图像,从而实现动画。动画在解释任何机器、过程或系统的实际工作中起着重要作用。在本章中,我们将介绍以下主题:
- 显示二维图形图片
- 点击按钮使球向下移动
- 做一个弹跳球
- 使球按照指定的曲线设置动画
要在 Python 中查看和管理 2D 图形项目,我们需要使用一个名为QGraphicsScene
的类。为了显示QGraphicsScene
的内容,我们需要另一个名为QGraphicsView
的类的帮助。基本上,QGraphicsView
提供了一个可滚动的视口来显示QGraphicsScene
的内容。QGraphicsScene
充当多个图形项目的容器。它还提供了几个标准形状,例如矩形和椭圆,包括文本项。还有一件事:QGraphicscene 使用 OpenGL 渲染图形。OpenGL 在显示图像和执行多媒体处理任务方面非常有效。QGraphicsScene
类提供了几种方法来帮助从场景中添加或删除图形项目。也就是说,您可以通过调用addItem
函数将任何图形项目添加到场景中。类似地,要从图形场景中删除项目,可以调用removeItem
函数
为了在 Python 中应用动画,我们将使用QPropertyAnimation
类。PyQt 中的QPropertyAnimation
类有助于在 PyQt 中创建和执行动画。QPropertyAnimation
类通过操纵 Qt 属性(如小部件的几何体、位置等)来实现动画。以下是几个QPropertyAnimation
方法:
start()
:此方法开始动画stop()
:此方法结束动画setStartValue()
:此方法用于指定动画的起始值setEndValue()
:此方法用于指定动画的结束值setDuration()
:此方法用于设置动画的持续时间(毫秒)setKeyValueAt()
:此方法在给定值处创建关键帧setLoopCount()
:此方法设置动画中所需的重复次数
在本配方中,您将学习显示 2D 图形图像。我们假设您的机器上有一个名为scene.jpg
的图形图像,您将了解它如何显示在表单上。本配方的重点是了解如何使用图形视图小部件显示图像。
显示图形的过程非常简单。首先需要创建一个QGraphicsScene
对象,该对象反过来利用QGraphicsView
类来显示其内容。然后通过调用QGraphicsScene
类的addItem
方法将图形项目(包括图像)添加到QGraphicsScene
类中。以下是在屏幕上显示 2D 图形图像的步骤:
- 基于对话框创建新的应用,而不使用按钮模板。
- 将图形视图小部件拖放到其上。
- 使用名称
demoGraphicsView.ui
保存应用。表单将显示如下屏幕截图所示:
pyuic5
命令实用程序将.ui
(XML)文件转换为 Python 代码。生成的 Python 脚本demoGraphicsView.py
可以在本书的源代码包中看到。
- 创建一个名为
callGraphicsView.pyw
的 Python 脚本,该脚本导入代码demoGraphicsView.py
,以调用用户界面设计,从磁盘加载图像,并通过图形视图显示。Python 脚本文件callGraphicsView.pyw
将包含以下代码:
import sys
from PyQt5.QtWidgets import QDialog, QApplication, QGraphicsScene, QGraphicsPixmapItem
from PyQt5.QtGui import QPixmap
from demoGraphicsView import *
class MyForm(QDialog):
def __init__(self):
super().__init__()
self.ui = Ui_Dialog()
self.ui.setupUi(self)
self.scene = QGraphicsScene(self)
pixmap= QtGui.QPixmap()
pixmap.load("scene.jpg")
item=QGraphicsPixmapItem(pixmap)
self.scene.addItem(item)
self.ui.graphicsView.setScene(self.scene)
if __name__=="__main__":
app = QApplication(sys.argv)
myapp = MyForm()
myapp.show()
sys.exit(app.exec_())
在此应用中,您将使用图形视图显示图像。将图形场景添加到图形视图小部件,然后添加QGraphicsPixmapItem
。如果要将图像添加到图形场景中,则需要以pixmap
项的形式提供图像。首先,您需要将图像表示为pixmap
,然后在将其添加到图形场景之前将其显示为pixmap
项。您需要创建一个QPixmap
实例,并指定要通过其load()
方法显示的图像。然后,通过将pixmap
传递给QGraphicsPixmapItem
的构造函数,将pixmap
项标记为pixmapitem
。然后通过addItem
将pixmapitem
添加到场景中。如果pixmapitem
大于QGraphicsView
,则自动启用滚动。
在前面的代码中,我使用了一个文件名为scene.jpg
的图像。请将文件名替换为磁盘上可用的图像文件名,否则屏幕上将不会显示任何内容。
使用以下方法:
QGraphicsView.setScene
:该方法(self,QGraphicsScene
场景)将作为参数提供的场景分配给GraphicView
实例进行显示。如果已在查看场景,则此函数不执行任何操作。在视图上设置场景时,会生成QGraphicsScene.changed
信号,并调整视图的滚动条以适应场景的大小。addItem
:此方法将指定的项目添加到场景中。如果某个项目已位于其他场景中,则将首先从其旧场景中删除该项目,然后将其添加到当前场景中。运行应用时,scene.jpg
图像将通过GrahicsView
小部件显示,如下图所示:
在本配方中,您将了解如何在对象上应用基本动画。此配方将由一个按钮和一个球组成,当按下按钮时,球将开始向地面移动。
为了制作这个食谱,我们将使用QPropertyAnimation
类。QPropertyAnimation
类的setStartValue()
和setEndValue()
方法将分别用于定义动画需要开始和结束的坐标。将调用setDuration()
方法来指定每次动画移动之间的延迟(以毫秒为单位)。以下是应用动画的逐步过程:
-
基于对话框创建新的应用,而不使用按钮模板。
-
将标签小部件和按钮小部件拖放到表单上。
-
将按钮小部件的文本属性设置为
Move Down
。我们假设您的计算机上有一个文件名为coloredball.jpg
的球图像。 -
选择其 pixmap 属性以将球图像指定给标签小部件。
-
在 pixmap 属性中,从两个选项中选择 Resource 和 File,选择 Choose File 选项,浏览磁盘,然后选择
coloredball.jpg
文件。球的图像将出现在标签小部件的位置。 -
将按钮小部件的 objectName 属性设置为
pushButtonPushDown
,将标签小部件的 objectName 属性设置为labelPic
。 -
使用名称
demoAnimation1.ui
保存应用。应用将显示在以下屏幕截图中:
使用 Qt Designer 创建的用户界面存储在一个.ui
文件中,该文件是一个需要转换为 Python 代码的 XML 文件。在应用pyuic5
命令实用程序时,.ui
文件被转换为 Python 脚本。生成的 Python 脚本demoAnimation1.py
可以在本书的源代码包中看到。
- 将
demoAnimation1.py
脚本视为头文件,并将其导入到将从中调用其用户界面设计的文件中。 - 创建另一个名为
callAnimation1.pyw
的 Python 文件,并将demoAnimation1.py
代码导入其中:
import sys
from PyQt5.QtWidgets import QDialog, QApplication
from PyQt5.QtCore import QRect, QPropertyAnimation
from demoAnimation1 import *
class MyForm(QDialog):
def __init__(self):
super().__init__()
self.ui = Ui_Dialog()
self.ui.setupUi(self)
self.ui.pushButtonMoveDown.clicked.connect(self.
startAnimation)
self.show()
def startAnimation(self):
self.anim = QPropertyAnimation(self.ui.labelPic,
b"geometry")
self.anim.setDuration(10000)
self.anim.setStartValue(QRect(160, 70, 80, 80))
self.anim.setEndValue(QRect(160, 70, 220, 220))
self.anim.start()
if __name__=="__main__":
app = QApplication(sys.argv)
w = MyForm()
w.show()
sys.exit(app.exec_())
可以看到 objectName 属性为pushButtonMoveDown
的按钮小部件的 click()事件连接到startAnimation
方法;点击按钮时,调用startAnimation
方法。在startAnimation
方法中,您创建QPropertyAnimation
类的一个对象,并将其命名为anim
。创建QPropertyAnimation
实例时,传递两个参数;第一个是要将动画应用到的标签小部件,第二个是定义要将动画应用到对象属性的对象属性的属性。因为要将动画应用于球的几何体,所以在定义QPropertyAnimation
对象时,将b"geometry"
作为第二个属性传递。之后,将动画的持续时间指定为10000
毫秒,这意味着您希望在每 10000 毫秒之后更改对象的几何体。通过setStartValue
方法,您可以指定矩形区域,即希望动画开始的区域,通过调用setEndValue
方法,您可以指定希望停止动画的矩形区域。通过调用start
方法,启动动画;因此,球从setStartValue
方法指定的矩形区域向下移动,直到到达setEndValue
方法指定的矩形区域。
运行应用时,您将在屏幕上找到一个按钮和一个表示球图像的标签小部件,如下面的屏幕截图(左)所示。单击“向下移动”按钮,球开始向地面移动,并在通过setEndValue
方法指定的区域停止其动画,如以下屏幕截图(右)所示:
在这个食谱中,你将制作一个弹跳球;当点击一个按钮时,一个球朝着地面落下,一碰到地面,它就会反弹回顶部。在本配方中,您将了解如何在对象上应用基本动画。此配方将由一个按钮和一个球组成,当按下按钮时,球将开始向地面移动。
要使球看起来像是在反弹,我们需要先使其朝向地面设置动画,然后从地面向上移动到天空。为此,我们将调用QPropertyAnimation
类的setKeyValueAt
方法三次。第一次和第二次调用setKeyValueAt
方法将使球从上到下设置动画。对setKeyValueAt
方法的第三次调用将使球从下至上设置动画。提供三种setKeyValueAt
方法中的坐标,以便球在相反方向反弹,而不是从何处反弹。以下是了解如何将球设置为反弹的动画的步骤:
- 基于对话框创建新的应用,而不使用按钮模板。
- 将标签小部件和按钮小部件拖放到表单上。
- 将按钮小部件的文本属性设置为
Bounce
。我们假设您的计算机上有一个文件名为coloredball.jpg
的球图像。 - 要将球图像指定给标签小部件,请选择其 pixmap 属性。
- 在 pixmap 属性中,在两个选项
Choose Resource
和Choose File
中,选择选择文件选项,浏览磁盘,然后选择coloredball.jpg
文件。球的图像将出现在标签小部件的位置。 - 将按钮小部件的 objectName 属性设置为
pushButtonBounce
,将标签小部件的 objectName 属性设置为labelPic
。 - 使用名称
demoAnimation3.ui
保存应用
应用将显示在以下屏幕截图中:
使用 Qt Designer 创建的用户界面存储在一个.ui
文件中,该文件是一个 XML 文件,需要转换为 Python 代码。在应用pyuic5
命令实用程序时,.ui
文件被转换为 Python 脚本。生成的 Python 脚本demoAnimation3.py
可以在本书的源代码包中看到。
- 将
demoAnimation3.py
脚本视为头文件,并将其导入到将从中调用其用户界面设计的文件中。 - 创建另一个名为
callAnimation3.pyw
的 Python 文件,并将demoAnimation3.py
代码导入其中:
import sys
from PyQt5.QtWidgets import QDialog, QApplication
from PyQt5.QtCore import QRect, QPropertyAnimation
from demoAnimation3 import *
class MyForm(QDialog):
def __init__(self):
super().__init__()
self.ui = Ui_Dialog()
self.ui.setupUi(self)
self.ui.pushButtonBounce.clicked.connect(self.
startAnimation)
self.show()
def startAnimation(self):
self.anim = QPropertyAnimation(self.ui.labelPic,
b"geometry")
self.anim.setDuration(10000)
self.anim.setKeyValueAt(0, QRect(0, 0, 100, 80));
self.anim.setKeyValueAt(0.5, QRect(160, 160, 200, 180));
self.anim.setKeyValueAt(1, QRect(400, 0, 100, 80));
self.anim.start()
if __name__=="__main__":
app = QApplication(sys.argv)
w = MyForm()
w.show()
sys.exit(app.exec_())
您可以看到,objectName 属性为pushButtonMoveDown
的按钮小部件的 click()事件连接到了startAnimation
方法;当点击按钮时,将调用startAnimation
方法。在startAnimation
方法中,您创建QPropertyAnimation
类的一个对象,并将其命名为anim
。创建QPropertyAnimation
实例时,传递两个参数:第一个是要将动画应用到的标签小部件,第二个是定义要将动画应用到对象属性的对象属性的属性。因为要将动画应用于球的几何体,所以在定义QPropertyAnimation
对象时,将b"geometry"
作为第二个属性传递。之后,将动画的持续时间指定为10000
毫秒,这意味着您希望在每 10000 毫秒之后更改对象的几何体。通过setKeyValue
方法,指定希望动画开始的矩形区域。通过此方法提到左上角区域是因为希望球从左上角落向地面。通过对setKeyValue
方法的第二次调用,您可以提供希望球落在地上的区域。还可以指定下降的角度。球将以对角线方向落向地面。通过调用第三个setValue
方法,可以指定希望动画停止的结束值,在本例中,该值位于右上角。通过对setKeyValue
方法的这三次调用,您可以使球沿对角线方向落向地面,然后反弹回右上角。通过调用start
方法,可以启动动画。
运行应用时,您将在屏幕的左上角找到表示球图像的按钮和标签小部件,如下面的屏幕截图(左)所示。
在点击弹跳按钮,球开始动画对角线向下朝地面,如中间屏幕截图所示,并在触摸地面后,球反弹回到屏幕右上角,如右图所示:
将创建具有所需形状和大小的曲线,并将球设置为在单击按钮时沿曲线的形状移动。在本食谱中,您将了解如何实现引导动画。
QPropertyAnimation
类的setKeyValueAt
方法确定动画的方向。对于引导动画,可以在循环中调用setKeyValueAt
方法。曲线的坐标传递给循环中的setKeyValueAt
方法,使球沿曲线运动。以下是使对象按需设置动画的步骤:
-
基于对话框创建新的应用,而不使用按钮模板。
-
将标签小部件和按钮小部件拖放到表单上。
-
将按钮小部件的文本属性设置为
Move With Curve
。 -
假设您的计算机上有一个文件名为
coloredball.jpg
的球图像,您可以使用其 pixmap 属性将此球图像分配给标签小部件。 -
在 pixmap 属性中,您将找到两个选项,选择 Resource 和 File;选择选择文件选项,浏览您的磁盘,然后选择
coloredball.jpg
文件。球的图像将出现在标签小部件的位置。 -
将按钮小部件的 objectName 属性设置为
pushButtonMoveCurve
,将标签小部件的 objectName 属性设置为labelPic
。 -
使用名称
demoAnimation4.ui
保存应用。应用将显示如下屏幕截图所示:
使用 Qt Designer 创建的用户界面存储在一个.ui
文件中,是一个 XML 文件。通过应用pyuic5
实用程序将 XML 文件转换为 Python 代码。您可以在本书的源代码包中找到生成的 Python 代码demoAnimation4.py
。
-
将
demoAnimation4.py
脚本视为头文件,并将其导入到将从中调用其用户界面设计的文件中。 -
创建另一个名为
callAnimation4.pyw
的 Python 文件,并将demoAnimation4.py
代码导入其中:
import sys
from PyQt5.QtWidgets import QDialog, QApplication
from PyQt5.QtCore import QRect, QPointF, QPropertyAnimation, pyqtProperty
from PyQt5.QtGui import QPainter, QPainterPath
from demoAnimation4 import *
class MyForm(QDialog):
def __init__(self):
super().__init__()
self.ui = Ui_Dialog()
self.ui.setupUi(self)
self.ui.pushButtonMoveCurve.clicked.connect(self.
startAnimation)
self.path = QPainterPath()
self.path.moveTo(30, 30)
self.path.cubicTo(30, 30, 80, 180, 180, 170)
self.ui.labelPic.pos = QPointF(20, 20)
self.show()
def paintEvent(self, e):
qp = QPainter()
qp.begin(self)
qp.drawPath(self.path)
qp.end()
def startAnimation(self):
self.anim = QPropertyAnimation(self.ui.labelPic, b'pos')
self.anim.setDuration(4000)
self.anim.setStartValue(QPointF(20, 20))
positionValues = [n/80 for n in range(0, 50)]
for i in positionValues:
self.anim.setKeyValueAt(i,
self.path.pointAtPercent(i))
self.anim.setEndValue(QPointF(160, 150))
self.anim.start()
if __name__=="__main__":
app = QApplication(sys.argv)
w = MyForm()
w.show()
sys.exit(app.exec_())
首先,使曲线显示在屏幕上。这是引导球动画的曲线;也就是说,它将充当动画的路径。您定义了一个QPainterPath
类的实例,并将其命名为路径。您可以调用QPainterPath
类的moveTo
方法来指定路径或曲线的起始位置。调用cubicTo
方法来指定球动画的弯曲路径。
可以看到 objectName 属性为pushButtonMoveCurve
的按钮小部件的点击事件连接到startAnimation
方法;单击按钮小部件时,将调用startAnimation()
方法。在startAnimation
方法中,您创建QPropertyAnimation
类的一个对象,并将其命名为anim
。创建QPropertyAnimation
实例时,传递两个参数:第一个是要将动画应用到的标签小部件,第二个是定义要将动画应用到对象属性的对象属性的属性。因为要将动画应用于球的位置,所以在定义QPropertyAnimation
对象时,将b'pos"
作为第二个属性传递。之后,您将动画的持续时间指定为4000
毫秒,这意味着您希望在每4000
毫秒后更改球的位置。使用QPropertyAnimation
类的setStartValue()
方法,可以指定希望球从何处设置动画的坐标。设置for
循环,指定球需要移动的值。通过调用for
循环中的setKeyValue
方法来指定球的动画路径。由于需要在路径中指定的每个点绘制球,因此可以通过调用pointAtPercent()
方法并将其传递给setKeyValueAt()
方法来设置需要绘制球的点。您还需要通过调用setEndValue()
方法来设置动画需要停止的位置。
不久之后,指定动画的开始和结束位置,指定动画的路径,并调用paintEvent()
方法在路径的每个点重新绘制球。
在运行应用时,您会在屏幕的左上角(屏幕截图的左侧)找到表示球图像的按钮小部件和标签小部件,单击“随曲线移动”按钮,球开始沿绘制的曲线设置动画,并在曲线结束处停止(屏幕截图的右侧):