MFC精确定时器

上一篇博客介绍了如何利用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()

猜你喜欢

转载自blog.csdn.net/liji_digital/article/details/82284367