你可以使用SetTimer函数为自己的Windows程序分配一个计时器,SetTimer包含一个无符号的整形参数,该参数指定了时间间隔的长短,单位是毫秒。
该函数的功能是在指定时间间隔内向你的程序发送一条WM_TIMER消息;
计时器消息不是异步的。
因为计时器是基于硬件计时器的中断,程序员有时候会被误导,认为他们的程序可能会被异步中断打断后被迫去处理wm_timer消息,事实上,Windows处理WM_TIMER消息和处理WM_PAINT消息很类似,这两种消息都是低优先级的,只有当消息队列中没有其他消息时,程序才会收到它们。
使用计时器的三种方法:
方法一:
#define TIMER_SEC 1
#define TIMER_MIN 2
//通过两个SetTimer函数分别设置两个计时器
SetTimer(hwnd,TIMER_SEC,1000,NULL);
SetTimer(hwnd,TIMER_MIN,60000,NULL);
//WM_TIMER的处理逻辑如下:
case WM_TIMER:
switch(wParam)
{
case TIMER_SEC:
每秒处理一次;
break;;
case TIMER_MIN:
每分钟处理一次
break;;
}
return 0;
下面看看一个简单的例子,在一秒时间间隔内,改变客户区的背景颜色,发出系统声音。
#include
#define ID_TIMER 1
LRESULT CALLBACK WindowProc(
HWND hwnd, // handle to window
UINT uMsg, // message identifier
WPARAM wParam, // first message parameter
LPARAM lParam // second message parameter
);
int WINAPI WinMain(
HINSTANCE hInstance, // handle to current instance
HINSTANCE hPrevInstance, // handle to previous instance
LPSTR lpCmdLine, // command line
int nCmdShow // show state
)
{
static TCHAR szAppName[]=TEXT("leidemingzi");
HWND hwnd;
MSG msg;
WNDCLASS wndclass;
wndclass.cbClsExtra=0;
wndclass.cbWndExtra=0;
wndclass.hbrBackground=(HBRUSH)GetStockObject(WHITE_BRUSH);
wndclass.hCursor=LoadCursor(NULL,IDC_ARROW);
wndclass.hIcon=LoadIcon(NULL,IDI_ERROR);
wndclass.hInstance=hInstance;
wndclass.lpfnWndProc=WindowProc;
wndclass.lpszClassName=szAppName;
wndclass.lpszMenuName=NULL;
wndclass.style=CS_HREDRAW|CS_VREDRAW;
if(!RegisterClass(&wndclass))
{
MessageBox(NULL,TEXT("the program require window nt!"),TEXT("xiao tips"),MB_ICONERROR);
return 0;
}
hwnd=CreateWindow(
szAppName, // registered class name
TEXT("this is title"), // window name
WS_OVERLAPPEDWINDOW, // window style
CW_USEDEFAULT, // horizontal position of window
CW_USEDEFAULT, // vertical position of window
CW_USEDEFAULT, // window width
CW_USEDEFAULT, // window height
NULL, // handle to parent or owner window
NULL, // menu handle or child identifier
hInstance, // handle to application instance
NULL // window-creation data
);
ShowWindow(hwnd,nCmdShow);
UpdateWindow(hwnd);
while(GetMessage(&msg,NULL,0,0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
LRESULT CALLBACK WindowProc(
HWND hwnd, // handle to window
UINT uMsg, // message identifier
WPARAM wParam, // first message parameter
LPARAM lParam // second message parameter
)
{
static BOOL fFlipFlop=FALSE;
HBRUSH hbrush;
HDC hdc;
PAINTSTRUCT ps;
RECT rect;
switch(uMsg)
{
case WM_CREATE:
SetTimer(hwnd,ID_TIMER,1000,NULL);//设置一个计时器,时间间隔为1秒
return 0;
case WM_TIMER:
MessageBeep(MB_ICONASTERISK);//发出系统声音
fFlipFlop=!fFlipFlop;//取反
InvalidateRect(hwnd,NULL,FALSE);//触发WM_PAINT事件
return 0;
case WM_PAINT:
hdc=BeginPaint(hwnd,&ps);
GetClientRect(hwnd,&rect);//获取客户区大小
hbrush=CreateSolidBrush(fFlipFlop?RGB(255,0,0):RGB(0,0,255));//判断填充红色还是蓝色
FillRect(hdc,&rect,hbrush);
EndPaint(hwnd,&ps);
DeleteObject(hbrush);//删除画刷
return 0;
case WM_DESTROY:
KillTimer(hwnd,ID_TIMER);//把Timer删掉
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hwnd,uMsg,wParam,lParam);
}
程序虽小,“五脏”俱全。
方法二:
让你只会Windows把计时器消息发送到程序中的另一个函数
收到计时器消息的函数被称为“回调”函数,这是程序中被Windows调用的函数,你告诉Windows这个函数的地址,Windows以后就会调用这个函数。
SetTimer不是以为使用回调功能的Windows函数,CreateDialog,DialogBox都会使用回调函数处理对话框的消息,有几个Windows函数(EnumChildWindow,EnumFont,EnumObject,EnumProps,EnumWindow)会传递枚举信息到回调函数,还有几个不常用的函数GrayString,LineDDA,SetWindowHookEx也要求使用回调函数功能。
//我们给回调函数起名为TimerProc,(你可以取其他名字,函数名不重叠就行)
VOID CALLBACK TimerProc(HWND hwnd,UNIT uMsg,UINT iTimerID,DWORD dwTime)
{
处理TIMER消息
}
下面看看第二种方法和第一种方法的对比,功能完全一样
#include
#define ID_TIMER 1
LRESULT CALLBACK WindowProc(
HWND hwnd, // handle to window
UINT uMsg, // message identifier
WPARAM wParam, // first message parameter
LPARAM lParam // second message parameter
);
VOID CALLBACK TimerProc(
HWND hwnd, // handle to window
UINT uMsg, // message identifier
UINT iTimerID , // first message parameter
DWORD dwTime // second message parameter
);
int WINAPI WinMain(
HINSTANCE hInstance, // handle to current instance
HINSTANCE hPrevInstance, // handle to previous instance
LPSTR lpCmdLine, // command line
int nCmdShow // show state
)
{
static TCHAR szAppName[]=TEXT("leidemingzi");
HWND hwnd;
MSG msg;
WNDCLASS wndclass;
wndclass.cbClsExtra=0;
wndclass.cbWndExtra=0;
wndclass.hbrBackground=(HBRUSH)GetStockObject(WHITE_BRUSH);
wndclass.hCursor=LoadCursor(NULL,IDC_ARROW);
wndclass.hIcon=LoadIcon(NULL,IDI_ERROR);
wndclass.hInstance=hInstance;
wndclass.lpfnWndProc=WindowProc;
wndclass.lpszClassName=szAppName;
wndclass.lpszMenuName=NULL;
wndclass.style=CS_HREDRAW|CS_VREDRAW;
if(!RegisterClass(&wndclass))
{
MessageBox(NULL,TEXT("the program require window nt!"),TEXT("xiao tips"),MB_ICONERROR);
return 0;
}
hwnd=CreateWindow(
szAppName, // registered class name
TEXT("this is title"), // window name
WS_OVERLAPPEDWINDOW, // window style
CW_USEDEFAULT, // horizontal position of window
CW_USEDEFAULT, // vertical position of window
CW_USEDEFAULT, // window width
CW_USEDEFAULT, // window height
NULL, // handle to parent or owner window
NULL, // menu handle or child identifier
hInstance, // handle to application instance
NULL // window-creation data
);
ShowWindow(hwnd,nCmdShow);
UpdateWindow(hwnd);
while(GetMessage(&msg,NULL,0,0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
LRESULT CALLBACK WindowProc(
HWND hwnd, // handle to window
UINT uMsg, // message identifier
WPARAM wParam, // first message parameter
LPARAM lParam // second message parameter
)
{
switch(uMsg)
{
case WM_CREATE:
SetTimer(hwnd,ID_TIMER,1000,TimerProc);
return 0;
case WM_DESTROY:
KillTimer(hwnd,ID_TIMER);
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hwnd,uMsg,wParam,lParam);
}
VOID CALLBACK TimerProc(
HWND hwnd, // handle to window
UINT uMsg, // message identifier
UINT iTimerID, // first message parameter
DWORD dwTime // second message parameter
)
{
static BOOL fFlipFlop=FALSE;
HBRUSH hbrush;
HDC hdc;
RECT rect;
MessageBeep(MB_ICONASTERISK);
fFlipFlop=!fFlipFlop;
GetClientRect(hwnd,&rect);
hdc=GetDC(hwnd);
hbrush=CreateSolidBrush(fFlipFlop?RGB(255,0,0):RGB(0,0,255));
FillRect(hdc,&rect,hbrush);
ReleaseDC(hwnd,hdc);
DeleteObject(hbrush);
}
方法三:
第三种设置计时器的方法和第二种方法相似,只不过SetTimer的hwnd参数被设置成为NULL,而且第二个方法被忽略了,此外这个函数会返回计时器的ID
itimerId=SetTimer(NULL,0,wMsecInterval,TimerProc);
KillTimer(NULL,iTimerID);
这种计时器比较少用,如果在程序中,需要不同的时候调用很多次SetTimer,但又不想记录哪些计时器ID已经被使用过,那么这种方法可能会派上用场
在此,不举例子了。
(关注计时器(X),有更精彩的例子)