说起时间,对于我们搞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); }
运行效果还是很漂亮的:
可以看见,无边矩形、椭圆、圆角矩形交错绘制,呵呵……