Skip to content

Latest commit

 

History

History
277 lines (209 loc) · 19.4 KB

File metadata and controls

277 lines (209 loc) · 19.4 KB

二十一、实现动画

在本章中,您将学习如何将运动应用于给定的图形图像,从而实现动画。动画在解释任何机器、过程或系统的实际工作中起着重要作用。在本章中,我们将介绍以下主题:

  • 显示二维图形图片
  • 点击按钮使球向下移动
  • 做一个弹跳球
  • 使球按照指定的曲线设置动画

介绍

要在 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 图形图像的步骤:

  1. 基于对话框创建新的应用,而不使用按钮模板。
  2. 将图形视图小部件拖放到其上。
  3. 使用名称demoGraphicsView.ui保存应用。表单将显示如下屏幕截图所示:

pyuic5命令实用程序将.ui(XML)文件转换为 Python 代码。生成的 Python 脚本demoGraphicsView.py可以在本书的源代码包中看到。

  1. 创建一个名为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。然后通过addItempixmapitem添加到场景中。如果pixmapitem大于QGraphicsView,则自动启用滚动。

在前面的代码中,我使用了一个文件名为scene.jpg的图像。请将文件名替换为磁盘上可用的图像文件名,否则屏幕上将不会显示任何内容。

使用以下方法:

  • QGraphicsView.setScene:该方法(self,QGraphicsScene场景)将作为参数提供的场景分配给GraphicView实例进行显示。如果已在查看场景,则此函数不执行任何操作。在视图上设置场景时,会生成QGraphicsScene.changed信号,并调整视图的滚动条以适应场景的大小。
  • addItem:此方法将指定的项目添加到场景中。如果某个项目已位于其他场景中,则将首先从其旧场景中删除该项目,然后将其添加到当前场景中。运行应用时,scene.jpg图像将通过GrahicsView小部件显示,如下图所示:

点击按钮使球向下移动

在本配方中,您将了解如何在对象上应用基本动画。此配方将由一个按钮和一个球组成,当按下按钮时,球将开始向地面移动。

怎么做。。。

为了制作这个食谱,我们将使用QPropertyAnimation类。QPropertyAnimation类的setStartValue()setEndValue()方法将分别用于定义动画需要开始和结束的坐标。将调用setDuration()方法来指定每次动画移动之间的延迟(以毫秒为单位)。以下是应用动画的逐步过程:

  1. 基于对话框创建新的应用,而不使用按钮模板。

  2. 将标签小部件和按钮小部件拖放到表单上。

  3. 将按钮小部件的文本属性设置为Move Down。我们假设您的计算机上有一个文件名为coloredball.jpg的球图像。

  4. 选择其 pixmap 属性以将球图像指定给标签小部件。

  5. 在 pixmap 属性中,从两个选项中选择 Resource 和 File,选择 Choose File 选项,浏览磁盘,然后选择coloredball.jpg文件。球的图像将出现在标签小部件的位置。

  6. 将按钮小部件的 objectName 属性设置为pushButtonPushDown,将标签小部件的 objectName 属性设置为labelPic

  7. 使用名称demoAnimation1.ui保存应用。应用将显示在以下屏幕截图中:

使用 Qt Designer 创建的用户界面存储在一个.ui文件中,该文件是一个需要转换为 Python 代码的 XML 文件。在应用pyuic5命令实用程序时,.ui文件被转换为 Python 脚本。生成的 Python 脚本demoAnimation1.py可以在本书的源代码包中看到。

  1. demoAnimation1.py脚本视为头文件,并将其导入到将从中调用其用户界面设计的文件中。
  2. 创建另一个名为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方法中的坐标,以便球在相反方向反弹,而不是从何处反弹。以下是了解如何将球设置为反弹的动画的步骤:

  1. 基于对话框创建新的应用,而不使用按钮模板。
  2. 将标签小部件和按钮小部件拖放到表单上。
  3. 将按钮小部件的文本属性设置为Bounce。我们假设您的计算机上有一个文件名为coloredball.jpg的球图像。
  4. 要将球图像指定给标签小部件,请选择其 pixmap 属性。
  5. 在 pixmap 属性中,在两个选项Choose ResourceChoose File中,选择选择文件选项,浏览磁盘,然后选择coloredball.jpg文件。球的图像将出现在标签小部件的位置。
  6. 将按钮小部件的 objectName 属性设置为pushButtonBounce,将标签小部件的 objectName 属性设置为labelPic
  7. 使用名称demoAnimation3.ui保存应用

应用将显示在以下屏幕截图中:

使用 Qt Designer 创建的用户界面存储在一个.ui文件中,该文件是一个 XML 文件,需要转换为 Python 代码。在应用pyuic5命令实用程序时,.ui文件被转换为 Python 脚本。生成的 Python 脚本demoAnimation3.py可以在本书的源代码包中看到。

  1. demoAnimation3.py脚本视为头文件,并将其导入到将从中调用其用户界面设计的文件中。
  2. 创建另一个名为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方法,使球沿曲线运动。以下是使对象按需设置动画的步骤:

  1. 基于对话框创建新的应用,而不使用按钮模板。

  2. 将标签小部件和按钮小部件拖放到表单上。

  3. 将按钮小部件的文本属性设置为Move With Curve

  4. 假设您的计算机上有一个文件名为coloredball.jpg的球图像,您可以使用其 pixmap 属性将此球图像分配给标签小部件。

  5. 在 pixmap 属性中,您将找到两个选项,选择 Resource 和 File;选择选择文件选项,浏览您的磁盘,然后选择coloredball.jpg文件。球的图像将出现在标签小部件的位置。

  6. 将按钮小部件的 objectName 属性设置为pushButtonMoveCurve,将标签小部件的 objectName 属性设置为labelPic

  7. 使用名称demoAnimation4.ui保存应用。应用将显示如下屏幕截图所示:

使用 Qt Designer 创建的用户界面存储在一个.ui文件中,是一个 XML 文件。通过应用pyuic5实用程序将 XML 文件转换为 Python 代码。您可以在本书的源代码包中找到生成的 Python 代码demoAnimation4.py

  1. demoAnimation4.py脚本视为头文件,并将其导入到将从中调用其用户界面设计的文件中。

  2. 创建另一个名为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()方法在路径的每个点重新绘制球。

在运行应用时,您会在屏幕的左上角(屏幕截图的左侧)找到表示球图像的按钮小部件和标签小部件,单击“随曲线移动”按钮,球开始沿绘制的曲线设置动画,并在曲线结束处停止(屏幕截图的右侧):