【Qt 专栏】QT定时任务- timerEvent事件使用以及和QTimer 定时器的使用区别
QTimer定时器
一般情况下我们使用定时器开启定时任务都是这样操作:
//.h文件--声明QTimer对象和槽函数
public slots:
void Timer_func();
public:
QTimer* Timer_;
//.cpp文件--实例化和连接信号槽
Timer_= new QTimer();
Timer_->setInterval(6000); //6s
connect(Timer_, SIGNAL(timeout()), this, SLOT(Timer_func()));
Timer_->start();
这样做很明确,且是专门一个信号来触发定时任务,不会导致冲突。但是这需要每一个不同的定时任务对应开一个QTimer。有些对象内部轮询的任务,用QTimer定时就有点麻烦(懒),所以找到了另外一种方法,它就是QObject提供的定时器方法。
QObject中的timerEvent事件重载-QObject定时器
通常使用startTimer()要比QTimer有更好的使用效率,下面是官方文档原话翻译,节选自QObject class里的startTimer()
函数下方注解。
启动计时器并返回一个计时器标识符,如果启动失败则返回零。
计时器事件将每毫秒发生一次,直到调用killTimer()。
如果标识符返回interval为0,则计时器事件在每次没有更多窗口系统事件需要处理时发生一次。
当计时器事件发生时,使用QTimerEvent事件参数类调用虚拟timerEvent()函数。
重载此函数以获取计时器事件。
如果有多个计时器在运行,QTimerEvent::timerId()可以用来找出哪个计时器被激活了。
(说人话)所有继承自QObject的类,都会有一个timerEvent(QTimerEvent *event)的纯虚函数,我们只需要继承QObject,startTimer()设定定时间隔,再重载这个函数以处理自己的定时任务。多个定时任务用timeId区分,结束后使用killTimer(timerid)关闭定时任务。
void timerEvent(QTimerEvent *event) override; 可以加override ,表示覆盖
.h文件内定义定时器ID:
.cpp 文件中重载timerEvent,使用startTimer(timerId)
开启定时器,使用killTimer(timerId)
关闭定时器。逻辑里通过验证timeID
实现不同功能:
Delay_MSec(INT msec)实现了QT中的非阻塞延时,非常好用,适合在对象内部自延时而不卡住其他事件(如界面事件)
void MainWindow::Delay_MSec(unsigned int msec)
{
QTime _Timer = QTime::currentTime().addMSecs(msec); // 在当前的时间上增加多少秒
while( QTime::currentTime() < _Timer ) // while循环
QCoreApplication::processEvents(QEventLoop::AllEvents, 100);// 期间在做主事件循环,就避免了阻塞
// 去掉这句就是阻塞延时了
}
另外,timerEvent事件最好不要处理过久,因为如果这个事件函数被占用了,下一次的startTimer
定时器事件也会无法响应。这有点类似STM32中的中断函数,中断函数不允许处理时间过长,否则会导致中断阻塞,功能不稳定。
示例,大家也可以自己做测试:
总结
QTimer适用性相对较广,因为它的使用一般是基于信号与槽,所以可通过信号或槽的多级绑定以实现更为复杂的定时任务。且可以同一时间被触发多次。
timerEvent事件则适用面相对较窄,因为实现它是继承和重载,这就意味着只有该类生成的对象能使用到这个定时事件,因为它们都在同一块内存空间中(同一个对象内),比如我A类重载了timerEvent,A类内部有个B类,则我可以通过A类对象的timerEvent来触发B类的定时操作。这非常适合在较少工作量的定时轮询场景中使用。但是timerEvent不允许占用时间过长,否则事件触发被阻塞,导致功能不稳定。
参考文章:
https://blog.csdn.net/corefunction/article/details/116586227