8.1 计时器的基本知识
(1)SetTimer时间参数:1毫秒到4294 967 295毫秒(近50天)
(2)Windows本身处理BIOS中断,应用程序不需介入,Windows会每个计时器保持一个计数值,硬件时钟滴答一次,这个值减1.当计数为0时,发送WM_TIMER到消息队列,同时计数值重新恢复到原始值。
(3)WIN98的计时器周期约为55毫秒,Windows NT大约为10毫秒。即SetTimer参数小于这个数值,则根据操作系统取其中的一个值。SetTimer会把指定的时间间隔舍入到时钟滴答的整数倍,如1000ms/54.925=18.2个时钟滴答,舍入后为18个时钟滴答,即实际的间隔为989ms。
(4)计时器消息不是异步的。在指定的时间内可能因程序忙而收到不到WM_TIMER消息。WM_TIMER消息与WM_PAINT消息都是低优先级的,只有当队列没其他消息时,程序才会接收它们。
8.2 使用计时器的三种方法
(1)处理WM_TIMER消息
①SetTimer(hwnd,ID_TIMER,uiMsecInterval,NULL);//ID_TIMER>0,不能为0.
②KillTimer(hwnd,ID_TIMER);
③消息参数:wParam=ID_TIMER; lParam =0;
例: 定义2个计时器 #define TIMER_SEC 1 #define TIMER_MIN 2 //设置定时器 SetTimer(hwnd,TIMER_SEC,1000,NULL); //1秒 SetTimer(hwnd,TIMER_MIN,60000,NULL); //1分钟 //WM_TIMER处理逻辑 case WM_TIMER: switch(wParam) { case TIMER_SEC: [每秒钟一次的处理] Break; case TIMER_MIN: [每分钟一次的处理] Break; } return 0; |
【Beeper1程序】
/*------------------------------------------------------------ BEEPER1.C -- Timer Demo Program No.1 (c) Charles Petzold, 1998 ------------------------------------------------------------*/ #include <windows.h> #define ID_TIMER 1 LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow) { static TCHAR szAppName[] = TEXT("Beeper1"); HWND hwnd; MSG msg; WNDCLASS wndclass; 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; } hwnd = CreateWindow(szAppName, // window class name TEXT("Beeper1 Timer Demo"), // window caption WS_OVERLAPPEDWINDOW, // window style CW_USEDEFAULT, // initial x position CW_USEDEFAULT, // initial y position CW_USEDEFAULT, // initial x size CW_USEDEFAULT, // initial y size NULL, // parent window handle NULL, // window menu handle hInstance, // program instance handle NULL); // creation parameters 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) { static BOOL fFlipFlop = FALSE; HBRUSH hBrush; HDC hdc; PAINTSTRUCT ps; RECT rect; switch (message) { case WM_CREATE: SetTimer(hwnd, ID_TIMER, 1000, NULL); return 0; case WM_TIMER: MessageBeep(-1); fFlipFlop = !fFlipFlop; InvalidateRect(hwnd, NULL, FALSE); 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); DeleteObject(hBrush); EndPaint(hwnd, &ps); return 0; case WM_DESTROY: KillTimer(hwnd, ID_TIMER); PostQuitMessage(0); return 0; } return DefWindowProc(hwnd, message, wParam, lParam); }
(2)利用回调函数处理——将忽略窗口过程中的WM_TIMER消息处理代码
①VOID CALLBACK MyTimerProc(HWNDhwnd,UINT message,UINT iTimerID,DWORD dwTime)
②SetTimer(hwnd,iTimerID,iMsecInterval,MyTimerProc);
★注意:从回调函数中得到的dwTime等于GetTickCount返回的值,指的是自Windows启动到现在的毫秒数。
【Beeper2程序】
/*------------------------------------------------------------ BEEPER2.C -- Timer Demo Program No.2 (c) Charles Petzold, 1998 ------------------------------------------------------------*/ #include <windows.h> #define ID_TIMER 1 VOID CALLBACK TimerProc(HWND, UINT, UINT, DWORD); LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow) { static TCHAR szAppName[] = TEXT("Beeper2"); HWND hwnd; MSG msg; WNDCLASS wndclass; 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; } hwnd = CreateWindow(szAppName, // window class name TEXT("Beeper2 Timer Demo"), // window caption WS_OVERLAPPEDWINDOW, // window style CW_USEDEFAULT, // initial x position CW_USEDEFAULT, // initial y position CW_USEDEFAULT, // initial x size CW_USEDEFAULT, // initial y size NULL, // parent window handle NULL, // window menu handle hInstance, // program instance handle NULL); // creation parameters ShowWindow(hwnd, iCmdShow); UpdateWindow(hwnd); while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } return msg.wParam; } VOID CALLBACK TimerProc(HWND hwnd, UINT message, UINT iTimerID, DWORD dwTime) { HBRUSH hBrush; HDC hdc; RECT rect; static BOOL fFlipFlop = FALSE; MessageBeep(-1); fFlipFlop = !fFlipFlop; hdc = GetDC(hwnd); GetClientRect(hwnd, &rect); hBrush = CreateSolidBrush(fFlipFlop ? RGB(255, 0, 0) : RGB(0, 0, 255)); FillRect(hdc, &rect, hBrush); DeleteObject(hBrush); ReleaseDC(hwnd, hdc); } LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { switch (message) { case WM_CREATE: SetTimer(hwnd, ID_TIMER, 1000, TimerProc); return 0; // case WM_TIMER: //MessageBeep(-1); //fFlipFlop = !fFlipFlop; //InvalidateRect(hwnd, NULL, FALSE); //return 0; case WM_DESTROY: KillTimer(hwnd, ID_TIMER); PostQuitMessage(0); return 0; } return DefWindowProc(hwnd, message, wParam, lParam); }
(3)方法三——与第2种相似,但SetTimer的设置如下。(一般很少这样用)
参数 |
设置 |
备注 |
hwnd |
NULL |
SetTimer、KillTimer、回调函数的hwnd都要设为NULL; |
第2个参数 |
0 |
被忽略,填0 |
第4个参数 |
TimerProc |
回调函数 |
返回值 |
计时器的ID |
如返回0,说明没有可用的计时器 |
8.3 使用计时器作为时钟
8.3.1 数字时钟
(1)获取系统时间:GetLocalTime(当地时间)和GetSystemTime(协调世界时UTC)
(2)显示数字和冒号——自定义函数DisplayDigit和DisplayColon
①BOOL fSevenSegment[10][7]——用来控制0-9这10个数字的LED相应段开与关
②static POINT ptSegment[7][6]——表示LED中7个六边形的顶点坐标。
③数字宽度为42个单位,高度为72个单位,冒号是12个单位宽。6个数字加冒号共276个单位宽度。
(3)国际化——控制面板【区域和语言选项】中设置格式化日期和时间
①显示12或24小时格式。
//获得是否是24小时格式
GetLocaleInfo(LOCALE_USER_DEFAULT,LOCALE_ITIME, szBuffer, 2);
f24Hour = (szBuffer[0] ==‘1‘);
②小时数字是0不显示的处理,见DisplayTwoDigits函数。
//获取是否显示小时的第1个0.
GetLocaleInfo(LOCALE_USER_DEFAULT,LOCALE_ITLZERO, szBuffer, 2);
fSuppress= (szBuffer[0] == ‘0‘);
【DigClock程序】
【效果图】
/*------------------------------------------------------------ DIGCLOCK.C -- Digital Clock (c) Charles Petzold, 1998 ------------------------------------------------------------*/ #include <windows.h> #define ID_TIMER 1 LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow) { static TCHAR szAppName[] = TEXT("DigClock"); HWND hwnd; MSG msg; WNDCLASS wndclass; 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; } hwnd = CreateWindow(szAppName, // window class name TEXT("Digital Clock"), // window caption WS_OVERLAPPEDWINDOW, // window style CW_USEDEFAULT, // initial x position CW_USEDEFAULT, // initial y position CW_USEDEFAULT, // initial x size CW_USEDEFAULT, // initial y size NULL, // parent window handle NULL, // window menu handle hInstance, // program instance handle NULL); // creation parameters ShowWindow(hwnd, iCmdShow); UpdateWindow(hwnd); while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } return msg.wParam; } void DisplayDigit(HDC hdc, int iNumber) { static BOOL fSevenSegment[10][7] = { 1, 1, 1, 0, 1, 1, 1, //0 0, 0, 1, 0, 0, 1, 0, //1 1, 0, 1, 1, 1, 0, 1, //2 1, 0, 1, 1, 0, 1, 1, //3 0, 1, 1, 1, 0, 1, 0, //4 1, 1, 0, 1, 0, 1, 1, //5 1, 1, 0, 1, 1, 1, 1, //6 1, 0, 1, 0, 0, 1, 0, //7 1, 1, 1, 1, 1, 1, 1, //8 1, 1, 1, 1, 0, 1, 1 };//9 //定义数字8的每个笔划(共7笔,每笔形状为6边形) static POINT ptSegment[7][6] = { 7, 6, 11, 2, 31, 2, 35, 6, 31, 10, 11, 10, //第0笔 6, 7, 10, 11, 10, 31, 6, 35, 2, 31, 2, 11, //第1笔 36, 7, 40, 11, 40, 31, 36, 35, 32, 31, 32, 11, //第2笔 7, 36, 11, 32, 31, 32, 35, 36, 31, 40, 11, 40, //第3笔 6, 37, 10, 41, 10, 61, 6, 65, 2, 61, 2, 41, //第4笔 36, 37, 40, 41, 40, 61, 36, 65, 32, 61, 32, 41, //第5笔 7, 66, 11, 62, 31, 62, 35, 66, 31, 70, 11, 70 }; //第6笔 for (int iSeg = 0; iSeg < 7; iSeg++) { if (fSevenSegment[iNumber][iSeg]) { Polygon(hdc, ptSegment[iSeg], 6); } } } void DisplayTwoDigits(HDC hdc, int iNumber, BOOL fSuppress) { //将0显示为“ 0”或“00” if (!fSuppress || (iNumber / 10 != 0)) DisplayDigit(hdc, iNumber / 10); //执行到这里,0显示为“00” OffsetWindowOrgEx(hdc, -42, 0, NULL); DisplayDigit(hdc, iNumber % 10); OffsetWindowOrgEx(hdc, -42, 0, NULL);//每个数字的宽度为42个像素 } void DisplayColon(HDC hdc) { POINT ptColon[2][4] = { 2, 21, 6, 17, 10, 21, 6, 25, 2, 51, 6, 47, 10, 51, 6, 55 }; Polygon(hdc, ptColon[0], 4); Polygon(hdc, ptColon[1], 4); OffsetWindowOrgEx(hdc, -12, 0, NULL); //冒号的宽度为12像素 } void DisplayTime(HDC hdc, BOOL f24Hour, BOOL fSuppress) { SYSTEMTIME st; GetLocalTime(&st); //显示小时,24小时格式变或12小时格式 if (f24Hour) { DisplayTwoDigits(hdc, st.wHour, fSuppress); } else { //12小时格式,将0\12\24,统一显示为12 DisplayTwoDigits(hdc, (st.wHour %= 12) ? st.wHour : 12, fSuppress); } DisplayColon(hdc); //显示分钟 DisplayTwoDigits(hdc, st.wMinute, FALSE); DisplayColon(hdc); //显示秒数 DisplayTwoDigits(hdc, st.wSecond, FALSE); } LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { static BOOL f24Hour, fSuppress; static HBRUSH hBrushRed; static int cxClient, cyClient; TCHAR szBuffer[2]; HDC hdc; PAINTSTRUCT ps; switch (message) { case WM_CREATE: SetTimer(hwnd, ID_TIMER, 1000, NULL); hBrushRed = CreateSolidBrush(RGB(255, 0, 0)); //继续执行 case WM_SETTINGCHANGE: //获得是否是24小时格式 GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_ITIME, szBuffer, 2); f24Hour = (szBuffer[0] == ‘1‘); //获取是否显示小时的第1个0. GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_ITLZERO, szBuffer, 2); fSuppress = (szBuffer[0] == ‘0‘); InvalidateRect(hwnd, NULL, TRUE); return 0; case WM_SIZE: cxClient = LOWORD(lParam); cyClient = HIWORD(lParam); return 0; case WM_TIMER: InvalidateRect(hwnd, NULL, TRUE); return 0; case WM_PAINT: hdc = BeginPaint(hwnd, &ps); SetMapMode(hdc, MM_ISOTROPIC); //各向同性 SetWindowExtEx(hdc, 276, 72, NULL);//共6个数字,每个数字宽42,2对显号,每对宽12 SetViewportExtEx(hdc, cxClient, cyClient, NULL); //输出中心移动到客户区中央 SetWindowOrgEx(hdc, 138, 36, NULL); SetViewportOrgEx(hdc, cxClient / 2, cyClient / 2, NULL); SelectObject(hdc, GetStockObject(NULL_PEN)); SelectObject(hdc, (HGDIOBJ)hBrushRed); DisplayTime(hdc, f24Hour, fSuppress); EndPaint(hwnd, &ps); return 0; case WM_DESTROY: KillTimer(hwnd, ID_TIMER); DeleteObject(hBrushRed); PostQuitMessage(0); return 0; } return DefWindowProc(hwnd, message, wParam, lParam); }
8.3.2 模拟时钟
(1)坐标系统的设置——各向同性、y轴向上为正,坐标轴原点在客户区中央。
①逻辑窗口范围(1000,1000)
②视口范围(cxClient/2,cyClient/2);
(2)坐标旋轴——用来画刻度和时分针
(3)stPrevious用来判断小时和分钟是否要更新。如果要,用白色画笔在之前的时间位置重绘一遍,相于当抹掉。如果不需要,只有秒针被抹掉。然后,用黑笔画所有指针一次。
【Clock程序】
效果图
/*------------------------------------------------------------ CLOCK.C -- Analog Clock Program (c) Charles Petzold, 1998 ------------------------------------------------------------*/ #include <windows.h> #include <math.h> #define TWOPI (2*3.14159) #define ID_TIMER 1 LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow) { static TCHAR szAppName[] = TEXT("Clock"); HWND hwnd; MSG msg; WNDCLASS wndclass; 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; } hwnd = CreateWindow(szAppName, // window class name TEXT("Analog Clock"), // window caption WS_OVERLAPPEDWINDOW, // window style CW_USEDEFAULT, // initial x position CW_USEDEFAULT, // initial y position CW_USEDEFAULT, // initial x size CW_USEDEFAULT, // initial y size NULL, // parent window handle NULL, // window menu handle hInstance, // program instance handle NULL); // creation parameters ShowWindow(hwnd, iCmdShow); UpdateWindow(hwnd); while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } return msg.wParam; } void SetIsotropic(HDC hdc, int cxClient, int cyClient) { SetMapMode(hdc, MM_ISOTROPIC); SetWindowExtEx(hdc, 1000, 1000, NULL); //逻辑高度和逻辑宽度 SetViewportExtEx(hdc, cxClient / 2, -cyClient / 2, NULL); //y轴向上为正 SetViewportOrgEx(hdc, cxClient / 2, cyClient / 2, NULL); //坐标原点位于客户区中央 } void RotatePoint(POINT pt[], int iNum, int iAngle) { POINT ptTemp; for (int i = 0; i < iNum; i++) { ptTemp.x = (int)(pt[i].x*cos(iAngle*TWOPI / 360) + pt[i].y*sin(iAngle*TWOPI / 360)); ptTemp.y = (int)(pt[i].y*cos(iAngle*TWOPI / 360) - pt[i].x*sin(iAngle*TWOPI / 360)); pt[i] = ptTemp; } } //画针面的刻度 void DrawClock(HDC hdc) { POINT pt[3]; for (int iAngle = 0; iAngle < 360; iAngle += 6) { pt[0].x = 0; pt[0].y = 900; RotatePoint(pt, 1, iAngle); pt[2].x = pt[2].y = (iAngle % 5) ? 33 : 100; //圆的大小(直径) //Ellipse左上角的点 pt[0].x -= pt[2].x / 2; pt[0].y -= pt[2].y / 2; //Ellipse右下角的点 pt[1].x = pt[0].x + pt[2].x; pt[1].y = pt[0].y + pt[2].y; SelectObject(hdc, GetStockObject(BLACK_BRUSH)); Ellipse(hdc, pt[0].x, pt[0].y, pt[1].x, pt[1].y); } } void DrawHands(HDC hdc, SYSTEMTIME* pst, BOOL fChange) { static POINT pt[3][5] = { 0, -150, 100, 0, 0, 600, -100, 0, 0, -150, //时针 0, -200, 50, 0, 0, 800, -50, 0, 0, -200, //分针 0, 0, 0, 0, 0, 0, 0, 0, 0, 800 }; //秒针 int iAngle[3]; POINT ptTemp[3][5]; iAngle[0] = (pst->wHour * 30) % 360 + pst->wMinute / 2; //时针每小时30度。 iAngle[1] = pst->wMinute * 6; //每分钟,分针走6度。 iAngle[2] = pst->wSecond * 6; //每秒,秒针走6度。 memcpy(ptTemp, pt, sizeof(pt)); for (int i = fChange ? 0 : 2; i < 3; i++) //判断是否只画秒针 { RotatePoint(ptTemp[i], 5, iAngle[i]); Polyline(hdc, ptTemp[i], 5); } } LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { HDC hdc; PAINTSTRUCT ps; static SYSTEMTIME stPrevious; BOOL fChange; SYSTEMTIME st; static int cxClient, cyClient; switch (message) { case WM_CREATE: SetTimer(hwnd, ID_TIMER, 1000, NULL); GetLocalTime(&st); stPrevious = st; return 0; case WM_SIZE: cxClient = LOWORD(lParam); cyClient = HIWORD(lParam); return 0; case WM_TIMER: GetLocalTime(&st); //小时和分钟是否改变 fChange = st.wHour != stPrevious.wHour || st.wMinute != stPrevious.wMinute; hdc = GetDC(hwnd); SetIsotropic(hdc, cxClient, cyClient); //将旧的时分秒针用白色擦掉 SelectObject(hdc, GetStockObject(WHITE_PEN)); DrawHands(hdc, &stPrevious, fChange); //画新的时分秒针 SelectObject(hdc, GetStockObject(BLACK_PEN)); DrawHands(hdc, &st, TRUE); ReleaseDC(hwnd, hdc); stPrevious = st; return 0; case WM_PAINT: hdc = BeginPaint(hwnd, &ps); SetIsotropic(hdc, cxClient, cyClient); DrawClock(hdc); DrawHands(hdc, &stPrevious, TRUE); EndPaint(hwnd, &ps); return 0; case WM_DESTROY: KillTimer(hwnd, ID_TIMER); PostQuitMessage(0); return 0; } return DefWindowProc(hwnd, message, wParam, lParam); }
8.4 在状态报告上使用计时器
(1)窗口固定大小:其大小从自定义的FindWindowSize函数求得。窗口风格WS_BORDER。
(2)创建屏幕DC,程序可以从屏幕任何地方获得当前鼠标指针位置的像素颜色。
【WhatClr程序】
效果图
/*------------------------------------------------------------ WHATCLR.C -- Displays Color Under Cursor (c) Charles Petzold, 1998 ------------------------------------------------------------*/ #include <windows.h> #define ID_TIMER 1 LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); void FindWindowSize(int*, int*); int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow) { static TCHAR szAppName[] = TEXT("WhatClr"); HWND hwnd; MSG msg; WNDCLASS wndclass; int cxWindow, cyWindow; 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; } FindWindowSize(&cxWindow, &cyWindow); hwnd = CreateWindow(szAppName, // window class name TEXT("What Color"), // window caption WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_BORDER, // window style CW_USEDEFAULT, // initial x position CW_USEDEFAULT, // initial y position cxWindow, // initial x size cyWindow, // initial y size NULL, // parent window handle NULL, // window menu handle hInstance, // program instance handle NULL); // creation parameters ShowWindow(hwnd, iCmdShow); UpdateWindow(hwnd); while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } return msg.wParam; } void FindWindowSize(int* pcxWindow, int* pcyWindow) { HDC hdcScreen; TEXTMETRIC tm; hdcScreen = CreateIC(TEXT("DISPLAY"), NULL, NULL, NULL); //屏幕hdc GetTextMetrics(hdcScreen, &tm); DeleteDC(hdcScreen); *pcxWindow = 2 * GetSystemMetrics(SM_CXBORDER) + 12 * tm.tmAveCharWidth; //宽度=2个边框加12个字符的宽度 *pcyWindow = 2 * GetSystemMetrics(SM_CYBORDER) + GetSystemMetrics(SM_CYCAPTION) + 2 * tm.tmHeight;; } LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { static HDC hdcScreen; static COLORREF cr, crLast; POINT pt; TCHAR szBuffer[16]; HDC hdc; PAINTSTRUCT ps; RECT rect; switch (message) { case WM_CREATE: hdcScreen = CreateDC(TEXT("DISPLAY"), NULL, NULL, NULL); SetTimer(hwnd, ID_TIMER, 100, NULL); return 0; case WM_TIMER: GetCursorPos(&pt); cr = GetPixel(hdcScreen, pt.x, pt.y); if (cr != crLast) { crLast = cr; InvalidateRect(hwnd, NULL, TRUE); } return 0; case WM_PAINT: hdc = BeginPaint(hwnd, &ps); GetClientRect(hwnd, &rect); wsprintf(szBuffer, TEXT(" %02X %02X %02X "), GetRValue(cr), GetGValue(cr), GetBValue(cr)); DrawText(hdc, szBuffer, -1, &rect, DT_SINGLELINE | DT_CENTER | DT_VCENTER); EndPaint(hwnd, &ps); return 0; case WM_DESTROY: DeleteDC(hdcScreen); KillTimer(hwnd, ID_TIMER); PostQuitMessage(0); return 0; } return DefWindowProc(hwnd, message, wParam, lParam); }