这段时间一直有看《windows程序设计》,通过C语言调用windows API,这并不是件轻松的事,windows API很复杂,还涉及到各种概念性的东西需要理解,再加上使用的是C语言,所以涉及到的知识点相当的多。《windows程序设计》第8章提供了一个简易的颜色拾取器,界面如下:
这个拾取器,实现了主要功能,但不能复制,不能暂停,也没有显示当前坐标拾取的颜色,于是自己花了点时间,改进下,实现了上述功能,代码如下:
#include#define ID_TIMER 1#define ID_EDIT 2#define ID_BUTTON 3#define PK_WIDTH 80#define BT_WIDTH 30void FindWindowSize (int *, int *,int *) ;LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ;VOID CALLBACK TimerProc(HWND,UINT,UINT,DWORD);BOOL setEditAndButton(HWND,HWND,BOOL);int cxWindow, cyWindow,cxPosition;int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow){ static TCHAR szAppName[] = TEXT ("PickColor") ; 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 ; } FindWindowSize (&cxWindow, &cyWindow,&cxPosition) ; hwnd = CreateWindowEx (WS_EX_TOPMOST | WS_EX_TOOLWINDOW,szAppName, TEXT ("颜色拾取"),WS_OVERLAPPED | WS_BORDER | WS_SYSMENU | WS_CLIPCHILDREN, cxPosition, 80, PK_WIDTH,cyWindow*2, NULL, NULL, hInstance, NULL) ; ShowWindow (hwnd, iCmdShow) ; UpdateWindow (hwnd) ; while (GetMessage (&msg, NULL, 0, 0)) { TranslateMessage (&msg) ; DispatchMessage (&msg) ; } return msg.wParam ;}void FindWindowSize (int * pcxWindow, int * pcyWindow,int *pcxPosition){ HDC hdcScreen ; TEXTMETRIC tm ; hdcScreen = CreateIC (TEXT ("DISPLAY"), NULL, NULL, NULL) ; GetTextMetrics (hdcScreen, &tm) ; DeleteDC (hdcScreen) ; /* SM_CXBORDER:边框的宽度,SM_CYCAPTION:标题栏的高度,tmAveCharWidth:字符的平均宽度,tmHeight:字符的最大高度 */ * pcxWindow = 2 * GetSystemMetrics (SM_CXBORDER) + 6 * tm.tmAveCharWidth ; * pcyWindow = 2 * GetSystemMetrics (SM_CYBORDER) + GetSystemMetrics (SM_CYCAPTION) + 2 * tm.tmHeight ; *pcxPosition = GetSystemMetrics(SM_CXSCREEN) - *pcxWindow-200;}LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam){ static BOOL flag = TRUE;//标志位 暂停(FALSE) 开启(TRUE) static HWND hwndEdit; static HWND hwndButton; switch (message) { case WM_CREATE: hwndEdit = CreateWindow (TEXT ("edit"), NULL, WS_CHILD | WS_VISIBLE | WS_BORDER | ES_CENTER | ES_READONLY, 0, cyWindow/2, PK_WIDTH, BT_WIDTH, hwnd, (HMENU) ID_EDIT, ((LPCREATESTRUCT) lParam) -> hInstance, NULL) ; hwndButton = CreateWindow( TEXT("button"), TEXT("停止(F7)"), WS_CHILD | WS_VISIBLE | WS_BORDER , 0, cyWindow, PK_WIDTH, BT_WIDTH, hwnd, (HMENU)ID_BUTTON, (HINSTANCE)GetWindowLong(hwnd,GWL_HINSTANCE), NULL); SetTimer (hwnd, ID_TIMER, 100, TimerProc) ; return 0 ; case WM_KEYDOWN: switch(wParam) { case VK_F7: flag = setEditAndButton(hwnd,hwndButton,flag); } return 0; case WM_COMMAND: switch(LOWORD(wParam)) { case ID_BUTTON: flag = setEditAndButton(hwnd,hwndButton,flag); } break; case WM_DESTROY: KillTimer (hwnd, ID_TIMER) ; PostQuitMessage (0) ; return 0 ; } return DefWindowProc (hwnd, message, wParam, lParam) ;}BOOL setEditAndButton(HWND hwnd,HWND hwndButton,BOOL flag){ if(flag){ SetWindowText(hwndButton,TEXT("开启(F7)")); KillTimer (hwnd, ID_TIMER) ; }else{ SetWindowText(hwndButton,TEXT("停止(F7)")); SetTimer (hwnd, ID_TIMER, 100, TimerProc) ; } SetFocus(hwnd); return !flag;}VOID CALLBACK TimerProc(HWND hwnd,UINT message,UINT iTimerID,DWORD dwTime){ COLORREF cr, crLast = 0 ; HDC hdcScreen = CreateDC (TEXT ("DISPLAY"), NULL, NULL, NULL) ; HDC hdc ; POINT pt ; RECT rc ; TCHAR szBuffer [16] ; COLORREF colorRef; GetCursorPos (&pt) ; cr = GetPixel (hdcScreen, pt.x, pt.y) ; hdc = GetDC(hwnd); if (cr != crLast) { crLast = cr ; InvalidateRect (hwnd, NULL, FALSE) ; } colorRef = RGB(GetRValue (cr), GetGValue (cr), GetBValue (cr)); GetClientRect (hwnd, &rc) ; wsprintf (szBuffer, TEXT ("#%02X%02X%02X"),GetRValue (cr), GetGValue (cr), GetBValue (cr)) ; SetWindowText(GetDlgItem(hwnd,ID_EDIT),szBuffer); FillRect(hdc, &rc,CreateSolidBrush (colorRef)); DeleteDC (hdcScreen) ;}
运行界面如下:
对于C语言来说,vc++6.0已经足够了,虽然最新的语法不支持,但那不是重点,基础学好了,新语法也能很快掌握。至于上面代码涉及到的东西相当多,讲几个本人觉得重要的:
1,关于CreateWindowEx,这个地方没有采用CreateWindow,因为它缺少一个dwExStle参数,这个参数可以指定窗口的扩展风格,具体来说,就是WS_EX_TOPMOST | WS_EX_TOOLWINDOW,WS_EX_TOPMOST 表示窗口总在最前面,WS_EX_TOOLWINDOW表示此窗口是一个游动的工具窗口,此处主要是让标题栏变得更窄,不能设计窗口的宽度低于一定程度时会不起作用,当然工具窗口不会出现在任务栏上面。
2,CreateWindowEx中的dwStyle,WS_OVERLAPPED | WS_BORDER | WS_SYSMENU | WS_CLIPCHILDREN,WS_BORDER表示固定窗口大小,WS_SYSMENU用于显示“关闭”图标,WS_CLIPCHILDREN表示,当在父窗口内绘图时,排除子窗口区域。
3,获取父窗口的实例句柄。在创建hwndEdit、hwndButton两个子窗口时,采用了两种不同的方式获取父窗口实例句柄:
第一种:((LPCREATESTRUCT) lParam) -> hInstance第二种:(HINSTANCE)GetWindowLong(hwnd,GWL_HINSTANCE)
4,计时器。颜色拾取器原理是根据鼠标移动位置时,在间隔极短的时间内触发计时器,从而获取当前坐标的颜色。本文采用的是SetTimer (hwnd, ID_TIMER, 100, TimerProc) ,将触发计时器的设置代码放在TimerProc,比直接放在主窗口的WM_TIMER感觉更好一些,毕竟代码分离得更清晰。
5,关于设置环境句柄。本文中有用到:
第一种:CreateIC (TEXT ("DISPLAY"), NULL, NULL, NULL) ;第二种:CreateDC (TEXT ("DISPLAY"), NULL, NULL, NULL) ;
如果只需要获取一些关于设备环境的信息,而不需要在上面绘制任何东西,就采用createIC,否则用CreateDC。上面代码表示,获取当前整个屏幕的设备环境句柄。
整个文件编译链接后,形成可执行文件,大小只有36K,这个确实比java轻松多了。