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 对象是否相等。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/461724.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

内感受性注意的电生理特征:频谱和源定位分析

摘要 对内感受信号的关注和有意识地处理能力被认为对最小自我、适应性自我调节和情感体验的发展&#xff0c;以及工具性和执行性认知功能的最佳表现至关重要。然而&#xff0c;尽管关于内感受推论解释的理论非常丰富&#xff0c;但实证证据仍然很少。在此基础上&#xff0c;本…

[OPEN SQL] FOR ALL ENTRIES IN

FOR ALL ENTRIES IN 语句用于从一个内部表中检索与另一个内部表中指定字段匹配的记录 语法格式 SELECT ... FOR ALL ENTRIES IN <itab> WHERE <cond>. <itab>&#xff1a;插入目标数据内表 <cond>&#xff1a;查询条件 使用FOR ALL ENTRY IN 语句时&…

GetX的一些高级API

目录 前言 一、一些常用的API 二、局部状态组件 1.可选的全局设置和手动配置 2.局部状态组件 1.ValueBuilder 1.特点 2.基本用法 2.ObxValue 1.特点 2.基本用法 前言 这篇文章主要讲解GetX的一些高级API和一些有用的小组件。 一、一些常用的API GetX提供了一些高级…

Windows下基于fping进行批量IP测试

fping是Linux下一个很好用的IP测试工具&#xff0c;结合代码可以完成批量的IP测试&#xff0c;在网络调试中用途很广。本文是基于fping for Windows结合bat批处理&#xff0c;定制的测试脚本样例。 一、程序信息 本次测试使用fpingV5.1 for Windows版&#xff0c;版本信息如下…

[MRCTF2020]你传你呢

[MRCTF2020]你传你&#x1f40e;呢 审题 一眼文件上传 知识点 .htaccess文件的作用 <FilesMatch "a.png"> SetHandler application/x-httpd-php </FilesMatch>将a.png当做php文件执行 AddType application/x-httpd-php .jpgAddType 是一个 Apach…

stm32cubeIde 使用笔记

划分flash空间 需要更改STM32xxx_FLASH.ld文件 输出其他格式文件

【Rust中的序列化:Serde(一)】

Rust中的序列化&#xff1a;Serde Serde是什么&#xff1f;什么是序列化序列化&#xff1f;Serde运行机制Serde Data ModelVistor ApiSerializer ApiDeserializer Api 具体示例流程分析具体步骤&#xff1a;那么依次这个结论是如何得出的呢?什么是de? 总结 Serde是什么&#…

【Flask】四、flask连接并操作数据库

目录 前言 一、 安装必要的库 二、配置数据库连接 三、定义模型 四、操作数据库 1.添加用户 2.删除用户 3.更新用户信息 4查询所有用户 五、测试结果 前言 在Flask框架中&#xff0c;数据库的操作是一个核心功能&#xff0c;它允许开发者与后端数据库进行交互&#xf…

手机实时提取SIM卡打电话的信令声音-新的篇章(三、Android虚拟声卡探索)

手机实时提取SIM卡打电话的信令声音-新的篇章(三、Android虚拟声卡探索) 前言 前面的篇章中&#xff0c;我们从理论方向和实际市面上出现的音频线传输声音的方式&#xff0c;讨论绕开手机对SIM卡电话通话声音的封锁场景的可行性&#xff0c;并实际选购几款数字和模拟的USB转接…

安装fpm,解决*.deb=> *.rpm

要从生成 .deb 包转换为 .rpm 包&#xff0c;可以按照以下步骤修改打包脚本 1. 使用 fpm 工具 fpm 是一个强大的跨平台打包工具&#xff0c;可以将 .deb 包重新打包成 .rpm&#xff0c;也可以直接从源文件打包成 .rpm。 安装 fpm sudo apt-get install ruby-dev sudo gem in…

青出于“蓝”的合资第一新能源,“换壳”背后有门道

文/王俣祺 导语&#xff1a;千呼万唤始出来的新能源“马6”终于亮相了&#xff0c;这款马自达EZ-6本以为凭借马自达多年来在国内市场深耕的底蕴可以收获一片支持&#xff0c;但最近却深陷“换壳”风波。那么今天我们就一起看看&#xff0c;这款马自达EZ-6和被冠以“原型”的深蓝…

HT8787B 可任意限幅、内置自适应升压的2x9.0W立体声音频功放

1 特性 ● 可任意配置的限幅功能 自由配置音频限制幅度&#xff0c;使输出音频信号限制在固定失真水平内 ● 内置自动限温控制功能 适应不同散热条件&#xff0c;避免出现过温关断现象 ● 高效自适应G类升压功能&#xff0c;有效延长播放时间 可调节最大限流值&#xff0c;有效…

Ansible基本使用

目录 介绍 安装 inventory-主机清单 分组 子组 modules-模块 command shell script file copy systemd yum get_url yum_repository user mount cron 介绍 ansible是基于python开发的自动化运维工具。架构相对比较简单&#xff0c;仅需通过ssh连接客户机执行…

Java并发常见面试题总结(上)

线程 ⭐️什么是线程和进程? 何为进程? 进程是程序的一次执行过程&#xff0c;是系统运行程序的基本单位&#xff0c;因此进程是动态的。系统运行一个程序即是一个进程从创建&#xff0c;运行到消亡的过程 在 Java 中&#xff0c;当我们启动 main 函数时其实就是启动了一…

38.第二阶段x86游戏实战2-HOOK窗口消息机制(解决多开窗口句柄问题)

免责声明&#xff1a;内容仅供学习参考&#xff0c;请合法利用知识&#xff0c;禁止进行违法犯罪活动&#xff01; 本次游戏没法给 内容参考于&#xff1a;微尘网络安全 本人写的内容纯属胡编乱造&#xff0c;全都是合成造假&#xff0c;仅仅只是为了娱乐&#xff0c;请不要…

【原创分享】详述中间件的前世今生

中间件是一种软件组件&#xff0c;位于应用程序和操作系统之间&#xff0c;通过提供统一的接口和功能来简化开发和管理应用程序、提高应用程序的可靠性和性能。 中间件的前世可以追溯到20世纪80年代的分布式系统和网络技术的发展。在那个时候&#xff0c;随着计算机网络的普及…

vite+vue3+ts使用vue3-draggable-resizable,可拖动、调整大小的模块库,真的太好用了!

前言&#xff1a;公司业务&#xff1a;在很多地方装了路灯&#xff0c;给路灯做了个管理系统&#xff0c;有管理系统肯定就是增&#xff0c;删&#xff0c;查&#xff0c;改&#xff0c;但是这次改好像有点复杂。给路灯下发指令&#xff0c;可以在路灯的大屏放文字&#xff0c;…

想给视频去背景音乐?简单几步搞定

在数字视频编辑和处理中&#xff0c;去除视频中的背景音乐是一个常见的需求。无论是因为背景音乐与视频内容不符&#xff0c;还是出于版权考虑&#xff0c;掌握视频去背景音乐的方法都显得尤为重要。那么&#xff0c;视频怎么去背景音乐呢&#xff1f;本文将详细介绍几种去除视…

C语言串口接收GPS数据

要在C语言中接收GPS数据&#xff0c;需要使用串口通信来与GPS设备进行数据交互。一个简单的串口通信代码主要包含了以下几个部分&#xff1a; 1.标准库头文件 stdio.h&#xff1a;包含输入输出函数&#xff0c;如 printf string.h&#xff1a;包含字符串处理函数&#xff0c…