MFC精確定時器
阿新 • • 發佈:2018-11-19
上一篇部落格介紹瞭如何利用QueryPerformanceCounter()來精確計時。我們 在上一篇部落格裡看到了,Qt的QTimer類是不能非常精確的定時的。本例介紹一種MFC自己提供的定時器函式timeSetEvent,實現毫秒量級的定時觸發。
h檔案:
#ifndef QTPRECISETIMER_H #define QTPRECISETIMER_H #include <QtWidgets/QMainWindow> #include "ui_qtprecisetimer.h" #include <Windows.h> #include <QDebug> #include <stdio.h> #include <mmsyscom.h> #pragma warning(disable:4996) #pragma comment(lib, "winmm.lib") void WINAPI OnTimer(UINT, UINT, DWORD, DWORD, DWORD); class QtPreciseTimer : public QMainWindow { Q_OBJECT public: QtPreciseTimer(QWidget *parent = 0); ~QtPreciseTimer(); public slots: void OnClickStart(void); private: Ui::QtPreciseTimerClass ui; }; #endif // QTPRECISETIMER_H
cpp檔案:
#include "qtprecisetimer.h" MMRESULT g_timerID; FILE * m_fp = NULL; LARGE_INTEGER m_nBegin; LARGE_INTEGER m_nFreq; QtPreciseTimer::QtPreciseTimer(QWidget *parent) : QMainWindow(parent) { ui.setupUi(this); connect(ui.pushButton, SIGNAL(clicked()), this, SLOT(OnClickStart())); m_fp = fopen("TimerRcd.txt", "w"); } QtPreciseTimer::~QtPreciseTimer() { fclose(m_fp); } void QtPreciseTimer::OnClickStart(void) { QueryPerformanceFrequency(&m_nFreq);//獲取頻率 QueryPerformanceCounter(&m_nBegin);//獲取起始時間 g_timerID = timeSetEvent(100, 1, (LPTIMECALLBACK)OnTimer, DWORD(50), TIME_PERIODIC); fprintf(m_fp, "m_timerID = %d\n", (int)g_timerID); } void WINAPI OnTimer(UINT uiID, UINT uiMsg, DWORD dwUser, DWORD dw1, DWORD dw2) { static int iCount = 0; if(iCount < 20) { LARGE_INTEGER nTime; QueryPerformanceCounter(&nTime);//獲取時間 //計算從起始時間開始,到當前的時間間隔,單位毫秒 int iInterval = (nTime.QuadPart - m_nBegin.QuadPart) / (double)m_nFreq.QuadPart * 1000; iCount++; fprintf(m_fp, "uiID = %d, uiMsg = %d, dwUser = %d, dw1 = %d, dw2 = %d, Time = %d ms\n", uiID, uiMsg, dwUser, dw1, dw2, iInterval); } else { timeKillEvent(g_timerID); } }
執行後的介面:
可見,1)定時誤差在1毫秒範圍內; 2)回撥函式OnTimer的第一個輸入引數uiID其實就等於timeSetEvent的返回值,也就是定時器的ID; 3)timeSetEvent()的第一個輸入引數 代表定時的間隔,單位毫秒,第二個引數代表定時的解析度,或者說精確度,第三個引數指向回撥函式;第四個引數是一個DWORD型,回撥函式的第三個引數的取值與其相等;最後的 引數決定定時器是週期性觸發TIME_PERIODIC還是單次觸發TIME_ONESHOT 。
結束timer時,呼叫timeKillEvent()