【Qt开发流程】之定时器事件与随机数示例

news2024/11/18 13:46:26

描述

QObject是所有Qt对象的基类,提供了Qt中基础的定时器支持。通过QObject::startTimer()函数,可以使用毫秒为单位的时间间隔来启动一个定时器。该函数返回一个唯一的整数定时器ID。该计时器现在将以规律的间隔触发,直到显式调用QObject::killTimer()函数并传入计时器ID为止。
为了使此机制工作,应用程序必须在事件循环中运行。可以使用QApplication::exec()函数启动事件循环。当计时器触发时,应用程序会发送一个QTimerEvent,并且控制流会离开事件循环,直到处理计时器事件。这意味着在应用程序忙于做其他事情时,计时器不能触发。换句话说:计时器的准确性取决于应用程序的粒度。
在多线程的应用程序中,可以在具有事件循环的任何线程中使用计时器机制。要在非GUI线程中启动事件循环,请使用QThread::exec()。Qt使用对象的线程亲和性来确定哪个线程将传递QTimerEvent。因此,必须在对象的线程中启动和停止所有计时器;无法为另一个线程中的对象启动计时器。
时间间隔值的上限由可以在有符号整数中指定的毫秒数确定(实际上,这是略微超过24天的时间段)。准确性取决于底层操作系统。Windows 2000具有15毫秒的准确性;有的其他系统可以处理1毫秒的间隔。
定时器功能的主要API是QTimer。该类提供定期定时器,当定时器触发时会发出信号,并继承QObject,因此适合大多数GUI程序的所有权结构。通常的使用方式如下所示:

      QTimer *timer = new QTimer(this);
      connect(timer, SIGNAL(timeout()), this, SLOT(updateCaption()));
      timer->start(1000);

QTimer对象被设置为该窗口小部件的子项,因此当该窗口小部件被删除时,计时器也将被删除。接下来,将其timeout()信号连接到要进行的工作的槽,并启动它。它使用1000毫秒的值启动,表示它将每秒触发一次超时事件。
QTimer还提供了一个用于短期定时器的静态函数。例如:

      QTimer::singleShot(200, this, SLOT(updateCaption()));

在执行此代码行后200毫秒(0.2秒),将调用updateCaption()槽。
为了使QTimer工作,必须在应用程序中有一个事件循环;也就是说,必须在某个地方调用QCoreApplication::exec()。只有在事件循环运行时,计时器事件才会被传递。
在多线程的应用程序中,可以在具有事件循环的任何线程中使用QTimer。要在非GUI线程中启动事件循环,请使用QThread::exec()。由于Qt使用定时器的线程关联性来确定哪个线程将发出timeout()信号,因此必须在其线程中启动和停止计时器;无法从另一个线程启动计时器。
如果已经有了一个QObject子类并且想要进行简单的优化,可以使用QBasicTimer而不是QTimer。使用QBasicTimer,必须在QObject的子类中重新实现timerEvent()函数,并在那里处理超时。

QTimer类

QTimer类提供了重复的单次计时器。
QTimer类为计时器提供了一个高级编程接口。要使用它,需要创建一个QTimer,将其timeout()信号连接到适当的插槽,然后调用start()。从那时起,它将以恒定的间隔发出timeout()信号。
1秒(1000毫秒)定时器的示例(来自模拟时钟示例):

      QTimer *timer = new QTimer(this);
      connect(timer, SIGNAL(timeout()), this, SLOT(update()));
      timer->start(1000);

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

QTimer::singleShot(200, this, SLOT(updateCaption()));

在多线程应用程序中,您可以在任何具有事件循环的线程中使用QTimer。要从非gui线程启动事件循环,请使用QThread::exec()。Qt使用定时器的线程关联来确定哪个线程将发出timeout()信号。因此,必须在其线程中启动和停止计时器;不可能从另一个线程启动计时器。
作为一种特殊情况,超时为0的QTimer将在处理完窗口系统事件队列中的所有事件后立即超时。这可以用来做繁重的工作,同时提供一个时髦的用户界面:

QTimer *timer = new QTimer(this);
connect(timer, SIGNAL(timeout())this, SLOT(processOneThing()));
timer- > start ();

从那时起,processOneThing()将被反复调用。它应该以这样一种方式编写,即它总是快速返回(通常在处理一个数据项之后),以便Qt可以将事件传递给用户界面并在完成所有工作后立即停止计时器。这是在GUI应用程序中实现繁重工作的传统方式,但是随着多线程在越来越多的平台上变得可用,我们期望零毫秒的QTimer对象将逐渐被qthread所取代。

精度和计时器分辨率

计时器的准确性取决于底层操作系统和硬件。大多数平台支持1毫秒的分辨率,尽管在许多实际情况下计时器的精度不等于这个分辨率。
准确度还取决于计时器的类型。对于Qt:: precistimer, QTimer将尝试将精度保持在1毫秒。精确的计时器也不会比预期更早超时。
对于Qt::CoarseTimer和Qt::VeryCoarseTimer类型,QTimer可能比预期更早唤醒,在这些类型的间隔范围内:Qt::CoarseTimer的间隔为5%,Qt::VeryCoarseTimer的间隔为500毫秒。
如果系统繁忙或无法提供所要求的准确性,所有计时器类型都可能超时,超时时间晚于预期。在这种超时超时的情况下,即使多个超时已经过期,Qt也只会发出一次activated(),然后恢复原来的时间间隔。

QTimer的替代品

使用QTimer的另一种方法是为对象调用QObject::startTimer(),并在类中重新实现QObject::timerEvent()事件处理程序(必须继承QObject)。缺点是timerEvent()不支持单次计时器或信号等高级特性。
另一个选择是QBasicTimer。它通常比直接使用QObject::startTimer()要简单。
一些操作系统限制可以使用的计时器的数量;Qt试图绕过这些限制。

QTimer常用方法
  1. std::chrono::milliseconds QTimer::intervalAsDuration() const
    以std::chrono::milliseconds对象的形式返回计时器的间隔。

  2. bool QTimer::isActive() const
    如果计时器正在运行(等待触发)则返回true,否则返回false。
    注意:active属性的getter函数。

  3. std::chrono::milliseconds QTimer::remainingTimeAsDuration() const
    以std::chrono::milliseconds对象的形式返回计时器对象的剩余时间。如果计时器已到期或已超时,则返回std::chrono::milliseconds::zero()。如果找不到剩余时间或计时器未处于活动状态,则该函数返回负持续时间。

  4. [static] void QTimer::singleShot(int msec, const QObject *receiver, const char *member)
    此静态函数在给定的时间间隔后调用槽。
    使用此函数非常方便,因为不需要使用timerEvent或创建本地QTimer对象。
    示例:

#include <QApplication>
#include <QTimer>

int main(int argc, char *argv[])
{
  QApplication app(argc, argv);
  QTimer::singleShot(600000, &app, SLOT(quit()));
  ...
  return app.exec();
}

该示例程序在10分钟后自动终止(600,000毫秒)。
接收者是接收对象,成员是槽。时间间隔为msec毫秒。

  1. [static] void QTimer::singleShot(int msec, Qt::TimerType timerType, const QObject *receiver, const char *member)
    此函数是重载函数。
    此静态函数在给定的时间间隔后调用槽。
    使用此函数非常方便,因为您不需要使用timerEvent或创建本地QTimer对象。
    接收者是接收对象,成员是槽。时间间隔为msec毫秒。timerType影响计时器的准确性。

  2. [static] void QTimer::singleShot(int msec, Qt::TimerType timerType, const QObject *receiver, PointerToMemberFunction method)
    此函数是重载函数。
    此静态函数在给定的时间间隔后调用QObject的成员函数。
    使用此函数非常方便,因为您不需要使用timerEvent或创建本地QTimer对象。
    接收者是接收对象,method是成员函数。时间间隔为msec毫秒。timerType影响计时器的准确性。
    如果在时间间隔到达之前接收者被销毁,则不会调用该方法。该函数将在接收对象的线程中运行。接收者的线程必须具有运行的Qt事件循环。

  3. [static] void QTimer::singleShot(int msec, Functor functor)
    此函数是重载函数。
    在给定的时间间隔之后,该静态函数将调用functor。
    使用此函数非常方便,因为您不需要使用timerEvent或创建本地QTimer对象。
    时间间隔为msec毫秒。

  4. [static] void QTimer::singleShot(int msec, Qt::TimerType timerType, const QObject *context, Functor functor)
    此函数是重载函数。
    在给定的时间间隔之后,该静态函数将调用functor。
    使用此函数非常方便,因为您不需要使用timerEvent或创建本地QTimer对象。
    时间间隔为msec毫秒。timerType影响计时器的准确性。
    如果在时间间隔到达之前上下文被销毁,则不会调用该函数。该函数将在上下文的线程中运行。上下文的线程必须具有运行的Qt事件循环。

  5. [static] void QTimer::singleShot(std::chrono::milliseconds msec, const QObject *receiver, const char *member)
    此函数是重载函数。
    在给定的时间间隔之后,该静态函数将调用槽。
    使用此函数非常方便,因为您不需要使用timerEvent或创建本地QTimer对象。
    接收者是接收对象,member是槽。时间间隔以duration对象msec的形式给出。

  6. [slot] void QTimer::start(int msec)
    使用msec毫秒的超时间隔启动或重新启动计时器。
    如果计时器已经在运行,则停止并重新启动。
    如果singleShot为true,则计时器仅会被激活一次。

  7. [slot] void QTimer::start()
    该函数重载start()。
    使用interval指定的超时间隔启动或重新启动计时器。
    如果计时器已经在运行,则停止并重新启动。
    如果singleShot为true,则计时器仅会被激活一次。

  8. void QTimer::start(std::chrono::milliseconds msec)
    这是一种重载函数。
    使用持续时间msec毫秒的超时启动或重新启动计时器。
    如果计时器已经在运行,则停止并重新启动。
    如果singleShot为true,则计时器仅会被激活一次。

  9. [slot] void QTimer::stop()
    停止计时器。

  10. [signal] void QTimer::timeout()
    当计时器超时时发出此信号。
    注意:这是一个私有信号。它可以用于信号连接,但用户不能发出它。

  11. [virtual protected] void QTimer::timerEvent(QTimerEvent *e)
    重新实现自QObject::timerEvent()。

  12. int QTimer::timerId() const
    如果计时器正在运行,则返回计时器的ID;否则返回-1。

QTimerEvent类

QTimerEvent类包含描述计时器事件的参数。
计时器事件定期发送给启动了一个或多个计时器的对象。每个计时器都有一个唯一的标识符。计时器通过QObject::startTimer()启动。
QTimer类提供了一个使用信号而不是事件的高级编程接口。它还提供单次计时器。
事件处理程序QObject::timerEvent()接收定时器事件。

  class MyObject : public QObject
  {
      Q_OBJECT

  public:
      MyObject(QObject *parent = 0);

  protected:
      void timerEvent(QTimerEvent *event);
  };

  MyObject::MyObject(QObject *parent)
      : QObject(parent)
  {
      startTimer(50);     // 50-millisecond timer
      startTimer(1000);   // 1-second timer
      startTimer(60000);  // 1-minute timer

      using namespace std::chrono;
      startTimer(milliseconds(50));
      startTimer(seconds(1));
      startTimer(minutes(1));

      // since C++14 we can use std::chrono::duration literals, e.g.:
      startTimer(100ms);
      startTimer(5s);
      startTimer(2min);
      startTimer(1h);
  }

  void MyObject::timerEvent(QTimerEvent *event)
  {
      qDebug() << "Timer ID:" << event->timerId();
  }

定时器示例

下面是一个使用定时器在界面显示当前时间的示例。
.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QTimer>
#include <QTimerEvent>

namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    explicit MainWindow(QWidget *parent = nullptr);
    ~MainWindow();

protected:
    void timerEvent(QTimerEvent *event);

private:
    Ui::MainWindow *ui;
    int mTimerId;
};

#endif // MAINWINDOW_H

.cpp

#include "mainwindow.h"
#include "ui_mainwindow.h"

#include <QTime>

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    mTimerId = startTimer(1000);
}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::timerEvent(QTimerEvent *event)
{
    if(event->timerId() == mTimerId)
    {
        ui->label->setText(QTime::currentTime().toString("hh:mm:ss"));
    }
    QMainWindow::timerEvent(event);
}

在这里插入图片描述

随机数

void qsrand(uint seed)
标准c++ srand()函数的线程安全版本。
设置参数seed,用于生成由qrand()返回的伪随机整数组成的新随机数序列。
每个线程生成的随机数序列是确定的。例如,如果两个线程调用qsrand(1)并随后调用qrand(),则线程将获得相同的随机数序列。
使用时,需要在构造中,添加以下代码,不然每次生成的随机数都是一样的,称为"伪随机"。

qsrand(QTime(0, 0, 0).msecsTo(QTime::currentTime()));
int nRand = qrand()%100+1;
qDebug() << "nRand : " << nRand;

结论

生活不止眼前的苟且,还有未来的苟且

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

谷歌用AI模型发现220万种新材料,研究能力超越人类!

谷歌旗下的AI研究机构DeepMind在全球顶级学术期刊《Nature》上发布了一篇论文&#xff0c;通过深度学习、计算机视觉、大数据等&#xff0c;开发了一个名为GNoME的图神经网络模型&#xff0c;主要用于材料发现。 研究团队通过GnoME便快速发现了220万个新的材料晶体结构&#x…

JVM==>图解字节码指令

一&#xff0c;原始代码 我们来看一下执行这段代码的具体流程 那执行这段代码中 JVM就会把已经编译好的.class文件加载到内存中&#xff0c;交给CPU运行 1&#xff09;常量池载入运行时常量池 我们发现 10 并没有被存入常量池中&#xff0c; 这是因为short范围以内的数字不会…

微机原理9

一、单项选择题(本大题共15小题,每小题3分、共45分。在每小题给出的四个备选项中,选出一个正确的答案,请将选定的答案填涂在答题纸的相应位置上。) 8088 系统的内存最大容量为 16MB. 其地址总线为&#xff08;&#xff09; A. 16 位 B. 20 位 C. 24 位 D. 32 位 2,以CPU为核心…

YITH WooCommerce Social Login跨境电商网站社交登录高级版插件

点击阅读YITH WooCommerce Social Login跨境电商网站社交登录高级版插件原文 YITH WooCommerce Social Login跨境电商网站社交登录高级版插件让您的用户节省时间并通过他们的社交资料之一登录或注册网站。 您如何从中受益&#xff1a; 用户无需填写表格、插入个人数据&#…

【数电笔记】06-码制

目录 说明&#xff1a; 二进制代码 1. 二 - 十进制码 2. 常用二 - 十进制代码表 2.1 例题 可靠性代码 1. 格雷码 2. 奇偶校验码 3. 8421奇偶校验码表 说明&#xff1a; 笔记配套视频来源&#xff1a;B站&#xff1b;本系列笔记并未记录所有章节&#xff0c;只对个人认…

计算机基础知识64

ForeignKey属性 to&#xff1a;设置要关联的表 related_name&#xff1a; 反向操作时&#xff0c;使用的字段名&#xff0c;用于代替原反向查询时的’表名_set’ related_query_name:反向查询操作时&#xff0c;使用的连接前缀&#xff0c;用于替换表名 to_field:设置要关联的表…

【数据分享】2015-2023年我国区县逐月二手房房价数据(Excel/Shp格式)

房价是一个城市发展程度的重要体现&#xff0c;一个城市的房价越高通常代表这个城市越发达&#xff0c;对于人口的吸引力越大&#xff01;因此&#xff0c;房价数据是我们在各项城市研究中都非常常用的数据&#xff01;之前我们分享过2015-2023年我国地级市逐月房价数据&#x…

关于你对 Zookeeper 的理解

看看普通人和高手是如何回答这个问题的&#xff1f; 普通人 Zookeeper 是一种开放源码的分布式应用程序协调服务 是一个分布式的小文件存储系统 一般对开发者屏蔽分布式应用开发过过程种的底层细节 用来解决分布式集群中应用系统的一致性问题 高手 对于 Zookeeper 的理解…

【ArcGIS Pro微课1000例】0047:深度学习--棕榈树提取全流程

一、创建训练样本 对汤加科洛瓦伊种植园每棵棕榈树的健康状况进行清查和评估,这需要花费大量的时间和劳动力。 为简化此过程,将在 ArcGIS Pro 中使用深度学习模型来识别树木,然后根据植被绿度的测量值计算其健康状况。 第一步是找到显示汤加科洛瓦伊的影像,该影像具有足够…

VQD视频质量诊断服务/图像质量诊断/视频流质量诊断/传统方法与深度学习结合的视频质量诊断

随着平安城市、大安防的发展&#xff0c;监控摄像机数量的不断增加&#xff0c;给监控系统的维护工作带来了新的挑战。如何及时了解前端视频设备的运行情况&#xff0c;发现故障并检测恶意遮挡与破坏的不法行为已成为视频监控系统运行的首要迫切问题。对于成千上万个监控摄像机…

Vue3 组合式实现 带连接线的Tree型 架构图(一级树形图)

创建组件名称 TreeNodeView.vue <template><div class"tree-node"><div class"node">{{ rootNodeName }}</div><div class"children" :style"childrenLineStyle"><div class"child-node"…

练习十一:简单卷积器的设计

简单卷积器的设计 1&#xff0c;任务目的&#xff1a;2&#xff0c;明确设计任务2.1,目前这部分代码两个文件没找到&#xff0c;见第5、6节&#xff0c;待解决中。 &#xff0c;卷积器的设计&#xff0c;RTL&#xff1a;con1.v4&#xff0c;前仿真和后仿真&#xff0c;测试信号…

一键自动修改和翻新OC源码,解决苹果审核4.3和马甲问题

ipaguard 自动修改/翻新/混淆/OC/iOS代码&#xff0c;自动替换类名&#xff0c;方法名 由来 网上有很多关于如何混淆iOS源码的方法&#xff0c;但是都不够智能&#xff0c;生成的方法类名要么千奇百怪&#xff0c;要么aaaabbbxxx这种完全毫无意义的名称&#xff0c;要么只能…

全网最新最全的自动化测试:python+pytest接口自动化-接口测试基础

接口定义 一般我们所说的接口即API&#xff0c;那什么又是API呢&#xff0c;百度给的定义如下&#xff1a; API&#xff08;Application Programming Interface&#xff0c;应用程序接口&#xff09;是一些预先定义的接口&#xff08;如函数、HTTP接口&#xff09;&#xff0c…

TEMU跨境平台与亚马逊检测认证几大认证您知道多少?

TEMU跨境平台与亚马逊检测认证几大认证您知道多少&#xff1f; TEMU跨境平台与亚马逊对于做外贸的人应该都不陌生,可是你是否知道产品入驻TEMU跨境平台与亚马逊需要办理的13大认证呢?如果你不知道,请认真阅读正面的内容,因为它关系着你的产品能否在TEMU跨境平台与亚马逊顺利上…

零基础学编程,中文编程工具构件之弹出菜单构件教程,中文编程工具下载

一、前言&#xff1a; 零基础自学编程&#xff0c;中文编程工具下载&#xff0c;中文编程工具构件之扩展系统菜单构件教程 编程系统化教程链接https://jywxz.blog.csdn.net/article/details/134073098?spm1001.2014.3001.5502 给大家分享一款中文编程工具&#xff0c;零基础…

二进制动态插桩工具intel PIN的学习笔记

前言 最近两周为了课程汇报学习了intel PIN这个动态插桩&#xff08;dynamic instrument&#xff09;工具&#xff0c;总体的学习感受还是挺累的。一方面&#xff0c;这个方向比较小众&#xff0c;相关的二手资料比较少&#xff0c;能参考的也就只有官方手册这种一手资料&…

12.4c++中的继承

#include <iostream>using namespace std;class Sofa { private:string way;int *score; public:Sofa(){}//有参构造函数Sofa(string way,int score):way(way),score(new int(score)){cout << "Sofa::有参构造函数" << endl;}//拷贝构造函数Sofa(c…

从声纹模型到语音合成:音频处理 AI 技术前沿 | 开源专题 No.45

facebookresearch/audiocraft Stars: 16.6k License: MIT AudioCraft 是一个用于音频生成的 PyTorch 库。它包含了两个最先进的 AI 生成模型 (AudioGen 和 MusicGen) 的推理和训练代码&#xff0c;可以产生高质量音频。该项目还提供了其他功能&#xff1a; MusicGen&#xf…

12月4日作业

完成沙发床的多继承 #include <iostream>using namespace std;class Bed { private:string sleeping; public:double *price; public:Bed(){cout << "Bed::无参构造函数" << endl;}Bed(string sleeping,int price):sleeping(sleeping),price(new …