当前位置: 首页 > news >正文

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);}
}

这里的关键点:

  • statictimer 在多次回调中保持状态;
  • 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. 注意事项

  1. 不要忘记 restart()start()
    如果直接调用 elapsed() 而没有先 start(),返回值可能没意义。

  2. 适合短时间测量
    elapsed() 返回 qint64 毫秒数,但并不是无限大的,通常可以保证数天范围内的精度,长时间测量建议用 QDateTime

  3. 线程安全
    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 用来“计算经过了多久”。

http://www.dtcms.com/a/355815.html

相关文章:

  • H5小游戏-超级马里奥
  • 【涂鸦T5】2. 光感bh1750
  • 效率飙升200%:Appsmith开发结合cpolar远程访问实战解析
  • 前端面试题2(vue)
  • 高并发内存池(14)- PageCache回收内存
  • Go 语言常用命令使用与总结
  • 【Agent】AutoAgent: A Fully-Automated and Zero-Code Framework for LLM Agents
  • 从零开始:手写数字识别程序的深度学习实践
  • 《实际项目》空调水系统群控方案
  • TensorFlow 深度学习 | 三种创建模型的 API
  • Promptalot-Midjourney提示词分享平台
  • Java爬虫是什么,如何获取API接口
  • 嵌入式开发学习———Qt软件环境下的C++学习(七)
  • Nginx中`location`路径匹配规则
  • 20250828_学习JumpServer开源堡垒机使用:统一访问入口 + 安全管控 + 操作审计
  • AI翻唱-RVC在线使用-AutoDL
  • 现代数据架构中的核心技术组件解析
  • RPM Spec 文件中 `Provides` 与 `%py_provides` 实现原理及应用场景解析
  • AP化学课程知识点解析学习计划及培训机构推荐
  • 解决pycharm中已经设置python解释器但是terminal中没有变成对应的conda环境
  • 步进电机、直流电机常见问题
  • ASCM-专有云公共云
  • C#写的一键自动测灯带的应用 AI帮写的。
  • 梯度下降,梯度消失,梯度爆炸
  • hintcon2025 Verilog OJ
  • 若依cloud集训总结
  • 对于冯诺依曼体系的理解
  • Linux:信号详解--醍醐灌顶
  • 基于Spring Cloud Gateway构建API网关
  • 第三章:Cesium 矢量数据可视化(点、线、面)