QT中延时的用法及定时器的用法
在 Qt 中,延迟操作是否会“去做其他命令”取决于你用的是哪种方式来实现延迟。Qt 提供了几种常见的延迟方法,有的是“硬延时”(阻塞线程),有的是“软延时”(允许事件循环继续运行):
🔴 1. QThread::sleep()
/ msleep()
/ usleep()
→ 硬延时(阻塞线程)
-
这些方法会阻塞当前线程(通常是主线程)
-
延迟期间不会处理任何事件,也不会执行其他槽函数
-
❗界面会卡顿、按钮无法点击、动画会停止
QThread::msleep(1000); // 阻塞当前线程1秒
⚠️ 不推荐在主线程中使用
🟡 2. 使用 QTimer
→ 非阻塞延时(推荐)
-
设置一个定时器,在指定时间后触发槽函数
-
这期间 Qt 的事件循环是活跃的,可以响应用户操作,继续运行其他任务
QTimer::singleShot(1000, this, SLOT(onTimeout()));
或者用 lambda:
QTimer::singleShot(1000, this, [](){qDebug() << "1秒后执行";
});
✅ 推荐方式,因为不会阻塞主线程,可以继续处理 UI 和其他事件
🟢 3. 自己写一个非阻塞“延时函数” → 事件循环 + QElapsedTimer
如果你确实想“等一会再继续往下执行”,但又不想阻塞主线程,可以用事件循环临时让出控制权:
void delay(int ms) {QEventLoop loop;QTimer::singleShot(ms, &loop, SLOT(quit()));loop.exec(); // 进入一个局部事件循环
}
⚠️ 仍然会“卡住”当前代码流程,但 UI 不会卡。
✅ 总结对比:
方法 | 是否阻塞 | 是否处理其他命令 | 备注 |
---|---|---|---|
QThread::sleep/msleep() | 是 | 否 | 不推荐在主线程用,界面卡死 |
QTimer::singleShot() | 否 | 是 | 推荐,延迟执行不阻塞主线程 |
QEventLoop +QTimer 延时函数 | 是(局部) | 是 | 控制力强,适合特定流程 |
如果你描述你的使用场景,比如:
“我希望点击按钮后等两秒再执行后续操作,但界面要能动”
那就推荐你用 QTimer::singleShot()
。。
定时器发出timeout信号并绑定槽函数的用法
Qt 的 QTimer::timeout
信号可以绑定到你自定义的槽函数上,用于定时触发执行某些操作。下面是最常见的几种绑定方式(以 Qt 5 和 Qt 6 都兼容的写法为主):
✅ 示例:定时器绑定槽函数
假设你有个类叫 MyWidget
,你想每隔1秒打印一次日志:
🔧 1. 头文件 mywidget.h
#include <QWidget>
#include <QTimer>class MyWidget : public QWidget {Q_OBJECT
public:explicit MyWidget(QWidget *parent = nullptr);private slots:void onTimeout(); // 槽函数private:QTimer *timer;
};
🔧 2. 实现文件 mywidget.cpp
#include "mywidget.h"
#include <QDebug>MyWidget::MyWidget(QWidget *parent) : QWidget(parent) {timer = new QTimer(this);connect(timer, &QTimer::timeout, this, &MyWidget::onTimeout);timer->start(1000); // 每1000毫秒(1秒)触发一次
}void MyWidget::onTimeout() {qDebug() << "定时器触发:" << QTime::currentTime().toString();
}
✅ 另一种写法:用 lambda 表达式绑定
如果你不想单独写一个槽函数,也可以直接写在构造函数中,用 lambda:
QTimer *timer = new QTimer(this);
connect(timer, &QTimer::timeout, this, [](){qDebug() << "lambda 中定时器触发";
});
timer->start(1000);
🔁 附:停止定时器
timer->stop(); // 停止计时
⏱️ 设置只触发一次
timer->setSingleShot(true); // 设置为只触发一次