在 GUI 开发、串口通信、动画刷新、任务调度等场景中,定时器是不可或缺的工具。Qt 提供了强大而易用的定时器机制,主要通过 QTimer 实现高精度的定时任务控制。本文将全面介绍 Qt 定时器的用法、分类、常见模式和注意事项。
QTimer 是 Qt 提供的定时器类,可用于在一段时间之后或以固定间隔触发一个槽函数(slot)。它基于 Qt 事件循环机制,具有跨平台性强、资源开销小的优点。
单次触发
QTimer::singleShot(1000, this, SLOT(doSomething()));
周期性触发
QTimer *timer = new QTimer(this);
connect(timer, &QTimer::timeout, this, &MyClass::updateUI);
timer->start(500); // 每500ms触发一次
函数 |
说明 |
start(int msec) |
启动定时器,触发间隔为 msec 毫秒 |
stop() |
停止定时器 |
isActive() |
判断定时器是否正在运行 |
setInterval(int msec) |
设置触发间隔(不立即生效) |
setSingleShot(bool) |
设置为只触发一次 |
remainingTime() |
获取当前定时器剩余触发时间(毫秒) |
timeout() |
定时器到期时发出的信号 |
// 用于图像显示/温度更新/状态轮询等
m_timer = new QTimer(this);
connect(m_timer, &QTimer::timeout, this, &MyWindow::refreshDisplay);
m_timer->start(100);
connect(&m_serialTimer, &QTimer::timeout, this, &MyDevice::sendPollingCmd);
m_serialTimer.setInterval(500);
m_serialTimer.start();
// 启动单次定时器,仅触发一次防止频繁响应
QTimer::singleShot(300, this, SLOT(handleClick()));
// 如果 5 秒未收到响应,则视为超时
connect(&timeoutTimer, &QTimer::timeout, this, &MyApp::handleTimeout);
timeoutTimer.setSingleShot(true);
timeoutTimer.start(5000);
每个QTimer实例都是独立运行的。可以在同一个类中同时启用多个定时器,分别绑定不同的槽函数。
#include "mainwindow.h"
#include
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
{
// 创建第一个定时器,每秒触发
timer1 = new QTimer(this);
connect(timer1, &QTimer::timeout, this, &MainWindow::onTimer1Timeout);
timer1->start(1000); // 1秒
// 创建第二个定时器,每两秒触发
timer2 = new QTimer(this);
connect(timer2, &QTimer::timeout, this, &MainWindow::onTimer2Timeout);
timer2->start(2000); // 2秒
// 创建第三个定时器,每500ms触发
timer3 = new QTimer(this);
connect(timer3, &QTimer::timeout, this, &MainWindow::onTimer3Timeout);
timer3->start(500); // 0.5秒
}
MainWindow::~MainWindow() {}
void MainWindow::onTimer1Timeout() {
qDebug() << "[Timer1] 每1秒触发";
}
void MainWindow::onTimer2Timeout() {
qDebug() << "[Timer2] 每2秒触发";
}
void MainWindow::onTimer3Timeout() {
qDebug() << "[Timer3] 每0.5秒触发";
}
预期输出:
[Timer3] 每0.5秒触发
[Timer1] 每1秒触发
[Timer3] 每0.5秒触发
[Timer2] 每2秒触发
[Timer3] 每0.5秒触发
[Timer1] 每1秒触发
...
#include
#include
#include
class MainWindow : public QMainWindow {
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr) : QMainWindow(parent) {
// timer1 - 每1秒打印一次
QTimer *timer1 = new QTimer(this);
connect(timer1, &QTimer::timeout, this, [=]() {
qDebug() << "[Lambda Timer1] 每1秒触发";
});
timer1->start(1000);
// timer2 - 每2秒打印一次
QTimer *timer2 = new QTimer(this);
connect(timer2, &QTimer::timeout, this, [=]() {
qDebug() << "[Lambda Timer2] 每2秒触发";
});
timer2->start(2000);
// timer3 - 每3秒打印一次
QTimer *timer3 = new QTimer(this);
connect(timer3, &QTimer::timeout, this, [=]() {
static int count = 0;
qDebug() << "[Lambda Timer3] 第" << ++count << "次触发";
});
timer3->start(3000);
}
};
输出:
[Lambda Timer1] 每1秒触发
[Lambda Timer2] 每2秒触发
[Lambda Timer3] 第 1 次触发
[Lambda Timer1] 每1秒触发
[Lambda Timer1] 每1秒触发
[Lambda Timer2] 每2秒触发
[Lambda Timer3] 第 2 次触发
...
#include "worker.h"
#include
//worker.cpp
Worker::Worker(QObject *parent) : QObject(parent) {
timer = new QTimer(this);
connect(timer, &QTimer::timeout, this, [=]() {
emit sendLog("[Worker] 子线程定时器触发:" + QTime::currentTime().toString());
});
}
Worker::~Worker() {}
void Worker::startWork() {
timer->start(1000); // 每秒触发
}
//mainwindow.cpp
#include "mainwindow.h"
#include "worker.h"
#include
#include
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
{
QThread *thread = new QThread(this);
Worker *worker = new Worker();
// 将 worker 移动到线程
worker->moveToThread(thread);
// 启动线程后,再调用 worker 的启动函数
connect(thread, &QThread::started, worker, &Worker::startWork);
// 从子线程发回消息
connect(worker, &Worker::sendLog, this, [](const QString &msg) {
qDebug() << msg;
});
// 程序退出时清理资源
connect(this, &MainWindow::destroyed, thread, &QThread::quit);
connect(thread, &QThread::finished, worker, &QObject::deleteLater);
connect(thread, &QThread::finished, thread, &QObject::deleteLater);
thread->start();
}
预计输出:
[Worker] 子线程定时器触发:12:34:56
[Worker] 子线程定时器触发:12:34:57
[Worker] 子线程定时器触发:12:34:58
...
connect(ui->pushButton, &QPushButton::clicked, this, [this]() {
ui->pushButton->setEnabled(false);
QTimer::singleShot(5000, this, [this]() {
ui->pushButton->setEnabled(true);
});
});
QTimer *clock = new QTimer(this);
connect(clock, &QTimer::timeout, this, [this]() {
ui->label->setText(QTime::currentTime().toString());
});
clock->start(1000);
按指定次数循环发送指令,通常适用于固定次数的任务(如重试机制、逐步操作等)。
可以通过 QTimer 设置定时器并结合计数器进行次数控制。当计数器达到指定次数时停止发送指令。
#include
#include
class CommandSender : public QObject {
Q_OBJECT
public:
CommandSender(QObject* parent = nullptr) : QObject(parent), m_count(0), m_maxCount(5) {
// 设置定时器,每500ms触发一次
m_timer.setInterval(500);
connect(&m_timer, &QTimer::timeout, this, &CommandSender::sendCommand);
}
void start() {
// 开始发送命令
m_count = 0;
m_timer.start();
}
private slots:
void sendCommand() {
if (m_count < m_maxCount) {
qDebug() << "发送命令:" << m_count + 1;
m_count++;
} else {
// 发送完毕,停止定时器
m_timer.stop();
qDebug() << "所有命令已发送完毕。";
}
}
private:
int m_count; // 当前发送次数
const int m_maxCount; // 最大发送次数
QTimer m_timer; // 定时器
};
// 使用示例
CommandSender sender;
sender.start();
按照固定的时间间隔重复发送指令,适用于周期性任务(如心跳包、定时状态报告、定期同步数据等)。
与按次数发送指令类似,定时发送指令可以使用 QTimer 来实现。不同的是,定时发送需要持续不断地发送直到用户停止或达到某个条件。
#include
#include
class PeriodicCommandSender : public QObject {
Q_OBJECT
public:
PeriodicCommandSender(QObject* parent = nullptr) : QObject(parent) {
// 设置定时器,每2秒触发一次
m_timer.setInterval(2000);
connect(&m_timer, &QTimer::timeout, this, &PeriodicCommandSender::sendPeriodicCommand);
}
void start() {
m_timer.start();
}
void stop() {
m_timer.stop();
}
private slots:
void sendPeriodicCommand() {
qDebug() << "定时发送命令";
}
private:
QTimer m_timer; // 定时器
};
// 使用示例
PeriodicCommandSender sender;
sender.start();
有时可能会遇到按次数和定时发送指令的结合需求,例如每隔一段时间发送指定次数的指令。此时,我们可以使用 嵌套定时器 或 递归定时器。
#include
#include
class TimedRepeatingSender : public QObject {
Q_OBJECT
public:
TimedRepeatingSender(QObject* parent = nullptr) : QObject(parent), m_count(0), m_maxCount(5), m_repeatInterval(1000) {
// 外层定时器,用于每1秒重复触发一次
m_timer.setInterval(m_repeatInterval);
connect(&m_timer, &QTimer::timeout, this, &TimedRepeatingSender::sendCommandPeriodically);
}
void start() {
m_count = 0;
m_timer.start();
}
private slots:
void sendCommandPeriodically() {
if (m_count < m_maxCount) {
qDebug() << "发送命令,次数:" << m_count + 1;
m_count++;
} else {
// 达到最大次数后停止定时器
m_timer.stop();
qDebug() << "所有命令已发送完毕。";
}
}
private:
int m_count;
const int m_maxCount;
const int m_repeatInterval; // 每次发送之间的间隔时间
QTimer m_timer;
};
// 使用示例
TimedRepeatingSender sender;
sender.start();
定时器无效的常见原因:
• 没有进入 Qt 的 事件循环;
• 定时器对象被提前析构;
• 使用 QTimer::singleShot() 时 lambda 没绑定有效 this;
• 在子线程中未启用事件循环。
精度问题:
• QTimer 基于系统计时器,有一定抖动;
• 对于高精度实时任务,不推荐使用 QTimer,可使用多线程 + QElapsedTimer 代替。
场景 |
推荐做法 |
单次延迟任务 |
QTimer::singleShot() |
周期执行/轮询 |
QTimer 实例 + start() |
多线程中使用 |
moveToThread() + 事件循环 |
精准测量执行耗时 |
使用 QElapsedTimer |
复杂控制需求(组合) |
多个 QTimer 实例 + 状态机控制 |
这两种方案都可以通过 QTimer 来实现,灵活控制定时任务的执行时间和频率。根据具体的应用场景,选择合适的方式进行设计,确保代码简洁、可维护且高效。如果有更具体的需求或场景,可以进一步细化和优化设计方案。