本文由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);
}
運行效果還是很漂亮的:
可以看見,無邊矩形、橢圓、圓角矩形交錯繪製,呵呵……