同以往一樣,我們先來看看程序的結構,整個程序大約205行,一共涉及6個類,如下圖:

Animation類

這個類繼承了QPropertyAnimation,我們在

學點編程吧:PyQt5番外篇(3):2018情人節特刊?

zhuanlan.zhihu.com圖標

中曾經介紹過。

我們這裡用到了QPropertyAnimation這個類。QPropertyAnimation類定義了Qt的屬性動畫。

QPropertyAnimation以Qt屬性做差值,作為屬性值存儲在QVariants中,該類繼承自QVariantAnimation,並支持基類相同的元類型動畫。

animation = QPropertyAnimation(myWidget, b"geometry")
animation.setDuration(10000)
animation.setStartValue(QRect(0, 0, 100, 30))
animation.setEndValue(QRect(250, 250, 100, 30))

animation.start()

聲明屬性的類必須是一個QObject,為了能夠讓屬性可以用做動畫效果,必須提供一個setter(這裡是:b」geometry」),這樣QPropertyAnimation纔可以設置屬性的值。注意:這能夠使它讓許多Qt控制項產生動畫效果。

首先,我們通過構造函數創建一個QPropertyAnimation對象,其中myWidget表示動畫作用的QObject對象,geometry則表示QObject的屬性。然後,可以指定屬性的開始值和結束值。

QVariantAnimation類詳細的描述瞭如何設置動畫。需要注意的是:如果沒有設置起始值,在QPropertyAnimation實例被創建時,屬性就會設置起始值為它有的值。

QPropertyAnimation就其本身而言非常奏效。對於複雜的動畫,例如:包含多個對象,則可以使用QAnimationGroup,動畫組是一個可以包含其它動畫的動畫,並可以管理動畫的播放。

class Animation(QPropertyAnimation):

def __init__(self, target, prop):
super(Animation, self).__init__(target, prop)

def updateCurrentTime(self, currentTime):
self.m_path = QPainterPath()
if self.m_path.isEmpty():
end = self.endValue()
start = self.startValue()
self.m_path.addEllipse(QRectF(start, end))

dura = self.duration()

if dura == 0:
progress = 1.0
else:
progress = (((currentTime - 1) % dura) + 1) / float(dura)

easedProgress = self.easingCurve().valueForProgress(progress)

if easedProgress > 1.0:
easedProgress -= 1.0
elif easedProgress < 0:
easedProgress += 1.0

pt = self.m_path.pointAtPercent(easedProgress)
self.updateCurrentValue(pt)

def startAnimation(self, startx, starty, endx, endy, duration):
self.setStartValue(QPointF(startx, starty))
self.setEndValue(QPointF(endx, endy))
self.setDuration(duration)
self.setLoopCount(-1)
self.start()

當動畫發生的時候,currentTime(此屬性保存動畫的當前時間和進度)總是在變化的。每次動畫的currentTime更改時,都會調用updateCurrentTime()函數。所以我們重寫該函數,好讓動畫的運行軌道能夠符合我們的要求。

target, prop這個兩個參數分別對應:動畫的產生對象和setter。

self.m_path = QPainterPath()
if self.m_path.isEmpty():
end = self.endValue()
start = self.startValue()
self.m_path.addEllipse(QRectF(start, end))

首先判斷下我們的路徑中是否增加了元素,很明顯一開始沒有,所以我們才會執行下面的語句。

設定行星的運行軌道,這裡是一個橢圓形。

endValue()、startValue()分別表示動畫的結束值和起始值。

self.m_path.addEllipse(QRectF(start, end))

在指定的boundingRectangle內創建一個橢圓,這裡是QRectF(start, end),並將其作為封閉的子路徑添加到painter路徑中。

dura = self.duration()
progress = (((currentTime - 1) % dura) + 1) / float(dura)

duration()此屬性保存動畫的持續時間(以毫秒為單位)。 默認持續時間為250毫秒。progress則描繪了當前的完成比率。

easedProgress = self.easingCurve().valueForProgress(progress)
if easedProgress > 1.0:
easedProgress -= 1.0
elif easedProgress < 0:
easedProgress += 1.0

返回進度緩和曲線的有效進度。 進度必須介於0和1之間,而返回的有效進度可能超出這些範圍。大於1就減1,小於0就加1。

pt = self.m_path.pointAtPercent(easedProgress)

返回當前路徑的百分比easedProgress處的點。 參數easedProgress必須介於0和1之間。當存在曲線時,百分比參數被映射到貝塞爾方程的t參數。

self.updateCurrentValue(pt)

每次動畫的當前值更改時,都會調用updateCurrentValue()。pt參數是新的當前值。沒有這個函數動畫動不了。

def startAnimation(self, startx, starty, endx, endy, duration):
self.setStartValue(QPointF(startx, starty))
self.setEndValue(QPointF(endx, endy))
self.setDuration(duration)
self.setLoopCount(-1)
self.start()

setStartValue()、setEndValue()分別表示設置動畫的起止位置,setDuration()設置動畫的運行時間,

self.setLoopCount(-1)

此屬性保存動畫的循環計數,動畫的循環計數描述為整數。 默認情況下,此值為1,表示動畫應僅運行一次,然後停止。 通過更改它,您可以讓動畫循環多次。 如果值為0,則動畫將根本不運行,並且值為-1時,動畫將永遠循環直至停止。 不支持在具有未定義持續時間的動畫上進行循環。 它只會運行一次。

start()表示開始運行動畫。

最後

我們下期再見!

如果你喜歡本篇文章,請給我點贊

讚賞(推薦)

分享給你的好友們吧!

歡迎關注微信公眾號:學點編程吧。加油!

(? ??_??)? (*????)


推薦閱讀:
相關文章