1.计时器定义
windows计时器是一种输入设备,每到一个指定的时间间隔,它就会周期性地通知应用程序。windows会反复地向程序发送WM_TIMER消息,以表示改时间间隔已经过去。
2.计时器功能
多任务进行。在抢占式多任务系统中,如果程序必须完成大量的处理,可以把一个任务分成许多小块,每当收到一个WM_TIMER消息时,就处理一小块任务。达到充分利用cpu的效果。
保持更新进度报告。应用程序可以利用计时器实时的显示不断变化的信息,例如时钟程序,也可以每隔一段时间更新显示不断变化的信息。
实现自动存储的功能。计时器可以提醒windows程序每隔一个指定时间间隔就把用户的工作自动保存到磁盘上。
终止程序的演示版。适用于一定演示时间的程序。
控制运动速度。游戏中的图形对象或者计算机辅助指令程序的连续显示也许需要以一定的速度进行。利用计时器可以消除因微处理器速度不同而造成的不均匀性。
多媒体。音乐程序常常在后台播放音频数据,一个程序可以利用计时器周期性地确定有多少音频符号已经播放,以协调屏幕视觉信息。
3.计时器工作原理
windows计时器只是简单地扩展了pc硬件和ROM BIOS中的计时逻辑。应用程序中的时钟或计时器功能是通过截获一个叫“时钟滴答”的BIOS中断而实现的,这个中断每54.925毫秒出现一次,windows应用程序并不截获BIOS中断,windows本身会处理硬件中断。对于当前设定的每个计时器,windows都会保持一个计数值,硬件时钟滴答每出现一次,这个值就会减1,当计数值减为0,windows就会把一个WM_TIMER消息适当的放在应用程序消息队列中,同时把计数值重新设置回它的原始值。
由于windows应用程序是是通过正常的消息队列来接收WM_TIMER消息,所以绝对不用担心程序在处理其他任务时会被突入而来WM_TIMER消息所中断。因此计时器与键盘和鼠标相似:驱动程序会处理异步硬件中断事件,windows则将这些事件转换成有序的,有组织和序列化的消息。
4.计时器的三种使用方式
设置定时器,一般在WM_CREATE消息处理中
hWnd:窗口句柄
nIDEvent:计时器ID
uElapse:时间间隔
lpTimeFuc:计时器回调函数地址,也就是函数名
终止定时器,务必在程序终止之前完成,也就是WM_DESTROY消息处理中
KillTimer(hWnd,nIDEvent)
第一种使用方法:
不使用回调计时器函数,直接在WM_TIMER中处理。
设定计时器:
SetTime(hWnd,nIDEvent,uElapse,NULL)
处理计时器:
case WM_TIMER:
//处理逻辑
......
break;
杀死计时器:
KillTimer(hWnd,nIDEvent)
第二种使用方法:
使用计时器回调函数,windows发送的WM_TIMER消息将直接在该回调函数中处理,不在由窗口过程处理。
其实窗口过程也是一个窗口的回调函数,windows发送给窗口的所有消息,将自动调用窗口过程来处理。
定义计时器回调函数:
void CALLBACK TimerProc(HWND hwnd,UINT message,UINT iTimerID,DWORD dwTime)
设置定时器:
SetTimer(hWnd,nIDEvent,uElapse,lpTimeFuc)
杀死计时器:
KillTimer(hWnd,nIDEvent)
第三种使用方法:
该方法和第二种类似,只不过SetTimer的hwnd的参数被设置为NULL,而且第二个参数(正常情况下是计时器的ID)被忽略了,此外这个函数会反悔计时器ID:
设定计时器:
iTimerID=SetTimer(NULL,0,uElapse,lpTimeFuc)
杀死计时器:
KillTimer(NULL,iTimerID)
个人觉得这样使用的计时器很乱。
示例代码:
#include <windows.h>
#define ID_TIMER 1
LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ;
void CALLBACK TimerProc(HWND,UINT,UINT,DWORD);
int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
PSTR szCmdLine, int iCmdShow)
{
static TCHAR szAppName[] = TEXT ("Beeper1") ;
HWND hwnd ;
MSG msg ;
WNDCLASS wndclass ;
wndclass.style = CS_HREDRAW | CS_VREDRAW ;
wndclass.lpfnWndProc = WndProc ;
wndclass.cbClsExtra = 0 ;
wndclass.cbWndExtra = 0 ;
wndclass.hInstance = hInstance ;
wndclass.hIcon = LoadIcon (NULL, IDI_APPLICATION) ;
wndclass.hCursor = LoadCursor (NULL, IDC_ARROW) ;
wndclass.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH) ;
wndclass.lpszMenuName = NULL ;
wndclass.lpszClassName = szAppName ;
if (!RegisterClass (&wndclass))
{
MessageBox (NULL, TEXT ("Program requires Windows NT!"),
szAppName, MB_ICONERROR) ;
return 0 ;
}
hwnd = CreateWindow (szAppName, TEXT ("Beeper1 Timer Demo"),
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT,
CW_USEDEFAULT, CW_USEDEFAULT,
NULL, NULL, hInstance, NULL) ;
ShowWindow (hwnd, iCmdShow) ;
UpdateWindow (hwnd) ;
while (GetMessage (&msg, NULL, 0, 0))
{
TranslateMessage (&msg) ;
DispatchMessage (&msg) ;
}
return msg.wParam ;
}
LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
/*static BOOL fFileFlop=FALSE;
HBRUSH hBrush;
HDC hdc;
PAINTSTRUCT ps;
RECT rect;*/
switch(message)
{
case WM_CREATE:
SetTimer(hwnd,ID_TIMER,1000,TimerProc); //交给计时器的回调函数完成
return 0;
/*case WM_TIMER:
MessageBeep(-1); //the fuction ?
fFileFlop=!fFileFlop;
InvalidateRect(hwnd,NULL,FALSE);
return 0;
case WM_PAINT:
hdc=BeginPaint(hwnd,&ps);
GetClientRect(hwnd,&rect);
hBrush=CreateSolidBrush(fFileFlop ? RGB(255,0,0) :RGB(0,0,255));
FillRect(hdc,&rect,hBrush);
EndPaint(hwnd,&ps);
DeleteObject(hBrush); //free the hBrush
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)
{
static BOOL fFilpFlop=FALSE;
HBRUSH hBrush;
HDC hdc;
RECT rect;
MessageBeep(MB_OK); //系统默认的发声
fFilpFlop=!fFilpFlop;
GetClientRect(hwnd,&rect);
hdc=GetDC(hwnd);
hBrush=CreateSolidBrush(fFilpFlop? RGB(255,0,0): RGB(0,0,255));
FillRect(hdc,&rect,hBrush);
ReleaseDC(hwnd,hdc);
DeleteObject(hBrush);
}