Qt|QElapsedTimer 的使用详解
文章目录
- QElapsedTimer 的使用详解
- 1. 基本用法
- 2. 与 `QTime` 的区别
- 3. 常见应用场景
- 3.1 性能测试
- 3.2 节流 UI 更新
- 3.3 超时检测
- 3.4 帧率控制(游戏/动画)
- 4. 与 `QTimer` 的区别
- 5. 注意事项
- 总结
- 最佳实践代码片段合集(速查表)
- 1. 性能分析
- 2. 节流 UI 更新(避免界面频繁刷新卡顿)
- 3. 超时检测
- 4. 帧率控制(游戏/动画)
- 5. 周期性任务(简单版定时器)
QElapsedTimer 的使用详解
在 Qt 程序中,我们经常需要测量时间间隔,比如统计函数耗时、定时刷新 UI、实现节流/限流逻辑等。Qt 提供了一个轻量级类 QElapsedTimer
,它专门用于 高精度时间测量。相比 QTimer
(依赖事件循环、用于异步定时任务),QElapsedTimer
更适合在代码逻辑里测量时间间隔。
1. 基本用法
QElapsedTimer
的常见使用模式是:
QElapsedTimer timer;
timer.start(); // 记录当前时间
... // 执行一些耗时操作
qint64 ms = timer.elapsed();// 计算从 start() 到现在的毫秒数
核心方法有:
start()
:启动计时器,相当于记录当前时间戳。restart()
:返回上一次start()
/restart()
到现在的毫秒数,并重新启动计时器。elapsed()
:返回从start()
/restart()
到现在的毫秒数。isValid()
:判断计时器是否已经被启动。
示例:
QElapsedTimer timer;
timer.start();
doSomething();
qDebug() << "耗时:" << timer.elapsed() << "ms";
2. 与 QTime
的区别
Qt 里还有一个类 QTime
也能测量时间差,但 QElapsedTimer
更适合 高精度计时:
QElapsedTimer
基于系统的单调时钟(monotonic clock),不会受系统时间修改影响。QTime
则是基于系统时间,如果用户修改了系统时间,结果可能不正确。
因此,推荐在性能分析、逻辑节流等场景下使用 QElapsedTimer
。
3. 常见应用场景
3.1 性能测试
QElapsedTimer timer;
timer.start();
heavyFunction();
qDebug() << "函数耗时:" << timer.elapsed() << "ms";
非常适合在调试时测量某段代码的执行效率。
3.2 节流 UI 更新
有些后台线程会频繁产生事件(比如数据回放、网络消息),直接更新 UI 会导致界面卡顿。这时候可以用 QElapsedTimer
控制 UI 更新频率。
void DataReplay::onFrameArrived(const std::string &f)
{static QElapsedTimer timer;int pos = slider_->tsToSec(QString::fromStdString(f));if (!timer.isValid() || timer.elapsed() > 1000) { // 每秒更新一次timer.restart();QMetaObject::invokeMethod(this,[=] { slider_->setPosition(pos); },Qt::QueuedConnection);}
}
这里的关键点:
- static 让
timer
在多次回调中保持状态; elapsed()
控制更新间隔(例如 1000 毫秒);Qt::QueuedConnection
确保 UI 更新在主线程执行。
3.3 超时检测
例如:等待某个条件满足,如果超过时间就退出。
QElapsedTimer timer;
timer.start();while (!ready()) {if (timer.elapsed() > 5000) { // 超过 5 秒qWarning() << "等待超时";break;}QThread::msleep(100);
}
3.4 帧率控制(游戏/动画)
在循环中根据 elapsed()
控制帧率:
QElapsedTimer timer;
timer.start();while (running) {renderFrame();int elapsed = timer.elapsed();if (elapsed < 16) // ~60 FPSQThread::msleep(16 - elapsed);timer.restart();
}
4. 与 QTimer
的区别
QElapsedTimer
:同步、阻塞式测量,用于计算耗时或控制循环。QTimer
:异步事件驱动,用于定时触发槽函数。
举例:
- 想知道函数执行多久 → 用
QElapsedTimer
; - 想每隔 1 秒刷新一次界面 → 用
QTimer
。
5. 注意事项
-
不要忘记
restart()
或start()
如果直接调用elapsed()
而没有先start()
,返回值可能没意义。 -
适合短时间测量
elapsed()
返回qint64
毫秒数,但并不是无限大的,通常可以保证数天范围内的精度,长时间测量建议用QDateTime
。 -
线程安全
QElapsedTimer
本身不是共享对象,每个线程应该有自己独立的实例。如果需要跨线程节流,可以考虑std::chrono
或自己加锁。
总结
QElapsedTimer
是 Qt 提供的 高精度时间测量工具。- 相比
QTime
,它基于单调时钟,不受系统时间修改影响,更适合性能测试、逻辑节流、超时检测。 - 配合
restart()
和elapsed()
,能非常方便地实现节流 UI 更新、循环控制、帧率限制等功能。
一句话概括:
当你需要在 Qt 里测量“过去了多少毫秒”时,优先使用 QElapsedTimer
。
最佳实践代码片段合集(速查表)
1. 性能分析
QElapsedTimer timer;
timer.start();// 需要测量耗时的代码
heavyFunction();qDebug() << "耗时:" << timer.elapsed() << " ms";
2. 节流 UI 更新(避免界面频繁刷新卡顿)
void DataReplay::onFrameArrived(const std::string &f)
{static QElapsedTimer timer;int pos = slider_->tsToSec(QString::fromStdString(f));// 每 1000ms 最多更新一次if (!timer.isValid() || timer.elapsed() > 1000) {timer.restart();QMetaObject::invokeMethod(this,[=] { slider_->setPosition(pos); },Qt::QueuedConnection // 保证在 UI 线程执行);}
}
3. 超时检测
QElapsedTimer timer;
timer.start();while (!ready()) {if (timer.elapsed() > 5000) { // 超过 5 秒qWarning() << "等待超时!";break;}QThread::msleep(100);
}
4. 帧率控制(游戏/动画)
QElapsedTimer timer;
timer.start();while (running) {renderFrame();int elapsed = timer.elapsed();if (elapsed < 16) // 约等于 60 FPSQThread::msleep(16 - elapsed);timer.restart();
}
5. 周期性任务(简单版定时器)
QElapsedTimer timer;
timer.start();while (running) {if (timer.elapsed() > 2000) { // 每 2 秒执行一次qDebug() << "定时任务";timer.restart();}QThread::msleep(50);
}
📌 小结:
- 用
QElapsedTimer
测 代码耗时、控 更新频率、做 超时检测,比QTimer
更轻量、精确。 - 它不依赖事件循环,可以安全地用于后台线程。
- 和
QTimer
互补:QTimer
用来“准时触发任务”,QElapsedTimer
用来“计算经过了多久”。