1.4 Qt定时器类QTimer
1. 定时器QTimer
在进行窗口程序的处理过程中, 经常要周期性的执行某些操作, 或者制作一些动画效果,看似比较复杂的问题使用定时器就可以完美的解决这些问题, Qt中提供了两种定时器方式,一种是使用Qt中的事件处理函数这个在后续章节会给大家做细致的讲解,本节主要给大家介绍一下Qt中的定时器类
QTimer的使用方法。要使用它,只需创建一个QTimer类对象,然后调用其
start()函数开启定时器,此后QTimer对象就会周期性的发出timeout()信号。我们先来了解一下这个类的相关API。1.1 public/slot function
// 构造函数 // 如果指定了父对象, 创建的堆内存可以自动析构 QTimer::QTimer(QObject *parent = nullptr); // 设置定时器时间间隔为 msec 毫秒 // 默认值是0,一旦窗口系统事件队列中的所有事件都已经被处理完,一个时间间隔为0的QTimer就会触发 void QTimer::setInterval(int msec); // 获取定时器的时间间隔, 返回值单位: 毫秒 int QTimer::interval() const; // 根据指定的时间间隔启动或者重启定时器, 需要调用 setInterval() 设置时间间隔 [slot] void QTimer::start(); // 启动或重新启动定时器,超时间隔为msec毫秒。 [slot] void QTimer::start(int msec); // 停止定时器。 [slot] void QTimer::stop(); // 设置定时器精度 /* 参数: - Qt::PreciseTimer -> 精确的精度, 毫秒级 - Qt::CoarseTimer -> 粗糙的精度, 和1毫秒的误差在5%的范围内, 默认精度 - Qt::VeryCoarseTimer -> 非常粗糙的精度, 精度在1秒左右 */ void QTimer::setTimerType(Qt::TimerType atype); Qt::TimerType QTimer::timerType() const; // 获取当前定时器的精度 // 如果定时器正在运行,返回true; 否则返回false。 bool QTimer::isActive() const; // 判断定时器是否只触发一次 bool QTimer::isSingleShot() const; // 设置定时器是否只触发一次, 参数为true定时器只触发一次, 为false定时器重复触发, 默认为false void QTimer::setSingleShot(bool singleShot);1.2 signals
这个类的信号只有一个, 当定时器超时时,该信号就会被发射出来。给这个信号通过conect()关联一个槽函数, 就可以在槽函数中处理超时事件了。
// 当定时器超时时,该信号就会发出。 [signal] void QTimer::timeout();1.3 static public function
// 其他同名重载函数可以自己查阅帮助文档 /* 功能: 在msec毫秒后发射一次信号, 并且只发射一次 参数: - msec: 在msec毫秒后发射信号 - receiver: 接收信号的对象地址 - method: 槽函数地址 */ [static] void QTimer::singleShot(int msec, const QObject *receiver, PointerToMemberFunction method);1.4. 定时器使用举例
周期性定时器
// 创建定时器对象 QTimer* timer = new QTimer(this); // 修改定时器对象的精度 timer->setTimerType(Qt::PreciseTimer); // 按钮 loopBtn 的点击事件 // 点击按钮启动或者关闭定时器, 定时器启动, 周期性得到当前时间 connect(ui->loopBtn, &QPushButton::clicked, this, [=]() { // 启动定时器 if(timer->isActive()) { timer->stop(); // 关闭定时器 ui->loopBtn->setText("开始"); } else { ui->loopBtn->setText("关闭"); timer->start(1000); // 1000ms == 1s } }); connect(timer, &QTimer::timeout, this, [=]() { QTime tm = QTime::currentTime(); // 格式化当前得到的系统时间 QString tmstr = tm.toString("hh:mm:ss.zzz"); // 设置要显示的时间 ui->curTime->setText(tmstr); });一次性定时器
// 点击按钮 onceBtn 只发射一次信号 // 点击按钮一次, 发射一个信号, 得到某一个时间点的时间 connect(ui->onceBtn, &QPushButton::clicked, this, [=]() { // 获取2s以后的系统时间, 不创建定时器对象, 直接使用类的静态方法 QTimer::singleShot(2000, this, [=](){ QTime tm = QTime::currentTime(); // 格式化当前得到的系统时间 QString tmstr = tm.toString("hh:mm:ss.zzz"); // 设置要显示的时间 ui->onceTime->setText(tmstr); }); });
笔记
1.QTimer类的常用API介绍
构造函数只有一个父对象类型的指针,用于把这个节点挂到一棵对象树上,最终可以实现内存的自动回收
把父对象指针传进去后,子对象内部记录了这个父对象的地址(子找父),同时父对象把子对象的指针加入自己的子对象列表(父找子)。这样建立了双向关系:父对象销毁时能通过列表找到所有子对象并销毁它们,子对象也能通过 parent 指针找到父对象。
对象树运行原理
1.所有继承
QObject的类都自带父子链表;2.传入
parent时,内部会执行:父对象把当前对象加入自己的子对象列表;3.父对象析构时,递归销毁全部子对象;
4.典型场景:窗口上所有按钮、输入框、定时器都挂载窗口为父,窗口关闭一键全部回收内存。
首先通过构造函数创建QTimer对象,然后调用start方法去启动定时器,启动定时器必须设定一个时间间隔(定时周期),当定时周期到达之后,定时器就会发射一个timeout信号,然后就需要一个指定的槽函数来处理这个信号
设置定时器精度,获取定时器精度
判定当前定时器是否正在运行
默认情况下是发生多次,可以设置是否只发射一次
2.QTimer定时器类的使用举例
举例:获取系统时间,把系统时间显示到当前窗口中
新建一个基于窗口的应用程序
在ui界面放两个控件
loop 翻译:循环
新建一个Push Button改名为loopBtn
新建一个Label控件,改名为curTime
分析需求:点一下开始按钮,然后启动定时器,定时器进行周期性定时,当定时器出发一次timeout信号就通过槽函数把时间写到label控件中
操作:先进行信号槽连接处理按钮的点击事件,当窗口的按钮被按下去就会发出一个clicked信号,当前mainwindow窗口的实例对象捕捉到这个信号之后就会进行处理,通过匿名槽函数执行相应的动作。
首先设置定时器、启动定时器
设置定时器对象时把当前窗口对象作为父对象,当前mainwindow窗口被析构的时候定时器对象也会被释放。
设置定时器发射时间为1s,意味着1s之后一个timeout信号被发射出来,timeout信号发射后需要对这个信号进行处理,接着进行一个connect操作,当timeout信号发出后让当前对象this接收这个信号,然后通过匿名槽函数进行获取、显示当前系统时间的处理操作。
添加对应日期的头文件
#include <QTime>label槽函数中有一个方法setText可以把获取到的字符串信息设置到当前对象中,也就是显示到窗口中。
点击按钮进行的操作
进行优化:假设按钮按下去之后,开始就变成关闭,不能说定时器已经启动还能再次启动。
先判定当前定时器是否在工作,如果正在工作,就关闭定时器并把定时器显示为开始,当点击开始按钮定时器启动后就需要把按钮显示的标题改为关闭。
代码
#include "mainwindow.h" #include "ui_mainwindow.h" #include <QTimer> #include <QTime> MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) , ui(new Ui::MainWindow) { ui->setupUi(this); // ============================================================ // ★ 创建定时器对象 // ============================================================ QTimer* timer = new QTimer(this); // parent = this → MainWindow 销毁时自动清理定时器 // ============================================================ // ★ 连接1:按钮点击 → 启动/停止定时器 // ============================================================ connect(ui->loopBtn, &QPushButton::clicked, this, [=](){ if(timer->isActive()) // 定时器运行中 → 停止 { timer->stop(); ui->loopBtn->setText("开始"); // 按钮提示"开始" } else // 定时器已停止 → 启动 { ui->loopBtn->setText("关闭"); // 按钮提示"关闭" timer->start(1000); // 每秒触发一次 timeout } }); // ============================================================ // ★ 连接2:定时器 timeout → 自动更新时间显示 // ============================================================ connect(timer, &QTimer::timeout, this, [=](){ QTime tm = QTime::currentTime(); // 获取当前时间 QString tmstr = tm.toString("hh:mm:ss.zzz"); // 格式化 ui->curTime->setText(tmstr); // 更新显示 }); } MainWindow::~MainWindow() { delete ui; }
点击按钮会以1秒的间隔显示当前系统时间
可以注意到时间每过1s,毫秒的误差在几毫秒的范围内,如果对定时器精度要求更高,可以修改当前计时器对象的精度
setTimerType()参数是一个Qt::TimerType类型的枚举,
Qt::PreciseTimer是最高精度,启动显示偏差基本不变或者在1ms内
如何使用QTimer这个类一次性定时
在ui界面选中控件,按住ctrl键拖动复制一份
将第二个开始按钮的名称改为onceBtn,对应的label name也该成onceTime