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事件類型,會根據其時間間隔決定產生的是精確定時還是粗糙的定時方式。