深入淺出Win32的計時器

本文由BlueCoder編寫   轉載請說明出處:

http://blog.csdn.net/crocodile__/article/details/9491863

我的郵箱:[email protected]    歡迎大家和我交流編程心得

我的微博:BlueCoder_黎小華    歡迎光臨^_^




說起時間,對於我們搞IT的人來說,那是要多重要有多重要。我覺得有價值的時間是給有抱負和有才能的人準備的,因爲他們會充分利用,不會讓時間失望……

 

呵呵,有點兒說遠了,還是迴歸主題吧

 

Win32的計時器其實就是用以下兩個函數控制的一個控件:

設置計時器

UINT_PTR SetTimer(
    HWND hWnd,
    UINT_PTR nIDEvent,
    UINT uElapse,
    TIMERPROC lpTimerFunc
);

 

關閉計時器

BOOL KillTimer(      

    HWND hWnd,
    UINT_PTR uIDEvent
);

 

函數KillTimer我不打算多說,只是對於多個計時器的時候,注意通過uIDEvent來關閉,不要關閉錯誤了

 

下面我講一下個人認爲比較重要的兩點:

(1)實現計時器有兩種主要的方式:

a)在窗口回調函數中響應WM_TIMER消息(SetTimer的第四個參數就應該設爲NULL,表示不使用計時器回調函數)

b)自行寫一個計時器回調函數,每一次就自動調用這個計時器回調函數(SetTimer的第四個參數就應該設爲改函數的名稱,TimerProc)

(2)如果是使用計時器回調函數,並用VC++6.0編譯的,可能會遇到以下情況:

剛剛寫計時器程序的時候,我就是按照API中給的TimerProc函數原型來調用:

#define ID_TIMER	1//計時器ID
SetTimer(hwnd, ID_TIMER, 1000, TimerProc);
VOID CALLBACK TimerProc(HWND, UINT, UINT_PTR, DWORD);
 
VOID CALLBACK TimerProc(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime)

 

結果發現編譯有錯誤:(我是用VC++6.0編譯的)

error C2664: 'SetTimer' : cannot convert parameter 4 from 'void (struct HWND__ *,unsigned int,unsigned long,unsigned long)' to 'void (__stdcall *)(struct HWND__ *,unsigned int,unsigned int,unsigned long)' ,  None of the functions with this name in scope match the target type

 

從給的提示上可以知道錯誤出現在類型轉換上,unsigned long不能轉換爲unsigned int

其實就是SetTimer的第二個參數在作怪,我們先來看看這第二個參數是什麼樣的類型:

typedef unsigned long UINT_PTR

然而我自行定義的ID_TIMER就是一個int,但是從c語言類型規範來講,int是可以轉換成unsigned int或unsigned long的,在win32中都是32位,只是在這裏VC++6.0不支持它們的轉換。這個可以用一個簡單的方法證明是編譯器的問題:

就是如果你用vs2008來編譯,沒有點兒問題……

 

解決方法有兩種:

a)一是上面講的,用vs2008或是更高的版本來編譯

b)二是依然用vc++6.0編譯,但是需要將WndProc的第三個參數的類型改爲UINT

LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)

 

 

以上就是個人覺得需要注意的地方,下面開始講我今兒編的程序,就是利用計時器來繪製五彩繽紛的圖形(我設定了三種:無邊框的矩形、橢圓、圓角矩形)

算法還是比較簡單,應該不需要多說,代碼也有註釋^_^:

//TimerDemo(定時器實例--隨機大小的圖形)
#include<windows.h>
#include<stdio.h>
//定義定時器ID
#define	ID_TIMER		0
//圖形種類
#define G_RECT		0
#define G_ELLIPSE		1
#define G_ROUNDRECT	2

//客戶區大小
int		cxClient, cyClient;

//計數變量(控制每次繪製的圖形)
int		gCount = 0;

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
VOID CALLBACK TimerProc(HWND, UINT, UINT_PTR, DWORD);		//計時器回調函數(由於我現在改用vs2008了,所以就不需要將UINT_PTR改爲UINT)

int WINAPI WinMain(HINSTANCE hInstance,
				   HINSTANCE hPrevInstance,
                   PSTR szCmdLine,
				   int iCmdShow)
{
	static	TCHAR	szAppName[] = TEXT("RandomRect");
	HWND			hwnd;
	MSG				msg;
	WNDCLASS		wndclass;
	int				cxSystem, cySystem;//系統屏幕分辨率(也就是長寬)
	
	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("This program requires Windows NT!"),
			szAppName, MB_ICONERROR);
		return 0;
	}
	
	//獲取屏幕大小
	cxSystem = GetSystemMetrics(SM_CXSCREEN);
	cySystem = GetSystemMetrics(SM_CYSCREEN);
	hwnd = CreateWindow(szAppName,
						TEXT("RandomRect Demo"),
						WS_OVERLAPPEDWINDOW,
						cxSystem / 4,//居中顯示窗口
						cySystem / 8,
						cxSystem / 2,
						cySystem * 3 / 4,
						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)
{	
	switch(message)
	{
	case WM_CREATE:
		SetTimer(hwnd, ID_TIMER, 100, TimerProc);		//啓動計時器
		return 0 ;

	case WM_SIZE:
		cxClient = LOWORD(lParam);
		cyClient = HIWORD(lParam);

		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 uMsg, UINT_PTR idEvent, DWORD dwTime)
{
	RECT	rect;
	HDC		hdc;
	HBRUSH  hBrush;

	hdc = GetDC(hwnd);

	hBrush = CreateSolidBrush(RGB(rand()%255, rand()%255, rand()%255));

	switch(gCount)
	{
	//無邊框矩形
	case G_RECT:
		SetRect(&rect, rand()%cxClient, rand()%cyClient, rand()%cxClient, rand()%cyClient);
		FillRect(hdc, &rect, hBrush);
		break;

	//彩色橢圓
	case G_ELLIPSE:
		SelectObject(hdc, hBrush);
		Ellipse(hdc, rand()%cxClient, rand()%cyClient, rand()%cxClient, rand()%cyClient);
		break;

	//圓角矩形
	case G_ROUNDRECT:
		SelectObject(hdc, hBrush);
		RoundRect(hdc, rand()%cxClient, rand()%cyClient, rand()%cxClient, rand()%cyClient, rand()%100, rand()%100);
		break;
	}
	gCount = (gCount + 1) % 3;//繼續計數,以控制下一次的圖形繪製
	DeleteObject(hBrush);
	ReleaseDC(hwnd, hdc);
}


 

 

運行效果還是很漂亮的:

 

可以看見,無邊矩形、橢圓、圓角矩形交錯繪製,呵呵……

發佈了39 篇原創文章 · 獲贊 29 · 訪問量 28萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章