8.1定时器基本知识
SetTimer:分配一个定时器,有一个间隔范围为1毫秒到4,294,967,295秒(约50天)的整形参数。指示间隔发送WM_TIMER的时间。
KillTimer:停止定时器消息。如我们可以调用该函数写一个只限用一次的定时器。该函数调用清除消息队列中未处理的WM_TIMER消息。
系统和定时器
win本身处理硬件中断,应用程序无需处理。对于拥有定时器的程序(win存储每个硬件timertick减少次数),当该计数减为0时,win在应用程序消息队列中放入一个WM_TIMER消息,并重置计数初值。
定时器消息不是异步的,无需担心WM_TIMER会中断程序的执行。和WM_PAINT消息类似:不会向消息队列中放入多个WM_PAINT消息,而是将多余的该消息组成一个。WM_TIMER消息仅在需要更新时才提示程序,所以程序本身不能由WM_TIMER消息数目来计时。
这两个消息都是低优先级的,程序只有在消息队列中没有其他消息时才接收它们。
定时器的三种使用方法
如果要在整个程序执行期间使得定时器,可以在WinMain或WM_CREATE中调用SetTImer。在退出或响应WM_DESTROY时调用用KillTimer。
方法一
win发送WM_TIMER至应用程序正常窗口消息处理程序。(最常用)
#define ID_TIMER 1
//每隔一秒重绘客户区
LRESULT CALLBACK WindowProc (HWND hwnd, UINT message, WPARAM wParam,LPARAM lParam)
{
static BOOL flag=FALSE; //标志符
HBRUSH hBrush;
RECT rect;
HDC hdc;
PAINTSTRUCT ps;
switch (message)
{
case WM_CREATE:
SetTimer(hwnd,ID_TIMER,1000,NULL); //设定定时器
return 0;
case WM_TIMER:
MessageBeep(-1);
flag=!flag;
InvalidateRect(hwnd,NULL,TRUE);//NULL,全部的窗口客户区将更新
return 0;
case WM_PAINT:
hdc=BeginPaint(hwnd,&ps);
hBrush=CreateSolidBrush(flag?RGB(255,0,0):RGB(0,255,0));
GetClientRect(hwnd,&rect); //填充之前一定要确定填充范围
FillRect(hdc,&rect,hBrush);
EndPaint(hwnd,&ps);
DeleteObject(hBrush);
return 0;
case WM_DESTROY:
KillTimer(hwnd,ID_TIMER);//清除定时器,清除所有WM_TIMER消息
PostQuitMessage(0);
return 0;
default:
break;
}
return DefWindowProc(hwnd,message,wParam,lParam);
}
方法二
win直接将定时器消息发送给程序的另一个函数。接收这些消息的函数被称为(callback函数),必须定义为CALLBACK(因为它是由win从程序代码段中调用)。其参数和返回值取决于函数目的。
VOID CALLBACK TimerProc (HWND hwnd, UINT message, UINT iTimerID, DWORD dwTime);
LRESULT CALLBACK WindowProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_CREATE:
SetTimer (hwnd, ID_TIMER, 1000, TimerProc) ;//win发送消息给TimerProc,而非法一中发送给WindowProc
//和方法一最后一个参数不同
return 0 ;
case WM_DESTROY:
KillTimer (hwnd, ID_TIMER) ;
PostQuitMessage (0) ;
return 0 ;
}
return DefWindowProc (hwnd, message, wParam, lParam) ;
}
VOID CALLBACK TimerProc (HWND hwnd, UINT message, UINT iTimerID, DWORD dwTime)//hwnd SetTimer中的窗口句柄
{
static BOOL flag = FALSE ;
HBRUSH hBrush ;
HDC hdc ;
RECT rc ;
MessageBeep (-1) ;
flag=!flag;
GetClientRect (hwnd, &rc) ;
hdc = GetDC (hwnd) ;
hBrush = CreateSolidBrush (flag ? RGB(255,0,0) : RGB(0,0,255)) ;
FillRect (hdc, &rc, hBrush) ;
ReleaseDC (hwnd, hdc) ;
DeleteObject (hBrush) ;
}
方法三
和法二类似,只是传递给SetTimer参数hwnd设为NULL。且第二个参数(一般为计时器ID)被忽略。最后传回此ID。(传递给TimerProc的参数也必须是NULL,很少用,如果在某时刻有一系列SetTimer调用,但又不想使用过的定时器ID被追踪,这方法很方便。)
iTimerID=SetTimer(NULL,0,wMsecInterval,TimerProc);//hwnd为NULL
KillTimer(NULL,iTimerID); //hwnd也为NULL
8.3定时器用于时钟
数字时钟
模拟时钟