使用PyQt5的動畫功能實現足球射門效果

QT做爲一個全面的桌面應用程序開發包,其天然提供了對圖像的動畫支持。本篇文章中,就來簡單地在PYQt5中使用Animation動畫功能實現一個足球射門的動畫效果。html

本篇將會依次完成如下功能:app

  • 在GUI界面中顯示一個圖片(用一個足球作演示);
  • 點擊按鈕實現足球的直線射門動畫;
  • 點擊按鈕實現足球的曲線射門動畫;
本文首發州的先生博客: Python GUI教程(十五):在PyQt5中使用動畫,轉載請註明出處

1、在圖形界面顯示圖片的兩種方法

通常狀況下,想要在GUI中顯示圖片,咱們會經過:oop

  • 實例化一個QLable()部件;
  • 實例化一個QPixmap()圖形類;
  • 經過QLabel()部件的setPixmap()方法設置QLabel()部件的圖形;

就像以下代碼所示:動畫

# coding:utf-8

from PyQt5 import QtGui,QtWidgets
import sys

class MainUi(QtWidgets.QMainWindow):
    def __init__(self):
        super().__init__()
        self.init_ui()

    def init_ui(self):
        self.setWindowTitle("動畫使用-zmister.com") # 設置窗口標題
        self.resize(400,200) # 規定窗口大小
        self.main_widget = QtWidgets.QWidget() # 建立一個widget部件
        self.label = QtWidgets.QLabel(self.main_widget) # 建立一個文本標籤部件
        png = QtGui.QPixmap() # 建立一個繪圖類
        png.load("logo.png") # 從pngz中加載一個圖片
        self.label.setPixmap(png) # 設置文本標籤的圖形
        self.setCentralWidget(self.main_widget)

if __name__ == '__main__':
    app = QtWidgets.QApplication(sys.argv)
    gui = MainUi()
    gui.show()
    sys.exit(app.exec_())

運行上述代碼,咱們將會獲得以下所示的圖形界面:
ui

可是這種方法沒有辦法實現對圖片更多的控制。爲了更好地對圖形界面中的圖片進行控制和管理,咱們還須要使用到其餘的類,好比QtWidgets中的QGraphicsScene類,QGraphicsScene提供了一個場景,用於對2D圖形進行管理。同時,爲了展現QGraphicsScene中的內容,咱們還須要使用到QtWidgets中的QGraphicsView類來提供一個視圖部件。spa

下面,咱們就經過一個簡單的例子來了解一下QGraphicsScene類和QGraphicsView類的使用。3d

首先是完整的代碼,以下所示:code

# coding:utf-8

from PyQt5 import QtGui,QtWidgets,QtCore
import sys

class MainUi(QtWidgets.QMainWindow):
    def __init__(self):
        super().__init__()
        self.init_ui()

    def init_ui(self):
        self.setWindowTitle("動畫使用-zmister.com") # 設置窗口標題
        self.resize(400,200) # 規定窗口大小
        self.main_widget = QtWidgets.QWidget() # 建立一個widget部件

        self.grapview = QtWidgets.QGraphicsView(self.main_widget) # 建立一個圖形視圖,繼承自main_widget
        self.grapview.setGeometry(QtCore.QRect(10, 10, 380, 180)) # 設置圖形視圖的矩形區域
        self.scene = QtWidgets.QGraphicsScene() # 建立一個圖形管理場景
        self.grapview.setScene(self.scene)
        png = QtGui.QPixmap() # 建立一個繪圖類
        png.load("logo.png") # 從png中加載一個圖片
        item = QtWidgets.QGraphicsPixmapItem(png) #
        self.scene.addItem(item)

        self.setCentralWidget(self.main_widget)

if __name__ == '__main__':
    app = QtWidgets.QApplication(sys.argv)
    gui = MainUi()
    gui.show()
    sys.exit(app.exec_())

在這裏面,基礎的窗口代碼與以前的代碼相似,有區別且最核心的爲如下幾行代碼。htm

首先,咱們實例化建立了一個用於展現圖形場景的圖形視圖QGraphicsView(),將它繼承自self.main_widget主窗口部件:對象

self.grapview = QtWidgets.QGraphicsView(self.main_widget)

而後,咱們實例化建立了一個圖形場景管理類QGraphicsScene(),並經過setScene()方法將圖形視圖self.grapview的圖形場景設置爲剛剛實例化建立的QGraphicsScene():

self.scene = QtWidgets.QGraphicsScene()
self.grapview.setScene(self.scene)

最後,咱們經過QPixmap()建立並加載了一個圖片,將其添加到圖形項目QGraphicsPixmapItem()中,並經過addItem()方法將圖形項目添加到圖形場景管理self.scene中:

png = QtGui.QPixmap()
png.load("logo.png")
item = QtWidgets.QGraphicsPixmapItem(png)
self.scene.addItem(item)

如此,咱們就完成了經過QGraphicsView()類和QGraphicsScene()類在圖形界面(GUI)中展現圖片的功能,運行完整的代碼,其顯示出來的圖形界面程序以下圖所示:

2、幾行代碼射個門

上面咱們經過兩種不一樣的方式實現了圖片在圖形界面中的展現,接下來,咱們藉助QtCore中的QPropertyAnimation()來實現圖片的動畫效果。

QPropertyAnimation()類主要依靠操縱對象的QT屬性來實現動畫效果,其有幾個比較主要的方法:

  • start():用於啓動動畫;
  • stop():用於中止動畫;
  • setStartValue():用於設置動畫的起始值;
  • setEndValue():用於設置動畫的結束值;
  • setDuration():用於設置動畫的持續時間;
  • setKeyValueAt():用於在特定時間建立一個關鍵的動畫幀動做;
  • setLoopCount():用於設置動畫的循環次數;

下面咱們就使用QPropertyAnimation()類實現圖片的動畫。爲了動畫的效果比5毛特效要好一點,州的先生(公衆號:zmister2016)在阿里的圖標庫iconfont裏找了一個小足球和球門的圖標,嗯,就像這樣:

而後,咱們建立一個圖形界面,裏面包含一個按鈕、一個小球和一個球門的圖片:

# coding:utf-8
from PyQt5 import QtGui,QtWidgets,QtCore
import sys

class MainUi(QtWidgets.QMainWindow):
    def __init__(self):
        super().__init__()
        self.init_ui()

    def init_ui(self):
        self.setWindowTitle("動畫使用-zmister.com") # 設置窗口標題
        self.resize(400,200) # 規定窗口大小
        self.main_widget = QtWidgets.QWidget() # 建立一個widget部件
        self.button = QtWidgets.QPushButton('射門',self.main_widget) # 建立一個按鈕
        self.button.setGeometry(10,10,60,30) # 設置按鈕位置
        self.label = QtWidgets.QLabel(self.main_widget) # 建立一個文本標籤部件用於顯示足球
        self.label.setGeometry(50,80,50,50) # 設置足球位置
        png = QtGui.QPixmap()  # 建立一個繪圖類
        png.load("football.png")  # 從png中加載一個圖片
        self.label.setPixmap(png)  # 設置文本標籤的圖形
        self.label.setScaledContents(True)

        self.qiumen = QtWidgets.QLabel(self.main_widget)  # 建立一個文本標籤部件用於顯示球門
        self.qiumen.setGeometry(345, 75, 50, 50)  # 設置球門位置
        pngqiumen = QtGui.QPixmap()  # 建立一個繪圖類
        pngqiumen.load("qiumen.png")  # 從png中加載一個圖片
        self.qiumen.setPixmap(pngqiumen)  # 設置文本標籤的圖形

        self.setCentralWidget(self.main_widget)

if __name__ == '__main__':
    app = QtWidgets.QApplication(sys.argv)
    gui = MainUi()
    gui.show()
    sys.exit(app.exec_())

運行上述代碼,咱們會獲得一個以下圖所示的圖形界面:

咱們的目的是想讓圖形界面中的小足球經過按鈕控制,進入到球門中。接下來,咱們就經過QPropertyAnimation()類來實現這個效果。

在MainUi()中新建一個名爲shoot()的方法,在其中寫入如下代碼:

self.anim = QtCore.QPropertyAnimation(self.label,b'geometry') # 設置動畫的對象及其屬性
self.anim.setDuration(2000) # 設置動畫間隔時間
self.anim.setStartValue(QtCore.QRect(50,80,50,50)) # 設置動畫對象的起始屬性
self.anim.setEndValue(QtCore.QRect(360, 90, 10, 10)) # 設置動畫對象的結束屬性
self.anim.start() # 啓動動畫

最後,咱們再講按鈕的點擊信號綁定到shoot()方法上:

self.button.clicked.connect(self.shoot)

完整的代碼以下所示:

# coding:utf-8
from PyQt5 import QtGui,QtWidgets,QtCore
import sys

class MainUi(QtWidgets.QMainWindow):
    def __init__(self):
        super().__init__()
        self.init_ui()

    def init_ui(self):
        self.setWindowTitle("動畫使用-zmister.com") # 設置窗口標題
        self.resize(400,200) # 規定窗口大小
        self.main_widget = QtWidgets.QWidget() # 建立一個widget部件
        self.button = QtWidgets.QPushButton('射門',self.main_widget) # 建立一個按鈕
        self.button.setGeometry(10,10,60,30) # 設置按鈕位置
        self.button.clicked.connect(self.shoot)
        self.label = QtWidgets.QLabel(self.main_widget) # 建立一個文本標籤部件用於顯示足球
        self.label.setGeometry(50,80,50,50) # 設置足球位置
        png = QtGui.QPixmap()  # 建立一個繪圖類
        png.load("football.png")  # 從png中加載一個圖片
        self.label.setPixmap(png)  # 設置文本標籤的圖形
        self.label.setScaledContents(True) # 圖片隨文本部件的大小變更

        self.qiumen = QtWidgets.QLabel(self.main_widget)  # 建立一個文本標籤部件用於顯示球門
        self.qiumen.setGeometry(345, 75, 50, 50)  # 設置球門位置
        pngqiumen = QtGui.QPixmap()  # 建立一個繪圖類
        pngqiumen.load("qiumen.png")  # 從png中加載一個圖片
        self.qiumen.setPixmap(pngqiumen)  # 設置文本標籤的圖形

        self.setCentralWidget(self.main_widget)

    def shoot(self):
        self.anim = QtCore.QPropertyAnimation(self.label,b'geometry') # 設置動畫的對象及其屬性
        self.anim.setDuration(2000) # 設置動畫間隔時間
        self.anim.setStartValue(QtCore.QRect(50,80,50,50)) # 設置動畫對象的起始屬性
        self.anim.setEndValue(QtCore.QRect(360, 90, 10, 10)) # 設置動畫對象的結束屬性
        self.anim.start() # 啓動動畫

if __name__ == '__main__':
    app = QtWidgets.QApplication(sys.argv)
    gui = MainUi()
    gui.show()
    sys.exit(app.exec_())

運行上述代碼,點擊「射門」按鈕,咱們將會獲得以下動圖所示的動畫:

這樣,經過QPropertyAnimation()的setDuration()方法、setStartValue()方法、setEndValue()方法咱們就實現了一個簡單的動畫。

3、圓月彎刀繼續射門

可是上面的射門動畫是一條直線將小足球移動到了球門以內,簡單粗暴欠缺了些許美感,下面,咱們讓這個射門換一種方式,用圓月彎刀的香蕉球將小足球射入球門。

還記得上面咱們提過QPropertyAnimation()的setKeyValueAt()這個用於設置動畫關鍵幀的方法。如今咱們就將利用它來實現足球射門時的曲線。

與上面的圖形界面的代碼不同的是,咱們須要繪製一條曲線線條來做爲足球射門時的路徑。因此咱們須要對上面的圖形界面的代碼進行一些修改:

# coding:utf-8
from PyQt5 import QtGui,QtWidgets,QtCore
import sys

class MainUi(QtWidgets.QMainWindow):
    def __init__(self):
        super().__init__()
        self.init_ui()

    def init_ui(self):
        self.setWindowTitle("動畫使用-州的先生zmister.com") # 設置窗口標題
        self.resize(400,200) # 規定窗口大小
        self.main_widget = QtWidgets.QWidget() # 建立一個widget部件
        self.button = QtWidgets.QPushButton('射門',self.main_widget) # 建立一個按鈕
        self.button.setGeometry(10,10,60,30) # 設置按鈕位置

        self.label = QtWidgets.QLabel(self.main_widget) # 建立一個文本標籤部件用於顯示足球
        self.label.setGeometry(50,150,50,50) # 設置足球位置
        png = QtGui.QPixmap()  # 建立一個繪圖類
        png.load("football.png")  # 從png中加載一個圖片
        self.label.setPixmap(png)  # 設置文本標籤的圖形
        self.label.setScaledContents(True) # 圖片隨文本部件的大小變更

        self.qiumen = QtWidgets.QLabel(self.main_widget)  # 建立一個文本標籤部件用於顯示球門
        self.qiumen.setGeometry(345, 75, 50, 50)  # 設置球門位置
        pngqiumen = QtGui.QPixmap()  # 建立一個繪圖類
        pngqiumen.load("qiumen.png")  # 從png中加載一個圖片
        self.qiumen.setPixmap(pngqiumen)  # 設置文本標籤的圖形

        self.path = QtGui.QPainterPath() # 實例化一個繪製類,用於繪製動做
        self.path.moveTo(50, 150)
        self.path.cubicTo(50, 150, 50, 20, 370, 90)

        self.setCentralWidget(self.main_widget)

    # 重寫patintEvent()方法
    def paintEvent(self, e):
        qp = QtGui.QPainter()
        qp.begin(self)
        qp.drawPath(self.path) # 在圖形界面上根據self.path繪製一條線條
        qp.end()
        
if __name__ == '__main__':
    app = QtWidgets.QApplication(sys.argv)
    gui = MainUi()
    gui.show()
    sys.exit(app.exec_())

在上面的代碼中,與以前的程序代碼有一下不一樣之處:

咱們實例化建立了一個QtGui.QPainterPath(),用於進行繪製操做。經過它的moveTo()方法,設置了繪製的起始點,經過它的cubicTo()方法,設置的繪製的整個路徑:

self.path = QtGui.QPainterPath() # 實例化一個繪製類,用於繪製動做
self.path.moveTo(50, 150)
self.path.cubicTo(50, 150, 50, 20, 370, 90)

接着,咱們重寫了窗口的paintEvent()方法,根據繪製操做的定義,在圖形上繪製一條相應的線條:

def paintEvent(self, e):
    qp = QtGui.QPainter()
    qp.begin(self)
    qp.drawPath(self.path) # 在圖形界面上根據self.path繪製一條線條
    qp.end()

這樣,咱們的圖形界面程序呈現出來的就是以下圖所示的樣子:

圖形上呈現了咱們設置的足球將要運動的軌跡,接下來,咱們經過QPropertyAnimation()的setKeyValueAt()設置關鍵幀的路徑,來實現足球曲線射門,具體操做一樣在shoot()方法中進行:

def shoot(self):
    self.anim_x = QtCore.QPropertyAnimation(self.label, b'geometry')                    self.anim_x.setDuration(3000)
    self.anim_x.setStartValue(QtCore.QRect(50,150,50,50)) # 設置動畫對象的起始屬性
    positionValues = [n / 10  for n in range(0, 10)]
    for n,i in enumerate(positionValues):
        x = self.path.pointAtPercent(i).x()
        y = self.path.pointAtPercent(i).y()
        z =  50 - n*3.5
        self.anim_x.setKeyValueAt(i,QtCore.QRect(x, y,z,z))
        self.anim_x.setEndValue(QtCore.QRect(360, 90, 10, 10))
        self.anim_x.start()

最後,一樣將「射門」按鈕的點擊信號綁定在shoot()方法上。運行程序代碼,點擊「射門」按鈕,將會出現以下動圖所示的動畫效果:

爲了更加的美觀,其實能夠將重寫的paintEvent()去掉,在這裏爲了演示路徑,就沒有去除。

在PyQt5中使用動畫是否是很簡單?有問題歡迎留言討論。

相關文章
相關標籤/搜索