windows程序在现实方式上属于图形方式,和文字方式的显示,有显著的不同。
什么是设备句柄,如何获取
使用统一的数据结构表示某一设备,这个结构就是设备句柄。
源码
1 #include<Windows.h> 2 3 LRESULT CALLBACK WindProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam); 4 5 int WinMain(HINSTANCE hInst, HINSTANCE tmp, LPSTR szCmd, int nShow) 6 { 7 WNDCLASS WndClass; 8 TCHAR* ClassName = TEXT("MyClass"); 9 HWND hwnd; 10 MSG msg; 11 12 WndClass.cbClsExtra = 0; 13 WndClass.cbWndExtra = 0; 14 WndClass.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); 15 WndClass.hCursor = LoadCursor(NULL, IDC_ARROW); 16 WndClass.hIcon = LoadIcon(NULL, IDI_APPLICATION); 17 WndClass.hInstance = hInst; 18 WndClass.lpfnWndProc = WindProc; 19 WndClass.lpszClassName = ClassName; 20 WndClass.lpszMenuName = NULL; 21 WndClass.style = CS_VREDRAW | CS_HREDRAW; 22 23 if (!RegisterClass(&WndClass)) 24 { 25 MessageBox(NULL, TEXT("Gegister Class Fail!!"), TEXT("error"), MB_OK); 26 return 0; 27 } 28 29 hwnd = CreateWindow(ClassName, TEXT("Hello"), WS_OVERLAPPEDWINDOW, 0, 0, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInst, NULL); 30 if (hwnd == NULL) 31 { 32 MessageBox(NULL, TEXT("Create Window Fail!!"), TEXT("error"), MB_OK); 33 return 0; 34 } 35 ShowWindow(hwnd, nShow); 36 UpdateWindow(hwnd); 37 38 while (GetMessage(&msg,NULL,0,0)) 39 { 40 TranslateMessage(&msg); 41 DispatchMessage(&msg); 42 } 43 44 return 0; 45 } 46 47 LRESULT CALLBACK WindProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) 48 { 49 HDC hdc; 50 PAINTSTRUCT pt; 51 TCHAR* str = TEXT("hello"); 52 switch (message) 53 { 54 case WM_DESTROY: 55 PostQuitMessage(0);//发送WM_QUIT消息 56 return 0; 57 case WM_PAINT: 58 hdc = BeginPaint(hwnd, &pt); 59 TextOut(hdc, 0, 0, str, _tcslen(str)); 60 EndPaint(hwnd, &pt); 61 return 0; 62 default: 63 break; 64 } 65 66 return DefWindowProc(hwnd, message, wParam, lParam); 67 }
也可以这样
1 #include<Windows.h> 2 3 LRESULT CALLBACK WindProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam); 4 5 int WinMain(HINSTANCE hInst, HINSTANCE tmp, LPSTR szCmd, int nShow) 6 { 7 WNDCLASS WndClass; 8 TCHAR* ClassName = TEXT("MyClass"); 9 HWND hwnd; 10 MSG msg; 11 12 WndClass.cbClsExtra = 0; 13 WndClass.cbWndExtra = 0; 14 WndClass.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); 15 WndClass.hCursor = LoadCursor(NULL, IDC_ARROW); 16 WndClass.hIcon = LoadIcon(NULL, IDI_APPLICATION); 17 WndClass.hInstance = hInst; 18 WndClass.lpfnWndProc = WindProc; 19 WndClass.lpszClassName = ClassName; 20 WndClass.lpszMenuName = NULL; 21 WndClass.style = CS_VREDRAW | CS_HREDRAW; 22 23 if (!RegisterClass(&WndClass)) 24 { 25 MessageBox(NULL, TEXT("Gegister Class Fail!!"), TEXT("error"), MB_OK); 26 return 0; 27 } 28 29 hwnd = CreateWindow(ClassName, TEXT("Hello"), WS_OVERLAPPEDWINDOW, 0, 0, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInst, NULL); 30 if (hwnd == NULL) 31 { 32 MessageBox(NULL, TEXT("Create Window Fail!!"), TEXT("error"), MB_OK); 33 return 0; 34 } 35 ShowWindow(hwnd, nShow); 36 UpdateWindow(hwnd); 37 38 while (GetMessage(&msg,NULL,0,0)) 39 { 40 TranslateMessage(&msg); 41 DispatchMessage(&msg); 42 } 43 44 return 0; 45 } 46 47 LRESULT CALLBACK WindProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) 48 { 49 HDC hdc; 50 PAINTSTRUCT pt; 51 TCHAR* str = TEXT("hello"); 52 switch (message) 53 { 54 case WM_DESTROY: 55 PostQuitMessage(0);//发送WM_QUIT消息 56 return 0; 57 case WM_PAINT: 58 /*hdc = BeginPaint(hwnd, &pt); 59 TextOut(hdc, 0, 0, str, _tcslen(str)); 60 EndPaint(hwnd, &pt);*/ 61 hdc = GetDC(hwnd); 62 TextOut(hdc, 0, 0, str, _tcslen(str)); 63 ReleaseDC(hwnd, hdc); 64 ValidateRect(hwnd, NULL); 65 return 0; 66 default: 67 break; 68 } 69 70 return DefWindowProc(hwnd, message, wParam, lParam); 71 }
使用EndPaint,直接就会使pt指向的区域变成有效区域。而ReleaseDC不会,WM_PAINT会一直存在,需要手动调用函数ValidateRect释放无效区。使无效客户区有效。
第三种做法
1 #include<Windows.h> 2 3 LRESULT CALLBACK WindProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam); 4 5 int WinMain(HINSTANCE hInst, HINSTANCE tmp, LPSTR szCmd, int nShow) 6 { 7 WNDCLASS WndClass; 8 TCHAR* ClassName = TEXT("MyClass"); 9 HWND hwnd; 10 MSG msg; 11 12 WndClass.cbClsExtra = 0; 13 WndClass.cbWndExtra = 0; 14 WndClass.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); 15 WndClass.hCursor = LoadCursor(NULL, IDC_ARROW); 16 WndClass.hIcon = LoadIcon(NULL, IDI_APPLICATION); 17 WndClass.hInstance = hInst; 18 WndClass.lpfnWndProc = WindProc; 19 WndClass.lpszClassName = ClassName; 20 WndClass.lpszMenuName = NULL; 21 WndClass.style = CS_VREDRAW | CS_HREDRAW; 22 23 if (!RegisterClass(&WndClass)) 24 { 25 MessageBox(NULL, TEXT("Gegister Class Fail!!"), TEXT("error"), MB_OK); 26 return 0; 27 } 28 29 hwnd = CreateWindow(ClassName, TEXT("Hello"), WS_OVERLAPPEDWINDOW, 0, 0, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInst, NULL); 30 if (hwnd == NULL) 31 { 32 MessageBox(NULL, TEXT("Create Window Fail!!"), TEXT("error"), MB_OK); 33 return 0; 34 } 35 ShowWindow(hwnd, nShow); 36 UpdateWindow(hwnd); 37 38 while (GetMessage(&msg,NULL,0,0)) 39 { 40 TranslateMessage(&msg); 41 DispatchMessage(&msg); 42 } 43 44 return 0; 45 } 46 47 LRESULT CALLBACK WindProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) 48 { 49 HDC hdc; 50 PAINTSTRUCT pt; 51 TCHAR* str = TEXT("hello"); 52 switch (message) 53 { 54 case WM_DESTROY: 55 PostQuitMessage(0);//发送WM_QUIT消息 56 return 0; 57 case WM_PAINT: 58 /* 第一种 59 hdc = BeginPaint(hwnd, &pt); 60 TextOut(hdc, 0, 0, str, _tcslen(str)); 61 EndPaint(hwnd, &pt); 62 */ 63 64 /* 第二种 65 hdc = GetDC(hwnd); 66 TextOut(hdc, 0, 0, str, _tcslen(str)); 67 ReleaseDC(hwnd, hdc); 68 ValidateRect(hwnd, NULL); 69 */ 70 71 hdc = GetWindowDC(hwnd); 72 TextOut(hdc, 100, 100, str, _tcslen(str)); 73 ReleaseDC(hwnd, hdc); 74 ValidateRect(hwnd, NULL); 75 return 0; 76 default: 77 break; 78 } 79 80 return DefWindowProc(hwnd, message, wParam, lParam); 81 }
GetWindowDC、ReleaseDC操作窗口句柄,在绘制时不是以有效区作为参考,而是以整个窗口做参考,所以需要在TextOut里面调整输出文字的位置
代码里TextOut只在pt这个无效区显示输出文字。
HDC BeginPaint( HWND hWnd, LPPAINTSTRUCT lpPaint );
hWnd:窗口句柄
lpPaint:包含了用来重画客户区的程序信息
typedef struct tagPAINTSTRUCT {
HDC hdc; //用来在客户去画图的设备表
BOOL fErase; //客户背景区是否需要重绘(stru=是)
RECT rcPaint; //无效客户区
BOOL fRestore; //保留
BOOL fIncUpdate;//保留
BYTE rgbReserved[16];//保留
} PAINTSTRUCT;
前面3段代码主要围绕设备句柄处理WM_PAINT消息。
如果使用TextOut在输出一段文字,调整不好位置的话容易遮挡之前输出的文字。代码如下
1 #include<Windows.h> 2 3 LRESULT CALLBACK WindProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam); 4 5 int WinMain(HINSTANCE hInst, HINSTANCE tmp, LPSTR szCmd, int nShow) 6 { 7 WNDCLASS WndClass; 8 TCHAR* ClassName = TEXT("MyClass"); 9 HWND hwnd; 10 MSG msg; 11 12 WndClass.cbClsExtra = 0; 13 WndClass.cbWndExtra = 0; 14 WndClass.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); 15 WndClass.hCursor = LoadCursor(NULL, IDC_ARROW); 16 WndClass.hIcon = LoadIcon(NULL, IDI_APPLICATION); 17 WndClass.hInstance = hInst; 18 WndClass.lpfnWndProc = WindProc; 19 WndClass.lpszClassName = ClassName; 20 WndClass.lpszMenuName = NULL; 21 WndClass.style = CS_VREDRAW | CS_HREDRAW; 22 23 if (!RegisterClass(&WndClass)) 24 { 25 MessageBox(NULL, TEXT("Gegister Class Fail!!"), TEXT("error"), MB_OK); 26 return 0; 27 } 28 29 hwnd = CreateWindow(ClassName, TEXT("Hello"), WS_OVERLAPPEDWINDOW, 0, 0, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInst, NULL); 30 if (hwnd == NULL) 31 { 32 MessageBox(NULL, TEXT("Create Window Fail!!"), TEXT("error"), MB_OK); 33 return 0; 34 } 35 ShowWindow(hwnd, nShow); 36 UpdateWindow(hwnd); 37 38 while (GetMessage(&msg,NULL,0,0)) 39 { 40 TranslateMessage(&msg); 41 DispatchMessage(&msg); 42 } 43 44 return 0; 45 } 46 47 LRESULT CALLBACK WindProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) 48 { 49 HDC hdc; 50 PAINTSTRUCT pt; 51 TCHAR* str = TEXT("hello"); 52 TCHAR* str1 = TEXT("World"); 53 switch (message) 54 { 55 case WM_DESTROY: 56 PostQuitMessage(0);//发送WM_QUIT消息 57 return 0; 58 case WM_PAINT: 59 hdc = BeginPaint(hwnd, &pt); 60 TextOut(hdc, 0, 0, str, _tcslen(str)); 61 TextOut(hdc, 5, 10, str1, _tcslen(str1)); 62 EndPaint(hwnd, &pt); 63 64 /* 第二种 65 hdc = GetDC(hwnd); 66 TextOut(hdc, 0, 0, str, _tcslen(str)); 67 ReleaseDC(hwnd, hdc); 68 ValidateRect(hwnd, NULL); 69 */ 70 71 /* 第三种 72 hdc = GetWindowDC(hwnd); 73 TextOut(hdc, 100, 100, str, _tcslen(str)); 74 ReleaseDC(hwnd, hdc); 75 ValidateRect(hwnd, NULL); 76 */ 77 78 return 0; 79 default: 80 break; 81 } 82 83 return DefWindowProc(hwnd, message, wParam, lParam); 84 }
输出结果
获得字体高度的函数:BOOL GetTextMetrics( HDC hdc, LPTEXTMETRIC lptm );
1 #include<Windows.h> 2 3 LRESULT CALLBACK WindProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam); 4 5 int WinMain(HINSTANCE hInst, HINSTANCE tmp, LPSTR szCmd, int nShow) 6 { 7 WNDCLASS WndClass; 8 TCHAR* ClassName = TEXT("MyClass"); 9 HWND hwnd; 10 MSG msg; 11 12 WndClass.cbClsExtra = 0; 13 WndClass.cbWndExtra = 0; 14 WndClass.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); 15 WndClass.hCursor = LoadCursor(NULL, IDC_ARROW); 16 WndClass.hIcon = LoadIcon(NULL, IDI_APPLICATION); 17 WndClass.hInstance = hInst; 18 WndClass.lpfnWndProc = WindProc; 19 WndClass.lpszClassName = ClassName; 20 WndClass.lpszMenuName = NULL; 21 WndClass.style = CS_VREDRAW | CS_HREDRAW; 22 23 if (!RegisterClass(&WndClass)) 24 { 25 MessageBox(NULL, TEXT("Gegister Class Fail!!"), TEXT("error"), MB_OK); 26 return 0; 27 } 28 29 hwnd = CreateWindow(ClassName, TEXT("Hello"), WS_OVERLAPPEDWINDOW, 0, 0, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInst, NULL); 30 if (hwnd == NULL) 31 { 32 MessageBox(NULL, TEXT("Create Window Fail!!"), TEXT("error"), MB_OK); 33 return 0; 34 } 35 ShowWindow(hwnd, nShow); 36 UpdateWindow(hwnd); 37 38 while (GetMessage(&msg,NULL,0,0)) 39 { 40 TranslateMessage(&msg); 41 DispatchMessage(&msg); 42 } 43 44 return 0; 45 } 46 47 LRESULT CALLBACK WindProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) 48 { 49 HDC hdc; 50 PAINTSTRUCT pt; 51 TEXTMETRIC ts; 52 TCHAR* str = TEXT("hello"); 53 TCHAR* str1 = TEXT("World"); 54 switch (message) 55 { 56 case WM_DESTROY: 57 PostQuitMessage(0);//发送WM_QUIT消息 58 return 0; 59 case WM_PAINT: 60 hdc = BeginPaint(hwnd, &pt); 61 TextOut(hdc, 0, 0, str, _tcslen(str)); 62 GetTextMetrics(hdc, &ts); 63 TextOut(hdc, 0, ts.tmHeight, str1, _tcslen(str1)); 64 EndPaint(hwnd, &pt); 65 66 /* 第二种 67 hdc = GetDC(hwnd); 68 TextOut(hdc, 0, 0, str, _tcslen(str)); 69 ReleaseDC(hwnd, hdc); 70 ValidateRect(hwnd, NULL); 71 */ 72 73 /* 第三种 74 hdc = GetWindowDC(hwnd); 75 TextOut(hdc, 100, 100, str, _tcslen(str)); 76 ReleaseDC(hwnd, hdc); 77 ValidateRect(hwnd, NULL); 78 */ 79 80 return 0; 81 default: 82 break; 83 } 84 85 return DefWindowProc(hwnd, message, wParam, lParam); 86 }
获取窗口无效区域: BOOL GetUpdateRect( HWND hWnd, LPRECT lpRect, BOOL bErase );
bErase :如果不想擦除背景,这个值就为false.
改变hdc设备句柄中字体颜色
COLORREF SetTextColor( HDC hdc, COLORREF color );
1 #include<Windows.h> 2 3 LRESULT CALLBACK WindProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam); 4 5 int WinMain(HINSTANCE hInst, HINSTANCE tmp, LPSTR szCmd, int nShow) 6 { 7 WNDCLASS WndClass; 8 TCHAR* ClassName = TEXT("MyClass"); 9 HWND hwnd; 10 MSG msg; 11 12 WndClass.cbClsExtra = 0; 13 WndClass.cbWndExtra = 0; 14 WndClass.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); 15 WndClass.hCursor = LoadCursor(NULL, IDC_ARROW); 16 WndClass.hIcon = LoadIcon(NULL, IDI_APPLICATION); 17 WndClass.hInstance = hInst; 18 WndClass.lpfnWndProc = WindProc; 19 WndClass.lpszClassName = ClassName; 20 WndClass.lpszMenuName = NULL; 21 WndClass.style = CS_VREDRAW | CS_HREDRAW; 22 23 if (!RegisterClass(&WndClass)) 24 { 25 MessageBox(NULL, TEXT("Gegister Class Fail!!"), TEXT("error"), MB_OK); 26 return 0; 27 } 28 29 hwnd = CreateWindow(ClassName, TEXT("Hello"), WS_OVERLAPPEDWINDOW, 0, 0, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInst, NULL); 30 if (hwnd == NULL) 31 { 32 MessageBox(NULL, TEXT("Create Window Fail!!"), TEXT("error"), MB_OK); 33 return 0; 34 } 35 ShowWindow(hwnd, nShow); 36 UpdateWindow(hwnd); 37 38 while (GetMessage(&msg,NULL,0,0)) 39 { 40 TranslateMessage(&msg); 41 DispatchMessage(&msg); 42 } 43 44 return 0; 45 } 46 47 LRESULT CALLBACK WindProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) 48 { 49 HDC hdc; 50 PAINTSTRUCT pt; 51 TEXTMETRIC ts; 52 TCHAR* str = TEXT("hello"); 53 TCHAR* str1 = TEXT("World"); 54 switch (message) 55 { 56 case WM_DESTROY: 57 PostQuitMessage(0);//发送WM_QUIT消息 58 return 0; 59 case WM_PAINT: 60 hdc = BeginPaint(hwnd, &pt); 61 SetTextColor(hdc, RGB(0x0, 0xFF, 0)); 62 TextOut(hdc, 0, 0, str, _tcslen(str)); 63 GetTextMetrics(hdc, &ts); 64 TextOut(hdc, 0, ts.tmHeight, str1, _tcslen(str1)); 65 EndPaint(hwnd, &pt); 66 67 /* 第二种 68 hdc = GetDC(hwnd); 69 TextOut(hdc, 0, 0, str, _tcslen(str)); 70 ReleaseDC(hwnd, hdc); 71 ValidateRect(hwnd, NULL); 72 */ 73 74 /* 第三种 75 hdc = GetWindowDC(hwnd); 76 TextOut(hdc, 100, 100, str, _tcslen(str)); 77 ReleaseDC(hwnd, hdc); 78 ValidateRect(hwnd, NULL); 79 */ 80 81 return 0; 82 default: 83 break; 84 } 85 86 return DefWindowProc(hwnd, message, wParam, lParam); 87 }
WM_PAINT消息的来源和处理方式
WM_PAINT系统根据用户动产生。
你自己认为,什么时候窗口应该重绘,那么此种情况下,Windows必发送WML_PAINT消息。
例如滚动条移动,窗口被覆盖区域重新显示灯
强制窗口重绘的函数:InvalidateRect和InvalidateRgn。
但也有例外:
鼠标滑过窗口,此时不发送WM_PAINT消息。这个重绘,由系统完成。
强制制定某一区域无效,需要重绘
BOOL InvalidateRect(HWND hWnd, CONST RECT *lpRect, BOOL bErase);
hWnd:想让哪个窗口的客户区无效
lpRect:客户无效区域
bErase:窗口背景是否需要重新绘制,如果是TRUE,那么窗口背景被擦去,需要重新绘制。
BOOL InvalidateRgn( HWND hWnd, HRGN hRgn, BOOL bErase );
hWnd:想让哪个窗口的客户区无效
hRgn:客户无效区域
bErase:窗口背景是否需要重新绘制,如果是TRUE,那么窗口背景被擦去,需要重新绘制。
HRGN和RECT之间的相互转换:CreateRectRgnIndirect
HRGN CreateRectRgnIndirect( CONST RECT *lprect );
什么是客户区的有效区,什么是客户区的无效区
获取字体的高度