之前一直使用SetTimer和OnTimer来定时,知道今天碰到了一个应用,运行结果反应SetTimer定时不准,研究了timeSetEvent/timeKillEvent的使用,其可以实现1ms的定时精度。
-
使用这两个函数时,需要在头部添加如下语句:
#include <MMSystem.h>
#pragma comment(lib, “Winmm.lib”)
-
timeSetEvent的函数声明如下:
MMRESULT timeSetEvent(UINT uDelay, UINT uResolution, LPTIMECALLBACK lpTimeProc, WORD dwUser, UINT fuEvent);
参数说明:
uDelay:指定定时的时间,单位是毫秒;
uResolution:以毫秒指定延时的精度,数值越小,定时器事件的分辨率越高,缺省值为1ms;
lpTimeProc:指向一个回调函数,该回调函数包含需要定时执行的代码;
dwUser:存放用户提供的回调数据;
fuEvent:指定定时器事件的类型:TIME_ONESHOT表示uDelay毫秒后只产生一次事件,TIME_PERIODIC表示每隔uDelay毫秒周期性地产生事件。
-
回调函数的形式如下:
void CALLBACK CXXXDlg::MMTimeProc(UINT uID, UINT uMsg, DWORD dwUsers, DWORD dw1, DWORD dw2)
{
CXXXDlg pDlg = (CXXXDlg)(dwUsers);
//添加你的处理代码
…
}
当回调函数是类里面的函数时,一定要声明为静态函数。
-
例子:
MMRESULT timer_id = timeSetEvent(100, 1, (LPTIMECALLBACK)MMTimeProc, (DWORD)this, TIME_PERIODIC);
这条语句设定了一个定时器事件,定时精度是1ms,每隔100ms执行一次MMTimeProc指定的回调函数。
timer_id标识该定时器事件,当不再使用时,可以使用timeKillEvent结束该定时器事件,即timeKillEvent(timer_id)。
-
对回调函数的编写需要注意,如果不是类的成员函数,则可以直接这样定义
void CALLBACK MMTimeProc(UINT uID, UINT uMsg, DWORD dwUsers, DWORD dw1, DWORD dw2)
{
//添加你的处理代码
…
}
但是由于在MFC中使用,声明为外部函数会导致访问类成员的困难。因此可以将其定义为类的成员函数,但是需要将其定义为静态成员函数,如此一来,仍旧无法直接访问类的其他成员函数,因为对非静态成员函数的访问需要类对象。
注意到timeSetEvent的第四个参数,为用户提供的回调数据,因此可以将当前对象的this指针传递给回调函数,然后从回调函数的第三个参数dwUsers解析出来。这样,不论将其声明为外部函数还是类的静态成员函数,均可以对其中的成员数据或函数进行访问。
-
pDlg->UpdateData()报错
当我将回调函数声明为类的静态成员函数,并将this指针传递给回调函数时,发现在回调函数内pDlg->UpdateData(TRUE)的执行出现如下图所示错误
针对这一错误,存在两种较为简单的解决方式:多媒体定时器(timeSetEvent)及使用pDlg->UpdateData()错误
-
使用control变量或直接获取控件指针对控件的变量进行更新:
pDlg->m_editCtrl.SetWindowText(pDlg->m_value2);
pDlg->GetDlgItem(IDC_EDIT2)->SetWindowText(pDlg->m_value2);
- 最简单的办法,将Debug改为Release即可正常运行。