MFc 中的时间函数

  VC++ 中提供了很多关于时间操作的函数,利用它们控制程序能够精确地完成定时和计时操作。VC++中的WM_TIMER消息映射能进行简单的时间控制。首先调用函数SetTimer()设置定时间隔,如SetTimer(0,200,NULL)即为设置200ms的时间间隔。然后在应用程序中增加定时响应函数OnTimer(),并在该函数中添加响应的处理语句,用来完成到达定时时间的操作。这种定时方法非常简单,但其定时功能如同Sleep()函数的延时功能一样,精度非常低,只可以用来实现诸如位图的动态显示等对定时精度要求不高的情况。   在精度要求较高的情况下,如要求误差不大于1ms时,可以利用GetTickCount()函数。该函数的返回值是DWORD型,表示以ms为单位的计算机启动后经历的时间间隔。下列的代码可以实现50ms的精确定时,其误差小于1ms。 // 起始值和中止值 DWORD dwStart, dwStop ; dwStop = GetTickCount(); while(TRUE) { // 上一次的中止值变成新的起始值 dwStart = dwStop ; // 此处添加相应控制语句  do  { dwStop = GetTickCount() ; }while(dwStop - 50 < dwStart) ; }   对于精确度要求更高的定时操作,则应该使用QueryPerformanceFrequency()和QueryPerformanceCounter()函数。这两个函数是VC++提供的仅供Windows 95及其后续版本使用的精确时间函数,并要求计算机从硬件上支持精确定时器。QueryPerformanceFrequency()函数和QueryPerformanceCounter()函数的原型如下:   BOOL QueryPerformanceFrequency(LARGE_INTEGER *lpFrequency);   BOOL QueryPerformanceCounter(LARGE_INTEGER *lpCount); 数据类型LARGE_INTEGER既可以是一个8字节长的整型数,也可以是两个4字节长的整型数的联合结构,其具体用法根据编译器是否支持64位而定。该类型的定义如下:   typedef union _LARGE_INTEGER {    struct    { // 4字节整型数 DWORD LowPart ; // 4字节整型数 LONG HighPart ;    }; // 8字节整型数    LONGLONG QuadPart ; } LARGE_INTEGER ;   在进行定时之前,先调用QueryPerformanceFrequency()函数获得机器内部定时器的时钟频率,然后在需要严格定时的事件发生之前和发生之后分别调用QueryPerformanceCounter()函数,利用两次获得的计数之差及时钟频率,计算出事件经历的精确时间。下面的程序用来测试函数Sleep(100)的精确持续时间:   LARGE_INTEGER litmp;   LONGLONG QPart1,QPart2;   double dfMinus, dfFreq, dfTim;   QueryPerformanceFrequency(&litmp);   // 获得计数器的时钟频率   dfFreq = (double)litmp.QuadPart;   QueryPerformanceCounter(&litmp);   // 获得初始值   QPart1 = litmp.QuadPart;   Sleep(100);   QueryPerformanceCounter(&litmp);   // 获得中止值   QPart2 = litmp.QuadPart;   dfMinus = (double)(QPart2 - QPart1);   // 获得对应的时间值   dfTim = dfMinus / dfFreq;   由于Sleep()函数自身的误差,上述程序每次执行的结果都会有微小误差。 使用多媒体定时器   微软公司在其多媒体Windows中提供了精确定时器的底层API支持。利用多媒体定时器可以很精确地读出系统的当前时间,并且能在非常精确的时间间隔内完成一个事件、函数或过程的调用。利用多媒体定时器的基本功能,可以通过两种方法实现精确定时。   1.使用timeGetTime()函数   该函数定时精度为ms级,返回从Windows启动开始所经过的时间。由于使用该函数是通过查询的方式进行定时控制的,所以,应该建立定时循环来进行定时事件的控制。   2. 使用timeSetEvent()函数   利用该函数可以实现周期性的函数调用。函数的参数说明如下:  uDelay:延迟时间;   uResolution:时间精度,在Windows中缺省值为1ms;   lpFunction:回调函数,为用户自定义函数,定时调用;  dwUser:用户参数;  uFlags:标志参数;   TIME_ONESHOT:执行一次;   TIME_PERIODIC:周期性执行。   具体应用时,可以通过调用timeSetEvent()函数,将需要周期性执行的任务定义在lpFunction回调函数中(如:定时采样、控制等),从而完成所需处理的事件。需要注意的是:任务处理的时间不能大于周期间隔时间。另外,在定时器使用完毕后,应及时调用timeKillEvent()将之释放。   下面这段代码的主要功能是设置两个时钟定时器,一个间隔是1ms,一个间隔是2s。每执行一次,把当前系统时钟值输入文件“cure.out”中,以比较该定时器的精确度。 //定义1ms和2s时钟间隔,以ms为单位 # define ONE_MILLI_SECOND 1 # define TWO_SECOND 2000 //定义时钟分辨率,以ms为单位 # define TIMER_ACCURACY 1 //定义时间间隔 UINT wTimerRes_1ms,wTimerRes_2s; //定义分辨率 UINT wAccuracy; //定义定时器句柄 UINT TimerID_1ms,TimerID_2s; //打开输出文件“cure.out” CCureApp::CCureApp():fout(“cure.out”, ios::out) {  // 给时间间隔变量赋值  wTimerRes_1ms = ONE_MILLI_SECOND;  wTimerRes_2s = TWO_SECOND;  TIMECAPS tc;  //利用函数timeGetDevCaps取出系统分辨率的取值范围,如果无错则继续  if(timeGetDevCaps(&tc,sizeof(TIMECAPS))==TIMERR_NOERROR) {   //分辨率的值不能超出系统的取值范围  wAccuracy=min(max(tc.wPeriodMin, TIMER_ACCURACY),tc.wPeriodMax); //调用timeBeginPeriod函数设置定时器的分辨率 timeBeginPeriod(wAccuracy); //设置定时器 InitializeTimer();  } } CCureApp:: ~CCureApp() { //结束时钟 fout <<“结束时钟”<< endl; // 删除两个定时器 timeKillEvent(TimerID_1ms); timeKillEvent(TimerID_2s); // 删除设置的分辨率 timeEndPeriod(wAccuracy); } void CCureApp::InitializeTimer() { StartOneMilliSecondTimer(); StartTwoSecondTimer(); } // 1ms定时器的回调函数,类似于中断处理程序,一定要声明为全局PASCAL函数,否则编译会有问题 void PASCAL OneMilliSecondProc(UINT wTimerID, UINT msg,DWORD dwUser,DWORD dwl,DWORD dw2) {  // 定义计数器 static int ms = 0; CCureApp *app = (CCureApp *)dwUser; // 取得系统时间,以ms为单位 DWORD osBinaryTime = GetTickCount(); //输出计数器值和当前系统时间 app->fout<<++ms<<“:1ms:” <
<think> 首先,用户的问题是关于MFC中SetTimer函数的使用方法。我需要基于提供的引用内容来回答。引用[1]到[4]提供了相关信息。 关键点从引用中提取: - 引用[1]:SetTimer用于创建定时器,示例是SetTimer(m_hWnd,1,1000,NULL) 创建一个1秒触发一次的定时器。在MFC中,它被封装在CWnd类中,所以不需要指定窗口句柄。 - 引用[2]:如果SetTimer的最后一个参数为NULL,则通过WM_TIMER消息处理函数来处理定时事件。添加处理函数的方法是通过类向导添加WM_TIMER消息映射。 - 引用[3]:SetTimer的参数:nIDEvent是定时器标识,nElapse是时间间隔(毫秒),第三个参数是回调函数,设为NULL则使用默认OnTimer函数。需要在类中添加WM_TIMER消息映射来生成OnTimer函数。 - 引用[4]:示例程序中使用SetTimer,声明了一些变量如startTime、endTime和isStart来控制计时器。 我的回答需要结构化、清晰,使用中文,并确保LaTeX格式正确(如行内数学表达式用$...$)。 回答结构: 1. **介绍SetTimer函数**:简要说明其作用和基本用法。 2. **参数解释**:详细解释每个参数的意义,基于引用。 3. **使用方法**: - 如何调用SetTimer。 - 如何处理定时事件:通过WM_TIMER消息和OnTimer函数。 - 示例代码片段(如引用中的Python示例,但用户是C++,所以用C++代码)。 4. **示例应用**:基于引用[4],描述一个简单的计时器程序。 5. **注意事项**:如定时器标识、时间间隔单位等。 6. **引用标识**:在相关部分末尾添加引用标识,如[^1]。 最后,生成相关问题,如指令要求。 生成相关问题: 1. 如何添加WM_TIMER消息处理函数? 2. SetTimer函数在不同场景下的优化技巧? 3. MFC定时器在实际应用中的常见问题? 确保回答真实可靠,基于引用。 现在,构建回答。 </think> ### MFC中SetTimer函数的使用方法 SetTimer函数MFC(Microsoft Foundation Classes)中用于创建定时器的核心函数,它允许在指定时间间隔内触发事件。基于Windows API的封装,SetTimer在CWnd类中实现,简化了窗口程序中的定时任务处理。以下内容基于引用资料逐步解释其使用方法和相关知识,确保回答可靠。 #### 1. **SetTimer函数的基本介绍** - **作用**:SetTimer用于创建一个定时器,在设定的时间间隔(以毫秒为单位)触发事件。例如,创建每秒触发一次的定时器:`SetTimer(1, 1000, NULL)`,其中标识符为1,间隔为1000毫秒[^1]。 - **封装特性**:在MFC中,SetTimer被封装在CWnd类中,调用时无需显式指定窗口句柄(如`m_hWnd`),简化了代码[^1]。 - **基本语法**: ```cpp UINT SetTimer(UINT nIDEvent, UINT nElapse, void (CALLBACK* lpfnTimer)(HWND, UINT, UINT, DWORD)); ``` 参数说明: - `nIDEvent`:定时器的标识符(ID),用于唯一标识定时器,如多个定时器需不同ID。 - `nElapse`:时间间隔(毫秒),例如1000表示1秒。 - `lpfnTimer`:回调函数指针;如果设为`NULL`,则使用系统默认的WM_TIMER消息处理机制[^3]。 #### 2. **SetTimer的使用步骤** 以下是实现定时器的典型流程,基于引用[2]和[3]: - **步骤1: 调用SetTimer函数** 在需要启动定时器的地方(如窗口初始化或按钮点击事件),调用SetTimer。例如,在对话框类的成员函数中添加: ```cpp // 在OnInitDialog()或其他函数中 SetTimer(1, 1000, NULL); // 创建ID为1、间隔1秒的定时器 ``` 如果`lpfnTimer`参数为`NULL`,系统会通过WM_TIMER消息触发事件[^2]。 - **步骤2: 添加WM_TIMER消息处理函数** - 使用Visual Studio的类向导(Class Wizard)为类添加WM_TIMER消息映射: 1. 在Solution Explorer中右键点击类,选择“Class Wizard”。 2. 在“Messages”列表中找到`WM_TIMER`,点击“Add Handler”生成`OnTimer`函数。 - 自动生成的函数框架在.cpp文件中,例如: ```cpp void CMyDialog::OnTimer(UINT_PTR nIDEvent) { if (nIDEvent == 1) // 检查定时器ID { // 在此添加定时任务代码,例如更新UI或计算时间 // 示例:每秒更新一次文本框 CString strTime; strTime.Format(_T("时间: %d秒"), GetTickCount() / 1000); SetDlgItemText(IDC_STATIC_TIME, strTime); } CDialog::OnTimer(nIDEvent); // 调用基类处理 } ``` 此函数会在每次时间间隔到达时自动执行[^3]。 - **步骤3: 销毁定时器** 当不再需要定时器时,调用`KillTimer`函数释放资源,通常在窗口关闭或特定事件中: ```cpp KillTimer(1); // 销毁ID为1的定时器 ``` #### 3. **示例应用:简单计时器程序** 基于引用[4],一个计时器程序的核心实现: - **声明变量**:在对话框头文件(如`MyTimerDlg.h`)中声明控制变量: ```cpp public: BOOL isStart = FALSE; // 控制计时开始/停止 time_t startTime, endTime; // 存储开始和结束时间 CFont cfont; // 用于文本显示的字形 ``` - **启动计时器**:在“开始”按钮事件中: ```cpp void CMyTimerDlg::OnBnClickedStart() { if (!isStart) { startTime = GetTickCount(); // 获取当前毫秒数 SetTimer(1, 100, NULL); // 每100毫秒触发一次更新 isStart = TRUE; } } ``` - **在OnTimer中更新显示**: ```cpp void CMyTimerDlg::OnTimer(UINT_PTR nIDEvent) { if (nIDEvent == 1) { endTime = GetTickCount(); // 获取当前时间 int elapsed = (endTime - startTime) / 1000; // 计算秒数 CString str; str.Format(_T("已运行: %d 秒"), elapsed); SetDlgItemText(IDC_TIME_DISPLAY, str); // 更新文本框 } CDialog::OnTimer(nIDEvent); } ``` - **停止计时器**:在“停止”按钮事件中调用`KillTimer(1)`并重置`isStart`[^4]。 #### 4. **注意事项与常见问题** - **时间精度**:SetTimer时间间隔不是精确的实时控制,受系统消息队列影响,最小间隔通常为10-15毫秒。对于高精度需求,需使用多媒体定时器。 - **多定时器管理**:如果使用多个定时器,需在`OnTimer`中通过`nIDEvent`区分ID。 - **资源释放**:忘记调用`KillTimer`可能导致内存泄漏或意外行为。 - **回调函数替代**:如果需要自定义回调(非`OnTimer`),可将`lpfnTimer`设为自定义函数,但推荐使用WM_TIMER机制以简化MFC集成[^3]。 - **数学表达式示例**:定时器间隔计算涉及时间单位转换,例如设定间隔$t$毫秒,实际触发频率为$f = \frac{1000}{t}$ Hz(基于$1 \text{秒} = 1000 \text{毫秒}$的关系)[^1]。 #### 5. **总结** SetTimerMFC中实现定时任务的高效工具,核心是通过WM_TIMER消息映射到OnTimer函数处理事件。合理使用可开发计时器、动画或数据采集等应用。实际开发中,建议结合类向导简化消息处理,并注意资源管理。更多细节可参考MFC文档或示例代码[^1][^2][^3][^4]。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值