qt定时器的使用一般有以下几种方式:
1、直接使用QTimer对象,绑定定时器的timeout信号;
2、使用QTimer的静态方法singleshot方法,产生一个一次性的定时事件
3、在QObject子类中,调用startTimer方法,产生定时器,并在timerEvent方法中实现其处理;
以上三种方法,本质上都是继承QObject类,调用QObject的startTimer,killTimer方法等实现的;
QObject类中定时器相关的方法有:startTimer、killTimer、timerEvent三个方法;
startTimer源码如下:
startTimer的实现比较简单,主要是向eventDispatcher中注册定时器事件;QAbstractEventDispatcher中registerTimer的实现如下:
生成一个定时器的id,并调用派生类的registerTimer的函数;
将定时器相关信息保存在WinTimerInfo结构中,并调用QEventDispatcherWin32Private类中的registerTimer方法;
首先会重新计算定时的时间间隔,调用calculateNextTimeout方法;
如果是非常粗糙的定时方式或者定时时间超过2s,且定时器类型不是精确定时,则定时器的触发时间存在500ms左右的偏差;
QZeroTimerEvent事件
如果定时时间间隔为0ms,则会调用qt的postEvent方法,向QEventDispatcherwin32对象抛一个QZeroTimerEvent事件,切入到qt的事件循环中;通过上几节介绍可知,通过postEvent抛出的事件最终会进入到qt_internal_proc方法中;
最终会进入到q->sendPostedEvents()方法中,
几经周转,会进入到QEventDispatcherWin32的event方法中,此处是ZeroTimerEvent事件,会调用QCoreApplication::sendEvent方法,向定时器事件的QObject对象发送一个QTimerEvent事件,从而转入到QObject的event方法中执行;并在此抛出一个QZeroTimerEvent事件;
回到registerTimer方法中:
PreciseTimer事件
如果定时器事件类型为精确定时,会调用windows操作系统的timerSetEvent接口,实现精确定时,定时精度1ms,其对应的回调函数qt_fast_time_proc方法如下:
其会在回调函数中向QEventDispatcherWin32对象post一个QTimerEvent事件;最终进入到QEventDispatcherWin32的event函数中,调用其sendTimerEvent函数,其定义如下:
在其方法中会调用QCoreApplication的sendEvent函数,最终切入到QObject的event函数中;
VeryCoarseTimer事件
精度要求不高的事件,会调用windows API的setTimer函数,注册一个定时器事件,此事件的回调函数为nullptr,qt会使用windows系统产生的WM_TIMER事件;最终会被qt_internal_proc回调函数捕获到;
其会直接调用QEventDispatcherWin32函数的sendTimerEvent方法;其余执行流程同上;
总结:
1、qt定时器会产生3种类型的定时事件 ,QZeroTimerEvent事件、QTimerEvent(PreciseTimer),QTimerEvent(VeryCoarseTimer、CoarseTimer);
2、当定时间隔为0时,会产生QZeroTimerEvent事件,其由QCoreApplication的postEvent方法切入到qt的事件循环中,几经周转在此回到QEventDispatcher类中执行;
3、当定时的精度要求比较高时,可以使用PreciseTimer事件类型,其调用weindowsAPI的timerSetEvent接口实现高精度定时,并在其回调函数中调用postEvent方法切入到qt的事件循环中处理;
4、当定时精度要求不高时,可以使用默认事件类型即VeryCoarseTimer事件类型,其会调用windowsAPI的setTimer接口,并产生WM_TIMER事件,切入到qt的事件循环中;
5、CoarseTimer事件类型,会根据其时间间隔决定产生的是精确定时还是粗糙的定时方式。