[QT编程系列-42]: QT定时器

2023-11-04

目录

第1章 QT下的定时器

1.1 主要的对象

1.2 QTTimer定时的特点

1.3 QT高精度定时器QElapsedTimer: 计时

第2章 Windows操作系统下的高性能定时器

2.1 时钟分辨率

2.2 两种来实现高性能定时器:

2.3 timeSetEvent用法

第3章 timeSetEvent和QTimer比较

3.1 概述

3.2 精度比较


第1章 QT下的定时器

1.1 主要的对象

QT框架中提供了两种类型的定时器:QTimerQTimerEvent

  1. QTimer:QTimer是QT提供的一个高级定时器类,它基于QObject类,并且可以与事件循环一起工作。QTimer提供了灵活的定时器功能,可以执行单次或周期性的定时任务。

    使用QTimer,你可以执行以下操作:

    • 启动和停止定时器。
    • 设置定时器的间隔时间,即触发定时器事件的时间间隔。
    • 设置定时器的类型,包括单次执行和重复执行。
    • 与QObject的槽函数或lambda表达式连接,触发定时器事件时执行特定的操作。

    以下是使用QTimer的示例代码:

    QTimer *timer = new QTimer(this);
    
    // 设置定时器间隔时间
    timer->setInterval(1000); // 每隔1秒触发一次定时器事件
    
    // 连接定时器事件和槽函数
    // 定时器到期后,自动发送timeout信号
    connect(timer, &QTimer::timeout, this, &MyClass::handleTimerEvent);
    
    // 启动定时器
    timer->start();
    
  2. QTimerEvent:QTimerEvent是QT中的一个事件类,它用于处理与QTimer相关的事件。在继承了QObject的类中,可以重写QObject的虚函数timerEvent(QTimerEvent* event)来处理定时器事件。

    以下是使用QTimerEvent的示例代码:

    void MyClass::timerEvent(QTimerEvent *event)
    {
        if (event->timerId() == timerId) {
            // 处理定时器事件的逻辑
        }
        QObject::timerEvent(event);
    }
    

QTimer是较为常用和方便的定时器类,它提供了简单的接口和信号槽机制来处理定时器事件。而QTimerEvent则更加底层,需要手动重写timerEvent函数,并进行定时器事件的处理逻辑。开发者可以根据具体需求选择使用哪种定时器类型。

1.2 QTTimer定时的特点

QT定时器的特点如下:

  1. 简单易用:QT定时器提供了简洁、易于使用的接口,使开发人员可以轻松创建和管理定时器对象。

  2. 灵活性:QT定时器支持各种类型的定时器,包括单次定时器、重复定时器和单次重叠定时器,可以根据具体需求选择合适的类型。

  3. 高精度:QT定时器能够提供高精度的计时能力,通常以毫秒级别为单位。这样,开发人员可以实现精确的定时任务,满足应用程序的需求。QT定时器的最小精度是毫秒。

  4. 线程安全:QT定时器可以安全地在多线程环境中使用。它提供了线程安全的机制,使定时器能够在不同线程中创建、启动和停止,以满足多线程应用程序的需求

  5. 与信号槽机制集成:QT定时器可以与QT的信号槽机制无缝集成。开发人员可以将定时器的超时信号(timeout)与其他对象的槽函数或lambda表达式连接,实现灵活的定时任务逻辑。

  6. 多平台支持:QT定时器在不同平台的行为表现一致,无论是在Windows、MacOS、Linux等操作系统上,还是在嵌入式系统上。这保证了代码在不同平台下的可移植性和一致性。

  7. 高度集成:QT定时器可以与QT框架中的其他组件高度集成,如GUI控件、网络功能等。这使得开发人员可以将定时器与其他功能相结合,实现丰富的交互和功能。

综上所述,QT定时器具有简单易用、灵活性、高精度、线程安全、信号槽机制集成、多平台支持和高度集成等特点。它是QT开发中管理和执行定时任务的重要组件。无论是创建简单的定时器还是实现复杂的定时任务逻辑,QT定时器能够有效地满足开发人员的需求。

1.3 QT高精度定时器QElapsedTimer: 计时

QElapsedTimer主要用于衡量时间间隔,而不是作为实时定时器。它提供了对时间的高分辨率测量,但不具备定时器的触发和重复执行功能。

在QT中,针对高性能定时器需求,可以使用Qt的高分辨率定时器类QElapsedTimer。QElapsedTimer提供了纳秒级别的精确计时功能,适用于需要精确计时高性能定时的应用场景。

使用QElapsedTimer进行高性能定时,可以按照以下步骤:

  1. 创建和启动QElapsedTimer对象:

    QElapsedTimer timer;
    timer.start();
    
  2. 执行代码或任务:

    // 执行需要计时的代码或任务
    
  3. 获取经过的时间:

    qint64 elapsedTime = timer.nsecsElapsed();  // 获取经过的纳秒数
    
    // 转换为所需时间单位(如毫秒)
    qreal elapsedMilliseconds = static_cast<qreal>(elapsedTime) / 1000000.0;
    

示例代码:

#include <QCoreApplication>
#include <QElapsedTimer>
#include <QDebug>

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);
    
    QElapsedTimer timer;
    timer.start();
    
    // 执行需要计时的代码或任务
    for (int i = 0; i < 10000000; ++i) {
        // 一些操作
    }
    
    qint64 elapsedTime = timer.nsecsElapsed();
    qreal elapsedMilliseconds = static_cast<qreal>(elapsedTime) / 1000000.0;
    qDebug() << "Elapsed time:" << elapsedMilliseconds << "ms";
    
    return a.exec();
}

使用QElapsedTimer类可以实现高性能的定时任务,尤其适用于需要测量代码执行时间或实现精确计时的应用程序。它提供了方便的接口来获取经过的纳秒数并进行单位转换,以满足不同精度的计时需求。

QElapsedTimer是Qt提供的一个高精度计时器类,用于测量时间间隔。它可以提供纳秒级别的精确计时,并且不受系统时间的影响。

以下是使用QElapsedTimer的示例代码:

#include <QCoreApplication>
#include <QElapsedTimer>
#include <QDebug>

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    QElapsedTimer timer;
    timer.start();

    // 执行需要计时的代码或任务
    for (int i = 0; i < 10000000; ++i) {
        // 一些操作
    }

    qint64 elapsedTime = timer.nsecsElapsed();
    qreal elapsedMilliseconds = static_cast<qreal>(elapsedTime) / 1000000.0;
    qDebug() << "Elapsed time:" << elapsedMilliseconds << "ms";

    return a.exec();
}

在上面的示例中,创建了QElapsedTimer对象timer,并使用timer.start()开始计时。

然后,在需要计时的代码或任务执行之后,调用timer.nsecsElapsed()获取经过的纳秒数

如果需要将纳秒数转换为其他单位,可以使用除以适当的倍数来转换,例如将纳秒转换为毫秒,需要除以1000000。

最后,可以打印或使用获得的时间间隔进行后续处理。

请注意,QElapsedTimer的计时器受到系统的性能和精度限制,因此在不同的系统上可能会有所不同。但相对于Qt的QTimer类,QElapsedTimer提供了更高精度的测量能力,适用于需要准确计时的场景。

第2章 Windows操作系统下的高性能定时器

2.1 时钟分辨率

在Windows操作系统中,时钟分辨率是指操作系统提供的计时器的最小时间间隔。它决定了定时器的精度和能够设置的最小延迟时间。

Windows操作系统的默认时钟分辨率是15.6毫秒(ms),即0.0156秒。这意味着最小的延迟时间或定时器触发间隔是15.6毫秒。

然而,可以通过调用timeBeginPeriod函数来改变时钟分辨率。timeBeginPeriod函数允许应用程序请求更高的时钟精度。通常,较低的时钟分辨率会导致更高的系统资源消耗,因此应该根据实际需求进行权衡和使用。

请注意,更高的分辨率并不一定意味着更高的准确性。时钟分辨率受到系统硬件和操作系统调度的限制,并且实际的定时器触发时间可能会受到其他因素的影响,例如系统负载、其他进程的优先级、功耗管理等。

在使用时钟分辨率时,请考虑应用程序的需求和系统资源使用,并在必要时恢复默认的时钟分辨率。对于大多数通用应用程序而言,Windows默认的时钟分辨率已经足够使用。如有特定需求,可以使用高分辨率定时器等特定技术来获得更高的精确度和准确性。

2.2 两种来实现高性能定时器:

在Windows操作系统中,可以使用以下两种来实现高性能定时器:

  1. QueryPerformanceCounter QueryPerformanceFrequency 函数:=》计时
    这是Windows操作系统提供的API函数,用于获取高性能计数器的值和频率。高性能计数器提供了一个非常精确的计时方式,可以用来测量短时间间隔的性能。这是通过QueryPerformanceFrequency函数获取计时器的频率(每秒计时器的计数数目),然后使用QueryPerformanceCounter函数获取当前计时器的计数值。

    示例代码:

    LARGE_INTEGER frequency;
    LARGE_INTEGER start;
    LARGE_INTEGER end;
    
    QueryPerformanceFrequency(&frequency);
    QueryPerformanceCounter(&start);
    
    // 执行代码或任务
    
    QueryPerformanceCounter(&end);
    double elapsedTime = (end.QuadPart - start.QuadPart) * 1000.0 / frequency.QuadPart;
    

    使用QueryPerformanceCounter和QueryPerformanceFrequency函数可以获取非常高精度的时间戳,适用于实现精确计时和定时任务,尤其在需要测量代码执行时间或实现实时系统应用程序时。

  2. Multimedia Timers(多媒体定时器):定时
    Windows操作系统还提供了多媒体定时器API,以实现高分辨率低延迟的定时器功能。多媒体定时器允许以毫秒级的精度设置和触发定时器事件,适用于需要高性能定时器功能的多媒体应用程序和实时系统。

    这些API包括timeSetEvent、timeBeginPeriod和timeEndPeriod等函数。其中,timeSetEvent函数用于创建启动定时器,可以指定定时器的触发间隔、回调函数等参数。

    示例代码:

    void CALLBACK TimerCallback(UINT uID, UINT uMsg, DWORD_PTR dwUser, DWORD_PTR dw1, DWORD_PTR dw2)
    {
        // 定时器事件的处理逻辑
    }
    
    // 设置定时器并启动
    UINT timerId = timeSetEvent(
        period,            // 间隔时间(单位:毫秒)
        resolution,        // 分辨率(单位:毫秒)
        TimerCallback,     // 回调函数
        0,                 // 回调函数参数
        TIME_PERIODIC      // 定时器类型 - 重复执行
    );
    
    // 停止定时器
    timeKillEvent(timerId);
    

    使用多媒体定时器API可以实现高性能的毫秒级别定时器,适用于需要高精度的定时任务,并且对实时性要求较高的应用程序。

无论使用哪种方法,高性能定时器的准确性和精度受到多个因素的影响,包括硬件性能、系统负载等。在实际应用中,应根据实际需求和应用场景选择适合的方法,并进行充分的测试和验证,以确保定时器满足性能要求。

2.3 timeSetEvent用法

Windows API中的timeSetEvent函数用于设置定时器事件。

该函数允许您在指定的时间间隔内定期调用一个回调函数

以下是timeSetEvent函数的用法:

MMRESULT timeSetEvent(
    UINT           uDelay,
    UINT           uResolution,
    LPTIMECALLBACK lpTimeProc,
    DWORD_PTR      dwUser,
    UINT           fuEvent
);

参数说明:

  • uDelay:指定事件触发的延迟时间(以毫秒为单位)。
  • uResolution:指定定时器的最小时间分度。较小的值表示较高的分辨率。通常使用1作为最小分度。
  • lpTimeProc:指向回调函数的指针,当定时器事件触发时将调用该函数。
  • dwUser:用于传递给回调函数的用户定义的值(可选)。
  • fuEvent:事件类型标志,可以是TIME_ONESHOT(定时器只触发一次)或TIME_PERIODIC(定时器定期触发)。

使用示例:

#include <Windows.h>
#include <iostream>

void CALLBACK TimerProc(UINT uTimerID, UINT uMsg, DWORD_PTR dwUser, DWORD_PTR dw1, DWORD_PTR dw2)
{
    std::cout << "Timer event triggered!" << std::endl;
}

int main()
{
    // 设置一个定时器,每1000毫秒触发一次
    MMRESULT timerId = timeSetEvent(1000, 0, TimerProc, 0, TIME_PERIODIC);
    if (timerId == 0)
    {
        std::cout << "Failed to set timer!" << std::endl;
        return 1;
    }

    // 等待用户按下任意键停止定时器
    std::cout << "Timer started. Press any key to stop." << std::endl;
    std::cin.get();

    // 停止定时器
    MMRESULT result = timeKillEvent(timerId);
    if (result != TIMERR_NOERROR)
    {
        std::cout << "Failed to stop timer!" << std::endl;
        return 1;
    }

    std::cout << "Timer stopped." << std::endl;
    return 0;
}

上述示例代码中,我们创建了一个定时器,每1000毫秒触发一次。当定时器事件被触发时,回调函数TimerProc将被调用。用户可以通过按下任意键来停止定时器。

请注意,在使用timeSetEvent函数后,应使用timeKillEvent函数停止定时器。否则,定时器事件将会持续触发,可能导致不必要的问题。

第3章 timeSetEvent和QTimer比较

3.1 概述

timeSetEvent和QTimer是两个不同的定时器机制,分别对应于Windows平台的原生API和Qt框架中的定时器类。

  1. timeSetEvent:

    • timeSetEvent是Windows API提供的函数,用于设置定时器事件。
    • 它可以在指定的时间间隔内定期调用一个回调函数。
    • timeSetEvent需要手动设置参数,包括延迟时间、事件分辨率、回调函数等。
    • timeSetEvent是使用C/C++编程语言进行调用和使用。
  2. QTimer:

    • QTimer是Qt框架提供的定时器类,封装了定时器的常用操作。
    • 它基于事件循环机制,可以在Qt应用程序中使用。
    • QTimer提供了方便的接口和信号槽机制来处理定时器事件,无需手动设置回调函数。
    • QTimer提供了更高级别的功能,例如单次定时、间隔定时、暂停和重启等。

主要区别:

  • 实现方式不同:timeSetEvent是通过调用Windows API实现的,而QTimer是基于Qt框架提供的定时器类。
  • 参数设置:timeSetEvent需要手动设置参数,包括延迟时间、回调函数等,而QTimer受到Qt框架的封装,提供了更简单的接口和信号槽机制。
  • 平台依赖性:timeSetEvent是Windows特定的API,只能在Windows平台上使用。而QTimer是Qt框架的一部分,可以在跨平台的Qt应用程序中使用。

选择使用timeSetEvent还是QTimer取决于您的开发环境和需求。如果您正在使用Windows平台,并且更倾向于使用原生API和C/C++进行开发,则可以选择timeSetEvent。如果您使用Qt框架,并且希望使用更便捷的接口和信号槽机制,以及跨平台的可移植性,则可以选择QTimer。

3.2 精度比较

在精度方面,timeSetEvent和QTimer可能会有一些差异,具体取决于操作系统硬件的限制。

(1)timeSetEvent:

  • 精度依赖于操作系统提供的时钟分辨率,可以通过设置uResolution参数来控制,最小单位为毫秒。
  • Windows操作系统的时钟分辨率通常为15.6毫秒,即最小分辨率为15.6毫秒。
  • 由于存在系统调度和其他任务的影响,timeSetEvent的实际触发时间可能会有一定的偏差。

(2)QTimer:

  • QTimer基于操作系统和使用的定时器设备驱动,可以实现更高的精度。
  • 在大多数情况下,QTimer的默认精度为10毫秒,即最小分辨率为10毫秒。
  • Qt框架使用操作系统提供的定时器机制(例如Windows下使用Multimedia Timer或定时器线程)来实现定时器功能。
  • QTimer的精度还受到机器负载、操作系统调度和其他因素的影响。

需要注意的是,无论是timeSetEvent还是QTimer,它们都无法提供绝对精确的定时器,因为操作系统和硬件的限制会造成一定的延迟和偏差。如果需要更高精度的定时功能,可能需要使用特定于硬件的定时器库或使用专用硬件设备。

总而言之,对于一般应用场景,QTimer通常具有足够的精度,可以满足大多数需求。但如果对精度要求非常高,例如实时应用或需要更精确时间控制的场景,可能需要使用其他方案来满足需求。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

[QT编程系列-42]: QT定时器 的相关文章

随机推荐

  • 已解决报错UnboundLocalError: local variable ‘title‘ referenced before assignment

    1 今天抓取某网站的数据时 显示报错UnboundLocalError local variable title referenced before assignment Traceback most recent call last Fi
  • 无法启动64位idea,无法启动idea64.exe的一种原因(意外删除破解文件导致无法打开idea)

    前言 突然有一天 我的IDEA出现了问题 点击桌面快捷方式的idea毫无反应 无奈之下重装了IDEA 但还是有相同的问题 无法打开64位的idea 网上找了一堆博客 花了两个多小时终于解决了 写篇博客记录下这个问题 1 首先打开idea b
  • 初识网络安全(黑客技术)

    目录 前言 一 安全事件案例 二 网络安全行业公司 三 网络安全岗位 四 网络安全网站 五 src漏洞平台 总结 前言 网络安全是指保护计算机网络和网络上的数据免受未经授权的访问 使用 泄露 破坏和干扰的一系列措施和技术 在当今数字化时代
  • JAVA web 获取系统时间

  • ROS---保存地图

    建立save map sh文件夹 bin bash rosrun map server map saver f catkin ws src hypharos minicar launch map mymap 保存地图时我们进入此文件所在文件
  • 从零实现一套属于自己的UI框架-发布到npm

    汤小梦 https juejin im post 5e200ee86fb9a02fdd38986d 不知不觉马上就要放假了 写一篇文章祝愿 2020 越来越好 如今前端工程师的要求越来越高了 需要掌握的技术点越来越多了 会一些基本的前端技能
  • 华为云 CentOS 8 下 Nginx 1.20 & PHP 8.2 安装

    Nginx 1 20 版本安装 使用 dnf module 选择 nginx 版本 如果不选择 默认安装 1 14 版 1 先 RESET 一下 xxx ecs 209716 sudo dnf module reset nginx Repo
  • 子网划分,子网掩码

    1 IP地址分类 有类编址 所谓的同一网段就是 网络位一模一样 才叫在同一网段 否则不是在同一网段 网络位 主机位 固定电话的区号 025 主机你的电话号码 85562264 同一区号 之间 漫游费 南京 徐州 苏州 漫游 借助路由器转发我
  • Qt多线程中的moveToThread()的简单用法

    之前在项目中用到了Qt的多线程 因为以前用的一直是用一个类直接继承QThread 然后再重写run 方法 需要注意的是 QThread只有run函数是在新线程里的 其他所有函数都在QThread生成的线程里 后来查阅了一些资料才知道 Qt有
  • 00_Ubuntu系统入门

    目录 前言 一 Ubuntu系统安装 1 1 VMware15安装虚拟机不兼容 无法打开 1 2 Ubuntu联网问题 二 Ubuntu系统入门 2 1 Ubuntu系统初体验 2 2 Ubuntu终端操作 2 3 shell操作 2 3
  • 关于汇编语言寄存器和指令操作的整理

    最近汇编学到后面的内容 越来越觉得前面的基础没有掌握好 弄得最后编写汇编程序的时候 寄存器瞎用 没有一点的规矩 中断操作也不知道是对哪个寄存器里的数进行操作 每次做一个小程序 都得翻书后面的INT中断查询表 感觉很不爽 今天花了大半天把几本
  • 数据通信——因特网基础

    引言 之前最开始并接触学习的是华为的路由器交换机等知识 后来慢慢的扩充到了计算机网络 现在在备考计网专业课 因此写一下我对计网现阶段知识的认知 也是对考研备考时的一个复习 我将用易于理解的逻辑阐述下计网中难以理解的知识 希望大家也多多补充并
  • Visual C++ 运行窗口一闪而过的解决方法

    本文简单介绍了Visual C 编写运行程序的步骤 解决Visual C 2010开发环境中运行程序时运行窗口一闪而过的问题 总结了 断点调试 F5 方法 开始执行 Ctrl F5 方法 调试工具条方法 暂停语句或者输入等待方法 共4种方法
  • jvisualvm远程监控centos上虚拟机的状态

    要使用jvisualvm监视远程主机需要先再远程主机上运行jstatd 1 在 JAVA HOME bin目录下新建jstatd all policy文件 内容如下 grant codebase file java home lib too
  • 符号优先级误区一:移位运算符优先级比加减运算符低

    目录 移位运算符优先级比加减运算符低 误区 发现问题 实际结果 举例子证实 代码如下 实际结果 移位运算符优先级比加减运算符低 这是我在做二分查找时发现的问题 误区 发现问题 直接除2 int mid start end start 2 移
  • message from server: “Host is not allowed to connect to this MySQL server“问题的解决办法

    数据库安装完成后 默认是不能远程登陆的 只能在本地用localhost 或者127 0 0 1登录访问 如果需要远程登录 则需要修改mysql设置 具体修改方式 1 本地登录mysql root localhost mysql u root
  • Java的网络编程

    网络编程是指编写运行在多个设备 计算机 的程序 这些设备都通过网络连接起来 java net 包中 J2SE 的 API 包含有类和接口 它们提供低层次的通信细节 你可以直接使用这些类和接口 来专注于解决问题 而不用关注通信细节 java
  • react生命周期---参考学习20220726

    react生命周期笔记 笔记 react生命周期 链接 react生命周期 https projects wojtekmaj pl react lifecycle methods diagram 1 挂载时 挂载时调用四个生命周期函数 2
  • Nginx高可用实战

    来源 jingfengjiaoyu Nginx的特点 跨平台 Nginx 可以在大多数 Unix like OS编译运行 而且也有Windows的移植版本 配置异常简单 非常容易上手 配置风格跟程序开发一样 神一般的配置 非阻塞 高并发连接
  • [QT编程系列-42]: QT定时器

    目录 第1章 QT下的定时器 1 1 主要的对象 1 2 QTTimer定时的特点 1 3 QT高精度定时器QElapsedTimer 计时 第2章 Windows操作系统下的高性能定时器 2 1 时钟分辨率 2 2 两种来实现高性能定时器