【快速上手QT】04-定时器Timer

news2024/11/17 14:19:47

先来个小示例

我们先简单的来触发一下定时器。

#include "Zhetu.h"

#include <qdebug.h>

void Zhetu::timerEvent(QTimerEvent* event) {	//定时器触发函数
	qDebug() << "Hello world";
}

Zhetu::Zhetu(QWidget *parent): QMainWindow(parent){
	this->setFixedSize(500, 500);

	this->startTimer(1000);			//开启以1000ms为周期的定时器
}

上面的代码很简单,就是开启一个1000ms的定时器,定时器触发的时候调用timerEvent这个函数,并且输出调试信息“Hello world”。

这边有几个需要注意的点,就是定时器触发函数是固定的,就是要下面这个形式。

void timerEvent(QTimerEvent* event)

当然,形参的名字可以自己起,但是返回值,函数名,形参类型都是需要固定的。

并且我们能够看得出来,开启定时器的对象是我们的主界面(在主界面的构造函数中)。因此我们的定时器触发函数得是我们主界面这个类的成员函数。

startTimer

我们使用startTimer这个函数就使得我们的主界面调用了定时器,那么我是怎么知道用这个函数的呢?答案就是QT助手。

我们的主界面类继承的是QMainWindow这个类,那么我们就去搜索QMainWindow,我们去找有没有定时器相关的函数,答案是没有的。

既然QMainWindow没有,那么我们就去它的父类去找。

然而我们在它的父类里也找不到,那么我们再从QWidget的父类中去寻找。

QWidget的父类有两个,分别是QObject和QPaintDevice。

凭借我高超的英语水平(四级差122分),一眼就能看出我们需要从QObject里找,因为QPaintDevice根据直译来判断,应该是和图形化相关的。

果然我们能在QObject中找到相关函数。

当我们点击进去之后就能看到关于这个函数的详细的解释了。

凭借我高超的英语水平(四级差122分),一眼就能看出我看不懂,所以我们稍微翻译参考一下。

根据这个粗糙的翻译,我们可以知道调用这个函数之后会返回一个标识符(ID),并且定时器事件会在每个时间间隔触发,直到我们调用killTimer这个函数,很明显这个函数是用来杀死(kill)定时器事件的。

我们再次点击进入killTimer这个函数。

我们知道startTimer会返回一个定时器ID,那么我们取消定时器,使用killTimer用的参数也是这个ID。

再回到我们的startTimer函数的解释里。

定时器事件触发之后,会调用TimerEvent函数。如果有多个定时器函数,我们还可以通过TimerEvent的参数去调用timerId来获取当前触发定时器函数的定时器ID是什么。

综上我们可以知道以下几个关键的信息。

  • startTimer是QObject的函数,而大多数组件都直接或间接继承了QObject,所以大多数组件都可以开启定时器。
  •  我们可以通过调用startTimer获取的定时器ID来删除定时器事件或是判断触发定时器事件的是哪个ID
  • 同类组件哪怕开启了多个定时器,但是定时器触发函数是固定的一个。

这样我们大概知道了怎么通过OBject的成员函数来开启定时器事件之后,我们就可以来测试一下了。

#include "Zhetu.h"

#include <qdebug.h>
#include <qpushbutton.h>

int windowID, buttonID;

void Zhetu::timerEvent(QTimerEvent* event) {	//定时器触发函数
	static int count = 0;
	if (event->timerId() == windowID) {		//获取触发定时器的ID,比较是否是主界面的定时器ID
		qDebug() << "w";
		if (++count >= 10) {
			killTimer(windowID);			//取消主界面定时器
			qDebug() << "kill window timer";
		}
	}
}

void QAbstractButton::timerEvent(QTimerEvent* event){
	static int count = 0;
	if (event->timerId() == buttonID) {		//获取触发定时器的ID,比较是否是按键的定时器ID
		qDebug() << "b";
		if (++count >= 10) {
			killTimer(buttonID);			//取消按键定时器
			qDebug() << "kill button timer";
		}
	}
}

Zhetu::Zhetu(QWidget *parent): QMainWindow(parent){
	this->setFixedSize(500, 500);

	QPushButton* button = new QPushButton("Timer", this);
	buttonID = button->startTimer(500);			//开启以500ms为周期的定时器

	windowID = this->startTimer(1000);			//开启以1000ms为周期的定时器
}

上面代码中,我用主界面开启了一个定时器,用一个普通的按键也开启了一个定时器。

由于它们所属的类不一样,因此需要重写两次TimerEvent函数。并且它们所属的类需要区分来开。

主界面的定时器触发函数的所属类就写Zhetu(我写的主界面类的名称)。

而按键的定时器触发函数的所属类需要写QAbstractButton,如果写QPushButton的话是不允许的,我已经试过了。

在各自的定时器触发函数中我通过调用参数的timerId来获取触发定时器事件的ID进行定时器ID的判断,各自触发十次之后取消定时器事件。

从下面运行结果的截图中也可以看的出来是没问题的。

QTimer

上面的开启定时器其实是够用了,不过这里还是介绍一下QTimer这个类,因为这个类才算得上是真正的定时器。

与startTimer不同的是,Timer开启定时器的方式是信号与槽函数。

我们照例先来个小例子。

#include "Zhetu.h"

#include <qdebug.h>
#include <QTimer> 

Zhetu::Zhetu(QWidget *parent): QMainWindow(parent){
	this->setFixedSize(500, 500);

	QTimer* t1 = new QTimer(this);
	connect(t1, &QTimer::timeout, [&]() {
		qDebug() << "hello world";
		});
	t1->start(1000);
}

既然触发定时器事件的是信号和槽函数,那么我们先看看QTimer都有些什么信号和槽函数。

看得出来信号只有一个,那就是timeout,凭借我高超的英语水平(四级差122分),一眼就能看出这个信号就是定时器定的时间到了之后发出的信号,也就是是计数溢出信号。

我们将这个信号和自定义的定时器触发函数进行绑定(connect),就可以达到触发定时器事件的目的了。

而我们可以调动槽函数去控制这个定时器 。

很明显start就是开启定时器,而stop就是关闭定时器。

那么我们通过上面一个小例子就可以知道如何使用Timer来实现定时器的周期计数了。

这边再介绍一个非周期计数,也就是只触发一次定时器事件的函数。

#include "Zhetu.h"

#include <qdebug.h>
#include <QTimer> 

Zhetu::Zhetu(QWidget *parent): QMainWindow(parent){
	this->setFixedSize(500, 500);

	QTimer* t1 = new QTimer(this);
	t1->singleShot(1000, []() {
		qDebug() << "Hello";
		});
}

Zhetu::~Zhetu()
{}

虽然我们使用周期定时器也可以达到同样的效果(触发一次之后就关闭周期定时器),但是这个非周期的定时器有一个特点,那就是它属于静态成员函数,也就是说我们不需要创建QTimer对象就可以使用这个函数。

这也是这个函数比较方便的一点。

QTimer::singleShot(1000, []() {
		qDebug() << "helo world";
		});

小结

关于定时器的使用我这里只是介绍了一点,但是对于我们需要快速上手的小伙伴来说是够用了,想要更近一步的小伙伴可以自己去查阅资料以及QT助手去自主进阶学习。

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

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

相关文章

实现可拖拽的页面元素排序更新数据库排序

摘要&#xff1a; 拖拽列表改变路边排序&#xff0c;并且更新后台数据库列表的排序&#xff0c;重新请求的时候获取拖拽后的排序&#xff01; Layui&#xff1a; // 拖拽内页顺序list document.querySelector(#view_side_tab);// 创建cruentItem存放将要拖动的元素let cruen…

JUC并发编程学习与实践

文章目录 学习资料创建和运行线程方法一&#xff1a;直接使用Thread方法二&#xff1a;使用Runnable配合Thread方法三&#xff1a;FutureTask配合Thread 线程的常见方法start与runsleep与yield线程的优先级 join方法详解interrupt线程打断interrupt线程打断后&#xff0c;线程不…

【成都游戏业:千游研发之都的发展与机遇】

成都游戏业&#xff1a; 千游研发之都的发展与机遇 作为我国西部游戏产业的龙头&#xff0c;成都这座城市正在高速发展&#xff0c;目标是崛起成为千亿级游戏研发之都。多年来&#xff0c;在政策扶持、人才汇聚以及文化底蕴等助力下&#xff0c;成都游戏业已经形成完整的产业链…

SAP MIGO发货过账的时候批次库存确定:事务码MBC1进行激活即可

事务码&#xff1a; MBC1 ~ MBC3 使用MBC1按照工厂层级进行激活 接下来MIGO发货过账的时候就可以使用批次库存确定了&#xff0c;点击下图中圈出来的库存确定按钮

Spring AOP 实现原理详解之 JDK 动态代理

目录 一. 前言 二. JDK 代理的示例 2.1. 不需要 Maven 依赖 2.2. 定义实体 2.3. 被代理的类和接口 2.4. JDK 代理类 2.5. 使用代理 三. JDK 代理的流程 3.1. ProxyGenerator 生成代码 3.2. 从生成的 Proxy 代码看执行流程 四. Spring AOP 中 JDK代理的实现 4.1. Sp…

【虚拟仿真】Unity3D中实现3DUI,并且实现Button、InputField、Toggle等事件绑定

推荐阅读 CSDN主页GitHub开源地址Unity3D插件分享简书地址大家好,我是佛系工程师☆恬静的小魔龙☆,不定时更新Unity开发技巧,觉得有用记得一键三连哦。 一、前言 最近在项目中需要用到3DUI的展示,之前一般会用TextMeshPro进行展示: 但是,后面又需要添加按钮、Toggle等…

[开源协议] 什么是MIT协议及其使用场景

什么是MIT协议? MIT协议是一种开放源代码软件授权协议&#xff0c;全称为Massachusetts Institute of Technology License。该协议允许自由地使用、复制、修改、合并、发布、分发、再授权和销售软件及其副本的任何部分。MIT协议要求在软件的所有副本中包含版权声明和许可声明…

Web基础②nginx搭建与配置

目录 一.Nginx概述 1.定义 2.Nginx模块作用 &#xff08;1&#xff09;main模块 &#xff08;2&#xff09;stream服务模块 &#xff08;3&#xff09;邮件服务模块 &#xff08;4&#xff09;第三方模块 &#xff08;5&#xff09;events模块 &#xff08;6&#xff…

WordPress如何将后台右上角管理员头像去除并调整注销位置及启用注销确认功能?

WordPress后台默认情况下右上角可以看到管理员昵称和头像&#xff0c;将鼠标移动到该昵称上还会出现一个下拉菜单&#xff0c;点击下拉菜单中的“注销”无需我们再次确认就会自动退出。 现在我想将WordPress后台右上角的管理员头像和管理员昵称子菜单去除&#xff0c;并将“注销…

探索亚马逊自养号测评的实际效果与使用感受

自养号在亚马逊测评中的应用给了我们一种全新的体验。通过使用亚马逊自养号&#xff0c;我们发现了许多令人满意的优势&#xff0c;这些优势不仅提升了我们的测评效率&#xff0c;还增加了我们的信誉度。 首先&#xff0c;自养号的质量可控性给了我们极大的信心。我们可以自行…

基于springboot+vue的高校学科竞赛系统(前后端分离)

博主主页&#xff1a;猫头鹰源码 博主简介&#xff1a;Java领域优质创作者、CSDN博客专家、阿里云专家博主、公司架构师、全网粉丝5万、专注Java技术领域和毕业设计项目实战&#xff0c;欢迎高校老师\讲师\同行交流合作 ​主要内容&#xff1a;毕业设计(Javaweb项目|小程序|Pyt…

Redis之缓存穿透问题解决方案实践SpringBoot3+Docker

文章目录 一、介绍二、方案介绍三、Redis Docker部署四、SpringBoot3 Base代码1. 依赖配置2. 基本代码 五、缓存优化代码1. 校验机制2. 布隆过滤器3. 逻辑优化 一、介绍 当一种请求&#xff0c;总是能越过缓存&#xff0c;调用数据库&#xff0c;就是缓存穿透。 比如当请求一…

利用LaTex批量将eps转pdf、png转eps、eps转png、eps转svg

1、eps转pdf 直接使用epstopdf命令&#xff08;texlive、mitex自带&#xff09;。 在cmd中进入到eps矢量图片的目录&#xff0c;使用下面的命令&#xff1a; for %f in (*.eps) do epstopdf "%f" 下面是plt保存eps代码&#xff1a; import matplotlib.pyplot as…

挑战6万月薪【三】Purple Pi OH开发板带你7天入门OpenHarmony!

现在为止&#xff0c;我们已经完成了Purple Pi OH主板的串口调试和部分配件的连接&#xff0c;接下来&#xff0c;让我们趁热打铁&#xff0c;完成剩余配件的连接&#xff01; 注&#xff1a;配件连接前请断开主板所有供电&#xff0c;避免敏感电路损坏&#xff01; 一. 接口…

计算机网络-局域网

文章目录 局域网局域网拓扑结构以太网以太网传输介质以太网时隙提高传统以太网带宽的途径以太网帧格式 局域网协议IEEE 802参考模型IEEE802.2协议LLC帧格式及其控制字段LLC提供的三种服务 IEEE 802.3协议IEEE 802.4协议IEEE 802.5协议 高速局域网100M以太网千兆以太网万兆以太网…

ubuntu22.04@Jetson Orin Nano之CSI IMX219安装

ubuntu22.04Jetson Orin Nano之CSI IMX219安装 1. 源由2. 安装2.1 硬件安装2.2 软件配置2.3 新增摄像头 3. 效果4. 参考资料 1. 源由 折腾半天时间&#xff0c;捣鼓这个套装摄像头(IMX219)的安装&#xff0c;死活就是没有这个设备。世界总是这么小&#xff0c;看看遇到问题的大…

吴恩达机器学习全课程笔记第三篇

目录 前言 P42-P48 神经元和大脑 神经网络中的层 更复杂的神经网络 前向传播&#xff08;做出预测&#xff09; P49-P53 代码中的推理 构建一个神经网络 P54-P60 矩阵乘法 TensorFlow框架实现神经网络 前言 这是吴恩达机器学习笔记的第三篇&#xff0c;第二篇笔记…

C#知识点-16(计算器插件开发、事件、递归、XML)

计算器插件开发 1、Calculator.cs using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks;namespace Calculator_DLL {//用来明确所有插件开发人员的开发规范public abstract class Calculator{public int N…

2024作品集设计指南:3个你需要知道的趋势!

如果你想在面试中获得额外的分数&#xff0c;你的首要任务是仔细准备一个个人作品集。作品集是展示设计师个人能力的载体。一个优秀的作品集不仅可以向面试官展示你的设计技巧&#xff0c;还可以通过将作品集与设计趋势“融合”来体现你对市场的关注。“设计技能市场思维”的作…

Linux环境下查看磁盘层级占用空间的解决方案

大家好,我是爱编程的喵喵。双985硕士毕业,现担任全栈工程师一职,热衷于将数据思维应用到工作与生活中。从事机器学习以及相关的前后端开发工作。曾在阿里云、科大讯飞、CCF等比赛获得多次Top名次。现为CSDN博客专家、人工智能领域优质创作者。喜欢通过博客创作的方式对所学的…