QTimeLine是PySide6 中用于实现时间线动画的核心类,它的本质是在一段指定时间内,从一个起始值平滑过渡到一个结束值。
一、基础用法:
python
timeLine = QTimeLine(500, None) # 定义一个500毫秒的时间线
timeLine.valueChanged.connect(on_time_line) # 连接valueChanged信号
timeLine.start() # 开始时间线
二、完整实例:
python
import sys
from PySide6.QtCore import QTimeLine, QElapsedTimer, Slot
from PySide6.QtWidgets import QApplication
app = QApplication(sys.argv)
i = 0
# 创建一个计时器统计时间线的耗时
timer = QElapsedTimer()
timer.start()
# 定义一个槽函数,用于处理时间线
@Slot(float)
def on_time_line(value):
global i
if value < 1:
i += 1
print(f"序号:{i}, 输出值:{value}, 耗时(毫秒): {timer.elapsed()}")
return
app.quit()
timeLine = QTimeLine(500, None) # 定义一个500毫秒的时间线
timeLine.valueChanged.connect(on_time_line) # 连接valueChanged信号
timeLine.start() # 开始时间线
app.exec()
运行结果:
python
序号:1, 输出值:0.014184133542663013, 耗时(毫秒): 38
序号:2, 输出值:0.06962898649802818, 耗时(毫秒): 85
序号:3, 输出值:0.15317334709359753, 耗时(毫秒): 128
序号:4, 输出值:0.27862088448054917, 耗时(毫秒): 177
序号:5, 输出值:0.4093971181864313, 耗时(毫秒): 221
序号:6, 输出值:0.5564281924367408, 耗时(毫秒): 268
序号:7, 输出值:0.7014532178568313, 耗时(毫秒): 316
序号:8, 输出值:0.8330059337171258, 耗时(毫秒): 366
序号:9, 输出值:0.928763328096826, 耗时(毫秒): 414
序号:10, 输出值:0.9835007438812176, 耗时(毫秒): 459
时间线启动后,它每隔若干毫秒(或每一帧)发射一个实数信号并被槽函数接收,信号的值从0.0到1.0线性增长,这就是QTimeLine基本工作过程。
三、最常用函数和方法
**1、setLoopCount():**设置循环次数。
2、**setFrameRange(start, end):**设置帧的范围(起始帧、结束帧)。当设置了帧的范围,就用frameChanged信号传递帧信息而不是之前的valueChanged:
python
import sys
from PySide6.QtCore import QTimeLine, QElapsedTimer, Slot, QObject
from PySide6.QtWidgets import QApplication
class TimeLineDemo(QObject):
def __init__(self):
super().__init__()
self.timeLine = QTimeLine(2000, self) # 定义一个2000毫秒的时间线
self.timeLine.setFrameRange(5, 11) # 设置时间线帧号的范围为5到11(时间仍然是0--2000毫秒)
self.timeLine.frameChanged.connect(self.on_time_line) # 连接frameChanged信号
self.timeLine.finished.connect(app.quit) # 当时间线结束时退出应用
self.timeLine.start() # 开始时间线
def on_time_line(self, frame):
print(f"frame:{frame},{self.timeLine.currentFrame()} , 时间点:{self.timeLine.currentTime()}, value:{self.timeLine.currentValue()}")
app = QApplication(sys.argv)
demo = TimeLineDemo()
app.exec()
运行结果:
python
frame:6,6 , 时间点:557, value:0.17947607153759376
frame:7,7 , 时间点:788, value:0.33655598517252877
frame:8,8 , 时间点:1021, value:0.516490370457325
frame:9,9 , 时间点:1253, value:0.6935164234684597
frame:10,10 , 时间点:1493, value:0.8496445738009342
frame:11,11 , 时间点:2000, value:1.0
**3、setDirection():**运行方向。默认正增长,value和时间都是从0开始递增。当设置了反向后,value和时间都是从最大值开始递减:
python
import sys
from PySide6.QtCore import QTimeLine, QElapsedTimer, Slot, QObject
from PySide6.QtWidgets import QApplication
class TimeLineDemo(QObject):
def __init__(self):
super().__init__()
self.timeLine = QTimeLine(500, self) # 定义一个时间线
self.timeLine.setDirection(QTimeLine.Backward) # 设置为反向
self.timeLine.valueChanged.connect(self.on_time_line) # 连接信号
self.timeLine.finished.connect(app.quit) # 当时间线结束时退出应用
self.timeLine.start() # 开始时间线
def on_time_line(self, value):
print(f"时间点:{self.timeLine.currentTime()}, value:{self.timeLine.currentValue()}")
app = QApplication(sys.argv)
demo = TimeLineDemo()
app.exec()
python
C:\Users\DY\.conda\envs\pyside\python.exe E:\HiKi_MVS\tmp\tmp2.py
时间点:500, value:1.0
时间点:455, value:0.9801468428384715
时间点:408, value:0.9187640200210708
时间点:356, value:0.8089298065451671
时间点:312, value:0.6898895477609005
时间点:265, value:0.5470541566592572
时间点:220, value:0.40630934270713764
时间点:170, value:0.2591231629491424
时间点:123, value:0.1420317584890844
时间点:74, value:0.05307928792436811
时间点:33, value:0.010709547837263966
时间点:0, value:-0.0
进程已结束,退出代码为 0
**4、setDuration():**设置持续时间
python
self.timeLine = QTimeLine(parent=self) # 定义一个时间线,初始化时并不定义持续时间
self.timeLine.setDuration(2000) # 设置时间线持续时间为2秒
四、函数和方法总结
1、核心配置函数(动画基础设置)
这类函数用于定义动画的核心参数,是使用 QTimeLine 的基础。
| 函数 | 功能说明 | 示例 |
|---|---|---|
setDuration(ms) |
设置动画总时长(单位:毫秒),决定动画执行的快慢 | timeline.setDuration(3000) # 动画持续 3 秒 |
setFrameRange(start, end) |
设置帧的范围(起始帧、结束帧),决定 currentFrame() 的取值范围 |
timeline.setFrameRange(0, 200) # 帧从 0 到 200 |
setStartFrame(frame) / setEndFrame(frame) |
单独设置起始帧 / 结束帧(替代 setFrameRange 的拆分写法) |
timeline.setStartFrame(10)``timeline.setEndFrame(100) |
2、状态控制函数(动画的启停 / 重置)
这类函数用于控制动画的执行状态,是动态操作动画的关键。
| 函数 | 功能说明 | 注意点 |
|---|---|---|
start() |
启动 / 重启时间线动画 | 若动画已在运行,调用后会从头重新开始 |
stop() |
停止当前动画,保留当前进度(再次 start() 会从停止位置继续) |
区别于 reset() |
setPaused() |
暂停动画,保留当前进度 | |
resume() |
恢复暂停的动画 | 需和 pause() 配合使用 |
toggleDirection``() |
切换方向 |
3、进度 / 数值获取函数(实时获取动画状态)
这类函数用于获取动画的实时进度或数值,常配合信号使用。
| 函数 | 功能说明 | 对比 / 补充 |
|---|---|---|
currentValue() |
返回 0.0~1.0 的归一化进度(浮点数) | 核心:currentFrame() 是整数帧值,currentValue() 是比例值示例:动画执行到一半时返回 0.5 |
currentTime() |
返回动画已执行的时间(单位:毫秒) | 范围:0 ~ 总时长(duration())示例:总时长 3000ms,执行 1 秒后返回 1000 |
duration() |
获取动画总时长(返回设置的毫秒数) | 对应 setDuration(),只读 |
startFrame() / endFrame() |
获取设置的起始帧 / 结束帧 | 对应 setStartFrame()/setEndFrame(),只读 |
state() |
返回当前时间线的状态(枚举值) | 状态枚举:- QTimeLine.State.NotRunning:未运行- QTimeLine.State.Running:运行中- QTimeLine.State.Paused:暂停中 |
4、行为设置函数(控制动画的循环 / 曲线)
这类函数用于定制动画的执行方式,让动画更符合业务需求。
| 函数 | 功能说明 | 常用参数 / 示例 |
|---|---|---|
setLoopCount(count) |
设置动画循环次数 | - 0:无限循环- 1:默认(只执行 1 次)- 3:循环 3 次示例:timeline.setLoopCount(0) # 无限循环 |
setEasingCurv() |
设置动画的缓动曲线(控制速度变化) | 曲线的详细介绍见下表 |
setDirection(direction) |
设置动画的播放方向 | 方向枚举:- QTimeLine.Direction.Forward:正向(从 startFrame 到 endFrame)- QTimeLine.Direction.Backward:反向(从 endFrame 到 startFrame)示例:timeline.setDirection(QTimeLine.Backward) |
5、动画的缓动曲线详解:
Qt 的 QEasingCurve 提供了几十种缓动曲线,其所有枚举值在QtCore.py下:
python
class QEasingCurve(Shiboken.Object):
class Type(enum.Enum):
Linear : QEasingCurve.Type = ... # 0x0
InQuad : QEasingCurve.Type = ... # 0x1
OutQuad : QEasingCurve.Type = ... # 0x2
InOutQuad : QEasingCurve.Type = ... # 0x3
OutInQuad : QEasingCurve.Type = ... # 0x4
InCubic : QEasingCurve.Type = ... # 0x5
OutCubic : QEasingCurve.Type = ... # 0x6
InOutCubic : QEasingCurve.Type = ... # 0x7
OutInCubic : QEasingCurve.Type = ... # 0x8
InQuart : QEasingCurve.Type = ... # 0x9
OutQuart : QEasingCurve.Type = ... # 0xa
InOutQuart : QEasingCurve.Type = ... # 0xb
OutInQuart : QEasingCurve.Type = ... # 0xc
InQuint : QEasingCurve.Type = ... # 0xd
OutQuint : QEasingCurve.Type = ... # 0xe
InOutQuint : QEasingCurve.Type = ... # 0xf
OutInQuint : QEasingCurve.Type = ... # 0x10
InSine : QEasingCurve.Type = ... # 0x11
OutSine : QEasingCurve.Type = ... # 0x12
InOutSine : QEasingCurve.Type = ... # 0x13
OutInSine : QEasingCurve.Type = ... # 0x14
InExpo : QEasingCurve.Type = ... # 0x15
OutExpo : QEasingCurve.Type = ... # 0x16
InOutExpo : QEasingCurve.Type = ... # 0x17
OutInExpo : QEasingCurve.Type = ... # 0x18
InCirc : QEasingCurve.Type = ... # 0x19
OutCirc : QEasingCurve.Type = ... # 0x1a
InOutCirc : QEasingCurve.Type = ... # 0x1b
OutInCirc : QEasingCurve.Type = ... # 0x1c
InElastic : QEasingCurve.Type = ... # 0x1d
OutElastic : QEasingCurve.Type = ... # 0x1e
InOutElastic : QEasingCurve.Type = ... # 0x1f
OutInElastic : QEasingCurve.Type = ... # 0x20
InBack : QEasingCurve.Type = ... # 0x21
OutBack : QEasingCurve.Type = ... # 0x22
InOutBack : QEasingCurve.Type = ... # 0x23
OutInBack : QEasingCurve.Type = ... # 0x24
InBounce : QEasingCurve.Type = ... # 0x25
OutBounce : QEasingCurve.Type = ... # 0x26
InOutBounce : QEasingCurve.Type = ... # 0x27
OutInBounce : QEasingCurve.Type = ... # 0x28
InCurve : QEasingCurve.Type = ... # 0x29
OutCurve : QEasingCurve.Type = ... # 0x2a
SineCurve : QEasingCurve.Type = ... # 0x2b
CosineCurve : QEasingCurve.Type = ... # 0x2c
BezierSpline : QEasingCurve.Type = ... # 0x2d
TCBSpline : QEasingCurve.Type = ... # 0x2e
Custom : QEasingCurve.Type = ... # 0x2f
NCurveTypes : QEasingCurve.Type = ... # 0x30
设置方法如下:
python
# 简略写法
self.timeLine.setEasingCurve(QEasingCurve.Linear)
# 或:
self.timeLine.setEasingCurve(QEasingCurve.Type.InQuart)
1). 基础线性(无缓动)
| 曲线类型 | 效果说明 | 适用场景 |
|---|---|---|
Linear |
匀速运动,无加速 / 减速,最生硬 | 进度条匀速填充、纯机械感的动画 |
2). 二次曲线(Quad):平滑基础款
基于二次函数(平方)的缓动,是最常用的基础平滑曲线,分为 3 种节奏:
| 曲线类型 | 效果说明 |
|---|---|
InQuad |
动画开始慢,逐渐加速(只加速) |
OutQuad |
动画开始快,逐渐减速(只减速) |
InOutQuad |
先加速、中间最快、后减速 |
3). 高次曲线(Cubic/Quartic/Quint):更夸张的加速 / 减速
比二次曲线的加速 / 减速效果更明显,数值越大(Quint > Quartic > Cubic),节奏反差越强:
| 曲线类型 | 效果说明 |
|---|---|
InCubic/OutCubic/InOutCubic |
三次方曲线,加速 / 减速比 Quad 更陡 |
InQuart/OutQuart/InOutQuart |
四次方曲线,反差更强 |
InQuint/OutQuint/InOutQuint |
五次方曲线,最夸张的平滑加速 / 减速 |
4). 指数 / 正弦曲线:非线性平滑
| 曲线类型 | 效果说明 |
|---|---|
InExpo/OutExpo/InOutExpo |
指数级加速 / 减速(开始极慢 / 结束极慢) |
InSine/OutSine/InOutSine |
正弦曲线,比 Quad 更柔和的缓动(接近物理 "轻推" 效果) |
5). 弹性 / 弹跳曲线:带回弹效果
模拟弹簧、弹跳的物理效果,适合活泼的动效:
| 曲线类型 | 效果说明 |
|---|---|
InElastic |
动画开始前先反向回弹一下,再加速前进 |
OutElastic |
动画到终点后,超出一点再回弹到目标位置**(最常用)** |
InOutElastic |
开始和结束都有回弹 |
OutBounce |
动画到终点前多次小弹跳(像皮球落地) |
InBounce |
动画开始前多次小弹跳 |
InOutBounce |
开始和结束都有弹跳 |
6). 阶跃 / 圆形曲线:特殊效果
| 曲线类型 | 效果说明 |
|---|---|
InCirc/OutCirc/InOutCirc |
圆形曲线,比指数曲线更极端的缓动 |
InBack/OutBack/InOutBack |
回退曲线:OutBack 会先超过目标位置再拉回(类似 "拉橡皮筋") |
InCurve/OutCurve |
Qt 早期兼容的曲线,效果接近 InSine/OutSine |
SineCurve |
等价于 InOutSine |
6、实用示例
下面是一个综合示例:
python
import sys
from PySide6.QtCore import QTimeLine, QElapsedTimer, Slot, QObject, QEasingCurve
from PySide6.QtWidgets import QApplication, QWidget, QVBoxLayout, QLabel, QPushButton
class TimeLineDemo(QWidget):
def __init__(self):
super().__init__()
self.timeLine = QTimeLine(parent=self) # 定义一个时间线
self.timeLine.setDuration(10000) # 设置时间线持续时间为10秒
self.timeLine.valueChanged.connect(self.on_time_line) # 连接信号
layout = QVBoxLayout(self)
self.label = QLabel("时间线示例", self)
layout.addWidget(self.label)
self.btn1 = QPushButton("启动时间线")
layout.addWidget(self.btn1)
self.btn1.clicked.connect(self.timeLine.start)
self.btn2 = QPushButton("暂停时间线")
layout.addWidget(self.btn2)
self.btn2.clicked.connect(lambda :self.timeLine.setPaused(True))
self.btn3 = QPushButton("继续时间线")
layout.addWidget(self.btn3)
self.btn3.clicked.connect(lambda :self.timeLine.setPaused(False))
self.btn4 = QPushButton("停止时间线")
layout.addWidget(self.btn4)
self.btn4.clicked.connect(self.timeLine.stop)
self.btn5 = QPushButton("切换方向")
layout.addWidget(self.btn5)
self.btn5.clicked.connect(self.timeLine.toggleDirection)
def on_time_line(self, value):
t = f"时间点:{self.timeLine.currentTime()}, value:{self.timeLine.currentValue()}"
self.label.setText(t)
app = QApplication(sys.argv)
window = TimeLineDemo()
window.show()
app.exec()
五、信号
QTimeLine的信号是驱动动画交互的核心,每个信号对应动画执行的不同阶段,以下是QTimeLine的信号列表:
| 信号名 | 触发时机 | 参数说明 | 典型使用场景 |
|---|---|---|---|
| frameChanged(int frame) | 动画推进过程中,每一帧数值发生变化时触发 | frame:当前最新的帧值(和 currentFrame() 一致) |
更新 UI 显示(如数字变化、控件位置)、实时同步动画状态 |
| valueChanged(float value) | 动画推进过程中,归一化进度值变化时触发 | value:0.0~1.0 的浮点数(和 currentValue() 一致) |
基于比例的动画(如控件宽度 / 高度变化、透明度调整) |
| stateChanged(QTimeLine.State newState) | 时间线的运行状态发生改变时触发 | newState:新状态(枚举值:NotRunning/Running/Paused) |
监听动画启停 / 暂停状态,更新按钮文字(如「暂停」→「恢复」) |
| finished() | 动画正常执行完毕时触发(单次动画结束 / 循环次数用尽) | 无参数 | 动画结束后执行收尾操作(如隐藏控件、触发下一个动画) |
信号使用关键注意事项:
- frameChanged vs valueChanged :
- 两者触发时机几乎同步,但参数类型不同:
frameChanged传整数帧值,valueChanged传 0.0~1.0 浮点数; - 优先用
frameChanged处理「整数计数」场景(如页码、步数),用valueChanged处理「比例计算」场景(如控件尺寸、透明度)。
- 两者触发时机几乎同步,但参数类型不同:
- finished 信号的触发条件 :
- 只有动画「正常执行完所有循环次数」才会触发;
- 若手动调用
stop()终止动画,不会触发finished。
- stateChanged 监听状态 :
- 可通过该信号实现「按钮文字随状态变化」(如运行中按钮显示「暂停」,暂停时显示「恢复」)。
总结
frameChanged/valueChanged是动画过程中最常用的信号,分别返回整数帧值和浮点比例值;stateChanged监听动画启停 / 暂停状态,finished监听动画正常结束,是控制动画生命周期的核心;directionChanged监听播放方向变化,适合需要反向播放的动画场景。
这些信号覆盖了 QTimeLine 动画交互的全场景,组合使用就能实现灵活的动画控制逻辑。
总结
- 核心配置 :
setDuration()(时长)、setFrameRange()(帧范围)是动画的基础,必须优先设置; - 状态控制 :
start()/stop()/pause/resume控制动画启停; - 数值获取 :
currentValue()(比例)、currentTime()(已执行时间)、state()(状态)是实时监控动画的核心; - 行为定制 :
setLoopCount()(循环)、setCurveShape()(速度曲线)、setDirection()(播放方向)让动画更灵活。
这些函数基本覆盖了 QTimeLine 日常使用的 大部分场景,掌握后就能实现大部分基础的时间线动画效果(如控件移动、数值变化、颜色过渡等)。