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

QT中的定时器与计时器

目录

QTimer

QTimer 的替代方案

API

QElapsedTimer

API


笔者写Qt的时候经常遇到需要定时完成任务的情况。举个例子:我写串口通信程序的时候需要定时向下位机发送数据。或者是定时任务周期性出发(更新时间等)

在Qt中,有两个非常常用的类来完成定时操作,请看:

QTimer

QTimer 类提供了一个高级的定时器编程接口。使用时,创建一个 QTimer,将其 timeout() 信号连接到相应的槽,并调用 start()。之后,它将在固定的时间间隔内发射 timeout() 信号。以下是一个一秒(1000 毫秒)定时器的示例(来自模拟钟表示例):

QTimer *timer = new QTimer(this);
connect(timer, &QTimer::timeout, this, QOverload<>::of(&AnalogClock::update));
timer->start(1000);

从那时起,update() 槽每秒会被调用一次。你可以通过调用 setSingleShot(true) 将定时器设置为只触发一次。你还可以使用静态的 QTimer::singleShot() 函数在指定的时间间隔后调用一个槽:

QTimer::singleShot(200, this, &Foo::updateCaption);

在多线程应用程序中,你可以在任何具有事件循环的线程中使用 QTimer。要从非 GUI 线程启动事件循环,使用 QThread::exec()。Qt 使用定时器的线程亲和性来确定哪个线程将发射 timeout() 信号。因此,必须在其线程中启动和停止定时器;不能从其他线程启动定时器。

在特殊情况下,超时时间为 0 的 QTimer 将尽快超时,但零定时器与其他事件源之间的顺序是未指定的。零定时器可以用于在保持用户界面响应的同时执行一些工作:

QTimer *timer = new QTimer(this);
connect(timer, &QTimer::timeout, this, &Foo::processOneThing);
timer->start();

从那时起,processOneThing() 将被重复调用。它应编写为总是快速返回(通常在处理一条数据项后),以便 Qt 能够向用户界面传递事件,并在完成所有工作后尽快停止定时器。这是实现 GUI 应用程序中重型工作的传统方法,但随着多线程在越来越多的平台上的可用性增加,我们预期零毫秒的 QTimer 对象将逐渐被 QThread 取代。

定时器的精度取决于底层操作系统和硬件。大多数平台支持 1 毫秒的分辨率,尽管在许多实际情况下,定时器的精度可能无法达到这一分辨率。精度也取决于定时器类型。对于 Qt::PreciseTimerQTimer 将尽力保持 1 毫秒的精度。精确定时器也不会提前超时。

对于 Qt::CoarseTimerQt::VeryCoarseTimer 类型,QTimer 可能会在预期之前提前唤醒,具体提前的时间范围为这些类型的边界:对于 Qt::CoarseTimer 为间隔的 5%,对于 Qt::VeryCoarseTimer 为 500 毫秒。

所有定时器类型可能会因系统繁忙或无法提供请求的精度而延迟超时。在超时过载的情况下,即使多个超时已经到达,Qt 只会发射一次 timeout(),然后恢复原始的时间间隔。

QTimer 的替代方案

Qt 6.8 引入了 QChronoTimer。这两个类之间的主要区别在于,QChronoTimer 支持更大的时间间隔范围和更高的精度(std::chrono::nanoseconds)。对于 QTimer,最大支持的间隔为 ±24 天,而对于 QChronoTimer 为 ±292 年(对大于 std::numeric_limits<int>::max() 的时间间隔,减少了整数溢出的可能性)。如果你只需要毫秒级的分辨率和 ±24 天的范围,可以继续使用 QTimer

另一个替代方案是在你的类中重新实现 QObject::timerEvent() 方法(该类必须是 QObject 的子类),并使用以下方法之一:

  • 使用 QBasicTimer,这是一个轻量级的值类,封装了定时器 ID。你可以使用 QBasicTimer::start() 启动定时器,并用 QBasicTimer::stop() 停止它。你可以在重新实现的 timerEvent() 中处理事件。

  • 更低级的方法是直接操作定时器 ID。启动定时器时调用 QObject::startTimer(),存储返回的 ID。停止定时器时调用 QObject::killTimer()。你可以在重新实现的 timerEvent() 中处理事件。这种方法通常比使用 QBasicTimer 更麻烦。

使用 timerEvent() 的一个缺点是一些高级功能,如单次触发定时器和信号,不受支持。

API

成员/信号/槽类型说明
QTimer(QObject *parent = nullptr)构造函数创建一个定时器对象,可以选择设置父对象。
virtual ~QTimer()析构函数销毁定时器对象。
QBindable<bool> bindableActive()成员返回一个可绑定的布尔值,指示定时器是否处于活动状态。
QBindable<int> bindableInterval()成员返回一个可绑定的整型值,表示定时器的时间间隔。
QBindable<bool> bindableSingleShot()成员返回一个可绑定的布尔值,指示定时器是否为单次触发模式。
QBindable<Qt::TimerType> bindableTimerType()成员返回一个可绑定的枚举值,表示定时器的类型。
QMetaObject::Connection callOnTimeout(Functor &&slot)成员连接指定的槽函数到 timeout() 信号,当定时器超时时调用。
QMetaObject::Connection callOnTimeout(const QObject *context, Functor &&slot, Qt::ConnectionType connectionType = Qt::AutoConnection)成员在指定上下文中连接槽函数到 timeout() 信号。
Qt::TimerId id() const (since 6.8)成员返回定时器的 ID,用于唯一标识定时器。
int interval() const成员返回定时器的时间间隔(毫秒)。
std::chrono::milliseconds intervalAsDuration() const成员返回以 std::chrono::milliseconds 表示的时间间隔。
bool isActive() const成员判断定时器是否处于活动状态。
bool isSingleShot() const成员判断定时器是否为单次触发模式。
int remainingTime() const成员返回定时器下次超时之前剩余的时间(毫秒)。
std::chrono::milliseconds remainingTimeAsDuration() const成员返回以 std::chrono::milliseconds 表示的剩余时间。
void setInterval(int msec)成员设置定时器的时间间隔(毫秒)。
void setInterval(std::chrono::milliseconds value)成员设置定时器的时间间隔,以 std::chrono::milliseconds 表示。
void setSingleShot(bool singleShot)成员设置定时器为单次触发或循环触发模式。
void setTimerType(Qt::TimerType atype)成员设置定时器的类型。
void start(std::chrono::milliseconds msec)成员启动定时器,设置时间间隔。
int timerId() const成员返回定时器的 ID。
Qt::TimerType timerType() const成员返回定时器的类型。
void start(int msec)公共槽启动定时器,并设置时间间隔(毫秒)。
void start()公共槽启动定时器,使用之前设置的时间间隔。
void stop()公共槽停止定时器。
void timeout()信号当定时器超时时发射的信号。
void singleShot(Duration interval, Functor &&functor)静态成员设置一个单次触发的定时器,在指定时间后调用给定的函数。
void singleShot(Duration interval, Qt::TimerType timerType, Functor &&functor)静态成员设置单次触发定时器,并指定定时器类型。
void singleShot(Duration interval, const QObject *context, Functor &&functor)静态成员在指定上下文中设置单次触发定时器。
void singleShot(Duration interval, Qt::TimerType timerType, const QObject *context, Functor &&functor)静态成员在指定上下文中设置单次触发定时器,并指定类型。
void singleShot(std::chrono::nanoseconds nsec, const QObject *receiver, const char *member)静态成员在指定纳秒数后调用接收者的成员函数。
void singleShot(std::chrono::nanoseconds nsec, Qt::TimerType timerType, const QObject *receiver, const char *member)静态成员在指定纳秒数后调用接收者的成员

QElapsedTimer

这个玩意是用来实现计时操作的:通常用于快速计算两个事件之间经过的时间。它的 API 与 QTime 类似,因此可以快速将使用 QTime 的代码迁移到这个新类。然而,与 QTime 不同,QElapsedTimer 尽可能使用单调时钟。这意味着无法将 QElapsedTimer 对象转换为人类可读的时间。该类的典型用例是确定在某个缓慢操作中花费了多少时间。最简单的示例是用于调试目的,如下所示:

QElapsedTimer timer;
timer.start();
slowOperation1();
qDebug() << "The slow operation took" << timer.elapsed() << "milliseconds";

在这个示例中,通过调用 start() 启动计时器,经过的时间通过 elapsed() 函数计算。经过的时间还可以用来重新计算另一项操作可用的时间,这在执行必须在特定时间内完成的多步操作时非常有用。例如,QIODevice 及其子类中的 waitFor 类型函数就是这种需求的良好示例。在这种情况下,代码可以如下:

void executeSlowOperations(int timeout)
{QElapsedTimer timer;timer.start();slowOperation1();
​int remainingTime = timeout - timer.elapsed();if (remainingTime > 0)slowOperation2(remainingTime);
}

另一个用例是为特定的时间片执行某个操作。为此,QElapsedTimer 提供了 hasExpired() 便利函数,可用于判断某些毫秒是否已经过去:

void executeOperationsForTime(int ms)
{QElapsedTimer timer;timer.start();
​while (!timer.hasExpired(ms))slowOperation1();
}

在这种情况下,使用 QDeadlineTimer 更为方便,它计算未来的超时,而不是跟踪经过的时间。QElapsedTimer 将在所有支持的平台上使用平台的单调参考时钟(见 QElapsedTimer::isMonotonic())。这带来了额外的好处,即 QElapsedTimer 对时间调整(例如用户修正时间)是免疫的。与 QTime 不同,QElapsedTimer 也对时区设置的变化(例如夏令时)免疫。

另一方面,这意味着 QElapsedTimer 的值只能与使用相同参考的其他值进行比较。如果从 QElapsedTimer 对象提取的参考时间(QElapsedTimer::msecsSinceReference())被序列化,这一点尤其重要。这些值不应在网络中交换或保存到磁盘,因为无法确定接收数据的计算机节点是否与原始节点相同,或者是否自那以来已经重启。

然而,确实可以与在同一机器上运行的其他进程交换该值,前提是它们也使用相同的参考时钟。QElapsedTimer 将始终使用相同的时钟,因此与来自同一机器的其他进程的值进行比较是安全的。如果要与其他 API 生成的值进行比较,应该检查使用的时钟是否与 QElapsedTimer 相同(见 QElapsedTimer::clockType())。

API

成员/操作符类型说明
QElapsedTimer()构造函数创建一个 QElapsedTimer 对象。
QElapsedTimer::Duration durationElapsed() const (since 6.6)成员返回从计时器启动到现在经过的时间。
QElapsedTimer::Duration durationTo(const QElapsedTimer &other) const (since 6.6)成员返回当前计时器到另一个计时器之间的经过时间。
qint64 elapsed() const成员返回自 start() 被调用以来的经过时间(毫秒)。
bool hasExpired(qint64 timeout) const成员判断指定的超时是否已经到达。
void invalidate()成员使计时器无效。
bool isValid() const成员判断计时器是否有效。
qint64 msecsSinceReference() const成员返回自参考时间以来经过的毫秒数。
qint64 msecsTo(const QElapsedTimer &other) const成员返回当前计时器到另一个计时器的毫秒数。
qint64 nsecsElapsed() const成员返回自 start() 被调用以来的经过时间(纳秒)。
qint64 restart()成员重新启动计时器并返回自上次启动以来的经过时间(毫秒)。
qint64 secsTo(const QElapsedTimer &other) const成员返回当前计时器到另一个计时器的秒数。
void start()成员启动计时器。
QElapsedTimer::ClockType clockType()静态公共成员返回 QElapsedTimer 使用的时钟类型。
bool isMonotonic()静态公共成员判断当前平台是否支持单调时钟。
bool operator!=(const QElapsedTimer &lhs, const QElapsedTimer &rhs)非成员操作符判断两个 QElapsedTimer 对象是否不相等。
bool operator<(const QElapsedTimer &lhs, const QElapsedTimer &rhs)非成员操作符判断第一个 QElapsedTimer 对象是否小于第二个。
bool operator==(const QElapsedTimer &lhs, const QElapsedTimer &rhs)非成员操作符判断两个 QElapsedTimer 对象是否相等。

相关文章:

QT中的定时器与计时器

目录 QTimer QTimer 的替代方案 API QElapsedTimer API 笔者写Qt的时候经常遇到需要定时完成任务的情况。举个例子&#xff1a;我写串口通信程序的时候需要定时向下位机发送数据。或者是定时任务周期性出发&#xff08;更新时间等&#xff09; 在Qt中&#xff0c;有两个非…...

国内AI大模型学习平台

据不完全统计&#xff0c;目前&#xff0c;国内有几大AI大模型学习平台可供选择&#xff1a; 1.昇思大模型平台&#xff1a;这是一个集算法选型、创意分享、模型实验和大模型在线体验于一体的AI学习与实践社区。 2.魔搭社区&#xff1a;提供AI模型、数据集和应用的开发与探索平…...

曹操出行借助 ApsaraMQ for Kafka Serverless 提升效率,成本节省超 20%

本文整理于 2024 年云栖大会主题演讲《云消息队列 ApsaraMQ Serverless 演进》&#xff0c;杭州优行科技有限公司消息中间件负责人王智洋分享 ApsaraMQ for Kafka Serverless 助力曹操出行实现成本优化和效率提升的实践经验。 曹操出行&#xff1a;科技驱动共享出行未来 曹操…...

深入理解数据库的三范式

数据库设计中的范式&#xff08;Normal Form&#xff09;是用于规范数据存储结构、消除冗余以及保证数据一致性的重要原则。范式的概念有多种层次&#xff0c;常用的前三种称为第一范式&#xff08;1NF&#xff09;、第二范式&#xff08;2NF&#xff09;和第三范式&#xff08…...

P11233 [CSP-S 2024] 染色

P11233 [CSP-S 2024] 染色 难度&#xff1a;提高/省选-。 考点&#xff1a;DP。 题意&#xff1a; 给定 n n n 个数 A i A_i Ai​&#xff0c;对 A i A_i Ai​ 进行染色&#xff0c;只有两种颜色。设 C C C 为 A A A 染色后的数组。 如果 A i A_i Ai​ 左侧没有预期同…...

图传推流学习(敬请期待)

图传推流简介 1.RTSP、RTP与RTCP2.搭建rtsp服务器&#xff08;资源下载&#xff09;3.搭建rtsp服务器&#xff08;搭建过程&#xff09; 1.RTSP、RTP与RTCP RTSP&#xff08;Real Time Streaming Protocol&#xff09;、RTP&#xff08;Real-time Transport Protocol&#xff0…...

【JavaGuide】十大经典排序算法总结

冒泡排序 算法步骤 不断的两两比较&#xff0c;这样当前最大的元素总是会排在最后面。所以称为冒泡。 图解算法 代码实现 public static int[] bubbleSort(int[] arr) {// i是排好了几个数for (int i 1; i < arr.length; i) {// flag标记当前循环是否调整了顺序&#xff0c…...

程序中怎样用最简单方法实现写excel文档

很多开发语言都能找到excel文档读写的库&#xff0c;但是在资源极其受限的环境下开发&#xff0c;引入这些库会带来兼容性问题。因为一个小功能引入一堆库&#xff0c;我始终觉得划不来。看到有项目引用的jar包有一百多个&#xff0c;看着头麻&#xff0c;根本搞不清谁依赖谁。…...

《机器学习与人类学习:比较、融合与未来展望》

《机器学习与人类学习&#xff1a;比较、融合与未来展望》 一、引言二、机器学习的概念与发展&#xff08;一&#xff09;机器学习的定义与分类&#xff08;二&#xff09;机器学习的发展历程&#xff08;三&#xff09;机器学习的应用领域 三、人类学习的本质与过程&#xff0…...

Mysql 8.4.3LTS 的离线部署

文章目录 一、部署环境资源配置 二、下载地址版本选择 三、部署详情1. 上传安装包2. 解压软件包3. 安装mysql3.3.1 创建mysql用户与用户组3.3.2 授权安装文件夹3.3.3 安装libaio依赖 &#xff08;坑&#xff09;ubuntu24.04 中关于libaio的坑 3.3.4 初始化Mysql数据库3.3.5 编辑…...

h5项目打包上线报错404文件找不到

配置一下路由就可以了 1.找到项目里的这个文件 2.滑到最下面‘源码视图’ 3.找到base&#xff0c;没有的话写上一个&#xff0c;保存后打包就可以了 "h5" : {"router" : {"base" : "./"}}...

mysql上课总结(5)(MySQL的完整性约束(详细介绍))

目录 一、完整性约束。 &#xff08;1&#xff09;概念与目的。 <1>概念。 <2>目的。 &#xff08;2&#xff09;各个约束的详细&#xff08;表格&#xff09; &#xff08;3&#xff09;各个约束的简要总结。 <1>主键约束。 <2>唯一约束。 <3>非…...

复原IP地址

分割字符串的姐妹题 题目&#xff1a;93. 复原 IP 地址 - 力扣&#xff08;LeetCode&#xff09; 题解&#xff1a;代码随想录 代码&#xff1a; class Solution {List<String> resnew ArrayList<>();public List<String> restoreIpAddresses(String s) …...

Effective C++ 学习笔记二

Effective C 学习笔记二 文章目录 Effective C 学习笔记二别让异常逃离析构函数绝不在构造和析构的过程中调用virtual函数令operator 返回一个reference to *this在operator中处理"自我赋值"C四种转换 别让异常逃离析构函数 C 并不禁止析构函数吐出异常&#xff0c;…...

以「JIMUMETA元宇宙体验馆」为例,探讨有哪些元宇宙场景?

让我们以「JIMUMETA元宇宙体验馆」为例&#xff0c;深入探讨元宇宙场景中提供的产品与服务。该体验馆由视创云展精心打造&#xff0c;集成了企业主展馆、元宇宙虚拟活动分会场、品牌展示分会场、线上论坛会场以及会议室接待会客等多重功能&#xff0c;旨在全方位满足企业发布会…...

RHCE的练习(8)

动态网站 lnmp&#xff08;LAMP&#xff09; 解析index.php界面 &#xff08;1&#xff09;预配&#xff0c;确保服务能够被访问 systemctl stop firewalld setenforce 0 &#xff08;2&#xff09;安装nginx服务 mount /dev/sr0 /mnt cat /etc/yum.repos.d/base.repo dnf …...

yocto是如何收集recipes,如何加入现有的bb文件

yocto通常是如何收集recipes: 在Yocto中&#xff0c;通过以下方式收集recipes&#xff1a; 层&#xff08;Layers&#xff09; Yocto项目使用层来组织recipes。层是包含配置文件、recipes和其他相关文件的目录结构。每个层有自己的目录&#xff0c;其中 recipes-* 目录用于存…...

[运维] 服务器本地网络可用性检查脚本

引言 在日常活动中&#xff0c;我遇到过一个令人头疼的问题。测试使用的远程终端在第二天继续使用时可能就发生无法与外网通信的情况&#xff0c;往往连上终端后在拉取资源时才能发现。这导致每次使用前都需要手动检查网络状况&#xff0c;增加了不必要的麻烦。为了简化这一过…...

MYSQL-显示信息关于服务器插件语法(二十五)

13.7.5.25 SHOW PLUGINS 语句 SHOW PLUGINSSHOW PLUGINS 显示信息 关于服务器插件。 SHOW PLUGINS 输出示例&#xff1a; mysql> SHOW PLUGINS\G *************************** 1. row ***************************Name: binlogStatus: ACTIVEType: STORAGE ENGINE Librar…...

【线下培训】龙信受邀参加开封市公安局举办的电子数据取证培训班

文章关键词&#xff1a;电子数据取证、手机取证、云取证、国产化取证 为了提升开封市公安机关在互联网电子数据取证分析方面的专业能力&#xff0c;龙信为开封市公安机关量身打造了一场高质量的电子数据取证分析技能培训课程。 本次培训课程不仅涵盖了电子数据取证的基础理论、…...

在HarmonyOS ArkTS ArkUI-X 5.0及以上版本中,手势开发全攻略:

在 HarmonyOS 应用开发中&#xff0c;手势交互是连接用户与设备的核心纽带。ArkTS 框架提供了丰富的手势处理能力&#xff0c;既支持点击、长按、拖拽等基础单一手势的精细控制&#xff0c;也能通过多种绑定策略解决父子组件的手势竞争问题。本文将结合官方开发文档&#xff0c…...

Ascend NPU上适配Step-Audio模型

1 概述 1.1 简述 Step-Audio 是业界首个集语音理解与生成控制一体化的产品级开源实时语音对话系统&#xff0c;支持多语言对话&#xff08;如 中文&#xff0c;英文&#xff0c;日语&#xff09;&#xff0c;语音情感&#xff08;如 开心&#xff0c;悲伤&#xff09;&#x…...

初学 pytest 记录

安装 pip install pytest用例可以是函数也可以是类中的方法 def test_func():print()class TestAdd: # def __init__(self): 在 pytest 中不可以使用__init__方法 # self.cc 12345 pytest.mark.api def test_str(self):res add(1, 2)assert res 12def test_int(self):r…...

Razor编程中@Html的方法使用大全

文章目录 1. 基础HTML辅助方法1.1 Html.ActionLink()1.2 Html.RouteLink()1.3 Html.Display() / Html.DisplayFor()1.4 Html.Editor() / Html.EditorFor()1.5 Html.Label() / Html.LabelFor()1.6 Html.TextBox() / Html.TextBoxFor() 2. 表单相关辅助方法2.1 Html.BeginForm() …...

从“安全密码”到测试体系:Gitee Test 赋能关键领域软件质量保障

关键领域软件测试的"安全密码"&#xff1a;Gitee Test如何破解行业痛点 在数字化浪潮席卷全球的今天&#xff0c;软件系统已成为国家关键领域的"神经中枢"。从国防军工到能源电力&#xff0c;从金融交易到交通管控&#xff0c;这些关乎国计民生的关键领域…...

小木的算法日记-多叉树的递归/层序遍历

&#x1f332; 从二叉树到森林&#xff1a;一文彻底搞懂多叉树遍历的艺术 &#x1f680; 引言 你好&#xff0c;未来的算法大神&#xff01; 在数据结构的世界里&#xff0c;“树”无疑是最核心、最迷人的概念之一。我们中的大多数人都是从 二叉树 开始入门的&#xff0c;它…...

LLaMA-Factory 微调 Qwen2-VL 进行人脸情感识别(二)

在上一篇文章中,我们详细介绍了如何使用LLaMA-Factory框架对Qwen2-VL大模型进行微调,以实现人脸情感识别的功能。本篇文章将聚焦于微调完成后,如何调用这个模型进行人脸情感识别的具体代码实现,包括详细的步骤和注释。 模型调用步骤 环境准备:确保安装了必要的Python库。…...

恶补电源:1.电桥

一、元器件的选择 搜索并选择电桥&#xff0c;再multisim中选择FWB&#xff0c;就有各种型号的电桥: 电桥是用来干嘛的呢&#xff1f; 它是一个由四个二极管搭成的“桥梁”形状的电路&#xff0c;用来把交流电&#xff08;AC&#xff09;变成直流电&#xff08;DC&#xff09;。…...

Android写一个捕获全局异常的工具类

项目开发和实际运行过程中难免会遇到异常发生&#xff0c;系统提供了一个可以捕获全局异常的工具Uncaughtexceptionhandler&#xff0c;它是Thread的子类&#xff08;就是package java.lang;里线程的Thread&#xff09;。本文将利用它将设备信息、报错信息以及错误的发生时间都…...

图解JavaScript原型:原型链及其分析 | JavaScript图解

​​ 忽略该图的细节&#xff08;如内存地址值没有用二进制&#xff09; 以下是对该图进一步的理解和总结 1. JS 对象概念的辨析 对象是什么&#xff1a;保存在堆中一块区域&#xff0c;同时在栈中有一块区域保存其在堆中的地址&#xff08;也就是我们通常说的该变量指向谁&…...