计时器(1)之3种方法

你可以使用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),有更精彩的例子)

你可能感兴趣的:(计时器(1)之3种方法)