週末玩個球,幾行程式碼用PyQt5實現足球射門動畫
QT作為一個全面的桌面應用程式開發包,其自然提供了對影象的動畫支援。本篇文章中,就來簡單地在PYQt5中使用Animation動畫功能。
本篇將會依次完成以下功能:
● 在GUI介面中顯示一個圖片(用一個足球做演示);
● 點選按鈕實現足球的直線射門動畫;
● 點選按鈕實現足球的曲線射門動畫;
在圖形介面顯示圖片的兩種方法
一般情況下,想要在GUI中顯示圖片,我們會通過:
● 例項化一個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_())
執行上述程式碼,我們將會得到如下所示的圖形介面:
但是這種方法沒有辦法實現對圖片更多的控制。為了更好地對圖形介面中的圖片進行控制和管理,我們還需要使用到其他的類,比如QtWidgets中的QGraphicsScene類,QGraphicsScene提供了一個場景,用於對2D圖形進行管理。同時,為了展示QGraphicsScene中的內容,我們還需要使用到QtWidgets中的QGraphicsView類來提供一個檢視部件。
下面,我們就通過一個簡單的例子來了解一下QGraphicsScene類和QGraphicsView類的使用。
首先是完整的程式碼,如下所示:
# 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_())
在這裡面,基礎的視窗程式碼與之前的程式碼類似,有區別且最核心的為以下幾行程式碼。
首先,我們例項化建立了一個用於展示圖形場景的圖形檢視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)中展示圖片的功能,執行完整的程式碼,其顯示出來的圖形介面程式如下圖所示:
上面我們通過兩種不同的方式實現了圖片在圖形介面中的展示,接下來,我們藉助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()方法我們就實現了一個簡單的動畫。
圓月彎刀繼續射門
但是上面的射門動畫是一條直線將小足球移動到了球門之內,簡單粗暴欠缺了些許美感,下面,我們讓這個射門換一種方式,用圓月彎刀的香蕉球將小足球射入球門。
還記得上面我們提過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中使用動畫是不是很簡單?
原文釋出時間為:2018-11-4
本文作者: 州的先生
本文來自雲棲社群合作伙伴“ ofollow,noindex">Python愛好者社群 ”,瞭解相關資訊可以關注“ Python愛好者社群 ”。