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

描述

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;

结论

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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

安卓apk抓包(apk抓不到包怎么办)

起因 手机&#xff08;模拟器&#xff09;有时候抓不到apk的包&#xff0c;需要借助Postern设置一个代理&#xff0c;把模拟器的流量代理到物理机的burp上。 解决方案 使用Postern代理&#xff0c;把apk的流量代理到burp。 Postern是一个用于代理和网络流量路由的工具&#xf…

智能优化算法应用:基于黑猩猩算法无线传感器网络(WSN)覆盖优化 - 附代码

智能优化算法应用&#xff1a;基于黑猩猩算法无线传感器网络(WSN)覆盖优化 - 附代码 文章目录 智能优化算法应用&#xff1a;基于黑猩猩算法无线传感器网络(WSN)覆盖优化 - 附代码1.无线传感网络节点模型2.覆盖数学模型及分析3.黑猩猩算法4.实验参数设定5.算法结果6.参考文献7.…

根文件系统lib库添加与初步测试

一. 简介 我们在编译 busybox源码时&#xff0c;选择的是动态编译&#xff0c;所以&#xff0c;制作生成的 根文件系统中/bin或 /sbin目录下软件运行时会调用到一些库文件的。库文件就是交叉编译器的库文件。 前面我们编译 busybox源码时&#xff0c;选择动态编译&#xff0…

APP逆向工具环境安装

环境安装及配置&#xff1a; 1.JDK安装及配置链接&#xff1a;https://pan.baidu.com/s/146I4vDJdz8YeR0OEqLS8xw 提取码&#xff1a;7h00 2.SDK环境配置链接&#xff1a;https://pan.baidu.com/s/1A8rwqyw8Nn7p93Axqpll3A 提取码&#xff1a;cwv43.NDK环境配置链接&#xff1…

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

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

华清远见嵌入式学习——C++——作业5

作业要求&#xff1a; 代码&#xff1a; #include <iostream>using namespace std;//沙发 类 class Sofa { private:string sitting; //是否可坐double *cost; //花费 public://无参构造函数Sofa(){}//有参构造函数Sofa(string s,double c):sitting(s),cost(new double(…

Python面向对象练习

Python面向对象练习 class Enty:blood100name""atackvalue100team0domain[1] #1,land 2 airdef setTeam(self,team0):self.teamteamdef atack(self,Enty):if self.teamEnty.team:print("不能向盟军开火")self.info()passelse :# print(self.domain)ss…

Python入门07循环及常见的数据结构

目录 1 循环的语法结构2 break和continue的示例3 可迭代对象4 列表5 元组6 列表和元组的应用场景7 集合8 字典9 生成器 1 循环的语法结构 在Python中&#xff0c;循环是一种控制结构&#xff0c;用于重复执行一段代码&#xff0c;直到满足特定条件。Python中有两种循环结构&am…

【超详细教程】基于html+js实现轮播图

轮播图是现代网页设计中常见的元素之一&#xff0c;它能够展示多张图片或内容&#xff0c;在有限的空间内循环播放&#xff0c;提升网页的视觉效果和用户体验。下面将以一个简单的网页轮播图为例&#xff0c;说明如何基于HTML和JavaScript实现。 ​ 1、R5Ai智能助手 chatgpt国…

Tap虚拟网卡 (草稿)

1 概述 Tap设备通常用于虚拟化场景下&#xff0c;参考如下场景&#xff1a; 图中标注了关键函数&#xff0c;以及数据流向。 tun有两个数据接口&#xff0c; file&#xff0c;给用户态使用&#xff1b;socket&#xff0c;给内核态使用&#xff0c;例如vhost 2 异步处理 图…

他山之石,可以攻玉|银行业数据中心数字化转型之模型篇 04(完结)

导语&#xff1a;他山之石&#xff0c;可以攻玉&#xff5c;银行业数据中心数字化转型之模型篇 04&#xff08;完结&#xff09; 银行业数据中心数字化转型是一项系统性工程既涉及管理层面转型——包括数字化转型战略、基础架构和技术架构转型、技术创新和知识体系转型&#xf…

2023Q4 私有化版本发布,和鲸 ModelWhale 持续赋能大科研、高校教改的 AI for Science

作为数据科学多人协同平台&#xff0c;和鲸 ModelWhale 从一而终地为各级用户提供完备而周全的解决方案&#xff0c;覆盖数据研究、算法探索、模型调优、Python 案例教学等多个场景。特别地&#xff0c;如果对研究分析平台有更高的安全合规要求、希望兼容原有业务系统&#xff…

安全测试工具Burpsuit和OWASP ZAP使用入门指南

Burpsuit使用入门指南 安装&#xff1a; 网上有很多相关相关保姆级别教程&#xff0c;所以这里不加赘述了 尽量使用java8版本&#xff0c;破解版兼容8做的比较好 如果发现注册机无法打开或者能打开注册机【run】无法点击唤起软件安装&#xff0c;可以使用命令行工具java -jar…

深入解析常见的软件架构模式

在软件开发领域&#xff0c;选择合适的架构模式对于项目的可维护性和扩展性至关重要。本文将深入探讨常见的软件架构模式&#xff0c;包括MVC、MVP、MVVM、MVVM-C以及VIPER。 1. MVC&#xff08;Model-View-Controller&#xff09; MVC 是一种经典的软件架构模式&#xff0c;将…

一天一个设计模式---生成器模式

概念 生成器模式&#xff08;Builder Pattern&#xff09;是一种创建型设计模式&#xff0c;用于构建复杂对象。它允许您逐步构造一个对象&#xff0c;将构建过程与最终对象的表示分离开来。这种模式通常用于创建复杂的对象&#xff0c;这些对象可能有多个部分组成&#xff0c…

探索人工智能领域——每日20个名词详解【day7】

目录 前言 正文 总结 &#x1f308;嗨&#xff01;我是Filotimo__&#x1f308;。很高兴与大家相识&#xff0c;希望我的博客能对你有所帮助。 &#x1f4a1;本文由Filotimo__✍️原创&#xff0c;首发于CSDN&#x1f4da;。 &#x1f4e3;如需转载&#xff0c;请事先与我联系以…

智能优化算法应用:基于社会群体算法无线传感器网络(WSN)覆盖优化 - 附代码

智能优化算法应用&#xff1a;基于社会群体算法无线传感器网络(WSN)覆盖优化 - 附代码 文章目录 智能优化算法应用&#xff1a;基于社会群体算法无线传感器网络(WSN)覆盖优化 - 附代码1.无线传感网络节点模型2.覆盖数学模型及分析3.社会群体算法4.实验参数设定5.算法结果6.参考…

Spring Security 自定义异常失效?源码分析与解决方案

&#x1f680; 作者主页&#xff1a; 有来技术 &#x1f525; 开源项目&#xff1a; youlai-mall &#x1f343; vue3-element-admin &#x1f343; youlai-boot &#x1f33a; 仓库主页&#xff1a; Gitee &#x1f4ab; Github &#x1f4ab; GitCode &#x1f496; 欢迎点赞…

用python删除指定目录下带某个字符串的图片

前言&#xff1a; 在文件处理中&#xff0c;有时我们需要批量删除指定文件夹中的特定类型文件。如果文件数量非常庞大&#xff0c;手动删除会非常麻烦&#xff0c;所有可以用 Python 编写一个简单而高效的脚本&#xff0c;自动执行重复性的任务&#xff0c;从而节省时间和精力&…

Intellij idea 快速定位到文件的开头或者结尾的几种方式

方式一&#xff1a;Scroll To Top / Scroll To Bottom 首先打开Keymap设置&#xff0c;并搜索Scroll To 依次点击File->Settings->Keymap可打开该界面 对于Scroll To Top 快速滑动定位到文件顶部&#xff0c; Scroll To Bottom快速定位到文件底部 默认是没有设置快捷键的…