這一篇來講解自定義控件的移動軌跡
原理:我們采用QPainterPath先畫一個弧線,然后加載一個物體讓物體移動,設置100個關鍵幀,每個關鍵幀物體的坐標位置就是弧線的坐標位置,這樣就能達到按照指定軌跡移動
首先,我們重寫QLabel,加載一個小黑球到QLabel上
class Ball(QLabel): def __init__(self, parent): super(Ball, self).__init__(parent) self.pix = QPixmap("../ball.png") # 加載一個ball的圖片 self.h = self.pix.height() # ball的高度 self.w = self.pix.width() # ball的寬度 self.setPixmap(self.pix) # 把ball加載到label上 def _set_pos(self, pos): self.move(pos.x() - self.w / 2, pos.y() - self.h / 2) pos = pyqtProperty(QPointF, fset=_set_pos)
然后我們用QPainterPath來畫弧線,先設置弧線:
def initView(self): self.path = QPainterPath() self.path.moveTo(30, 30) self.path.cubicTo(30, 30, 200, 350, 350, 30) # 設置弧線的樣子
再通過paintEvent繪制弧線:
def paintEvent(self, e): qp = QPainter() qp.begin(self) qp.setRenderHint(QPainter.Antialiasing) qp.drawPath(self.path) # 畫弧線 qp.end()
最后組合起來就行了,剩下的不難,下面是完整代碼:
#!/usr/bin/python3 # -*- coding: utf-8 -*- """ PyQt5 Animation tutorial This program will show along curve with QPropertyAnimation. Author: Semishigure 401219180@qq.com Last edited: 2018.03.02 """ from PyQt5.QtWidgets import * from PyQt5.QtGui import * from PyQt5.QtCore import * import sys class Ball(QLabel): def __init__(self, parent): super(Ball, self).__init__(parent) self.pix = QPixmap("../ball.png") # 加載一個ball的圖片 self.h = self.pix.height() # ball的高度 self.w = self.pix.width() # ball的寬度 self.setPixmap(self.pix) # 把ball加載到label上 def _set_pos(self, pos): self.move(pos.x() - self.w / 2, pos.y() - self.h / 2) pos = pyqtProperty(QPointF, fset=_set_pos) class Example(QWidget): def __init__(self): super(Example, self).__init__() self.initView() self.initAnimation() def initView(self): self.path = QPainterPath() self.path.moveTo(30, 30) self.path.cubicTo(30, 30, 200, 350, 350, 30) # 設置弧線的樣子 self.ball = Ball(self) self.ball.pos = QPointF(30, 30) # 設置ball起點位置,這里就是弧線的起點位置 self.setWindowTitle("Animation along curve") self.setGeometry(300, 300, 400, 300) self.show() def paintEvent(self, e): qp = QPainter() qp.begin(self) qp.setRenderHint(QPainter.Antialiasing) qp.drawPath(self.path) # 畫弧線 qp.end() def initAnimation(self): self.anim = QPropertyAnimation(self.ball, b'pos') self.anim.setDuration(3000) self.anim.setStartValue(QPointF(30, 30)) vals = [p / 100 for p in range(0, 101)] for i in vals: self.anim.setKeyValueAt(i, self.path.pointAtPercent(i)) # 設置100個關鍵幀 self.anim.setEndValue(QPointF(350, 30)) self.anim.start() if __name__ == '__main__': app = QApplication(sys.argv) ex = Example() sys.exit(app.exec_())
界面預覽效果:
備注:
1、關鍵幀的范圍值為0-1,我們在其中創建100個點,即[0.01, 0.02, 0.03, 0.04...0.98, 0.99, 1.00],這里直接使用for循環 vals = [p / 100 for p in range(0, 101)]
2、通過i傳遞百分比到self.path.pointAtPercent()就可以拿到弧線的對應坐標QPoinF,所以關鍵幀就可以設置成self.anim.setKeyValueAt(i, self.path.pointAtPercent(i))