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 }
对WM_PAINT消息的处理几乎总是从调用BeginPaint函数开始:hdc = BeginPaint(hwnd, &pt)
而以调用EndPaint函数结束:EndPaint(hwnd, &pt);
在这两个函数调用中,第一个参数均为程序的窗口句柄,而第二个参数均为指向一个类型为PAINTSTRUCT结构的指针。PAINTSTRUCT结构包含一些窗口过程用来对客户区进行绘制的信息。
BeginPaint 调用将使整个客户区有效,并返回一个“设备环境句柄”。
如何知道客户区呢?
该函数的第一个参数是程序的窗口句柄。第二个参数为指向类型为RECT的矩形结构的指针。该结构具有4个类型为LONG的字段,名称分别为left、top、right 和botom。GetclientRect函数将依据窗口尺寸来对这4个字段进行设置。其中,left和top字段总是会被赋为0,这样right和bottom字段就分别表示以像素为单位的客户区的宽度和高度。
BOOL GetClientRect( HWND hWnd, // 窗口句柄 LPRECT lpRect // 客户区坐标 );
也可以这样
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 }
前面讲到3中获取hdc的方式,第一种 BeginPaint & EndPaint,在EndPaint之后,原来的无效区就成为有效区,不在发送WM_PAINT重绘
而第二三种方法,在ReleaseDC后,并不能使原来的无效区成为有效区,一直是无效区。需要使用ValidateRect(hwnd, NULL);来使原来的无效区变成有效区,但是这种方法效率太低,是整个窗口的重回。可以先获取窗口无效区,在针对这个无效区进行重绘
BOOL ValidateRect( HWND hWnd, // 窗口的句柄 CONST RECT *lpRect // 指向RECT结构的指针 );
也就是代码顺序
GetUpdateRect
ValidateRect //让某一个矩形区域变得有效
如果只用第一种方法,就不必写上面2个函数了。
获取窗口无效区域: BOOL GetUpdateRect( HWND hWnd, LPRECT lpRect, BOOL bErase );
bErase :如果不想擦除背景,这个值就为false.
BOOL GetUpdateRect(
HWND hWnd,
LPRECT lpRect,
BOOL bErase
);
改变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 }
可以在Win10上选好颜色,然后初始化RGB
桌面->右键->个性化->颜色->自定义颜色
创建画刷函数
HBRUSH CreateSolidBrush( COLORREF color );
1 #include<Windows.h> 2 #include<tchar.h> 3 #define NUM 1000 4 5 LRESULT CALLBACK WindProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam); 6 7 int WinMain(HINSTANCE hInst, HINSTANCE tmp, LPSTR szCmd, int nShow) 8 { 9 WNDCLASS WndClass; 10 TCHAR* ClassName = TEXT("MyClass"); 11 HWND hwnd; 12 MSG msg; 13 HBRUSH hBrush; 14 hBrush = CreateSolidBrush(RGB(0xFF, 0, 0)); 15 16 WndClass.cbClsExtra = 0; 17 WndClass.cbWndExtra = 0; 18 WndClass.hbrBackground = hBrush; 19 WndClass.hCursor = LoadCursor(NULL, IDC_ARROW); 20 WndClass.hIcon = LoadIcon(NULL, IDI_APPLICATION); 21 WndClass.hInstance = hInst; 22 WndClass.lpfnWndProc = WindProc; 23 WndClass.lpszClassName = ClassName; 24 WndClass.lpszMenuName = NULL; 25 WndClass.style = CS_VREDRAW | CS_HREDRAW; 26 27 if (!RegisterClass(&WndClass)) 28 { 29 MessageBox(NULL, TEXT("Gegister Class Fail!!"), TEXT("error"), MB_OK); 30 return 0; 31 } 32 33 hwnd = CreateWindow(ClassName, TEXT("Hello"), WS_OVERLAPPEDWINDOW, 0, 0, 500, 300, NULL, NULL, hInst, NULL); 34 if (hwnd == NULL) 35 { 36 MessageBox(NULL, TEXT("Create Window Fail!!"), TEXT("error"), MB_OK); 37 return 0; 38 } 39 ShowWindow(hwnd, nShow); 40 UpdateWindow(hwnd); 41 42 while (GetMessage(&msg, NULL, 0, 0)) 43 { 44 TranslateMessage(&msg); 45 DispatchMessage(&msg); 46 } 47 48 return 0; 49 } 50 51 LRESULT CALLBACK WindProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) 52 { 53 HDC hdc; 54 PAINTSTRUCT pt; 55 TEXTMETRIC ts; 56 TCHAR* str = TEXT("hello"); 57 TCHAR* str1 = TEXT("World"); 58 switch (message) 59 { 60 case WM_DESTROY: 61 PostQuitMessage(0);//发送WM_QUIT消息 62 return 0; 63 case WM_PAINT: 64 hdc = BeginPaint(hwnd, &pt); 65 SetTextColor(hdc, RGB(0x0, 0xFF, 0)); 66 TextOut(hdc, 0, 0, str, _tcslen(str)); 67 GetTextMetrics(hdc, &ts); 68 TextOut(hdc, 0, ts.tmHeight, str1, _tcslen(str1)); 69 EndPaint(hwnd, &pt); 70 71 /* 第二种 72 hdc = GetDC(hwnd); 73 TextOut(hdc, 0, 0, str, _tcslen(str)); 74 ReleaseDC(hwnd, hdc); 75 ValidateRect(hwnd, NULL); 76 */ 77 78 /* 第三种 79 hdc = GetWindowDC(hwnd); 80 TextOut(hdc, 100, 100, str, _tcslen(str)); 81 ReleaseDC(hwnd, hdc); 82 ValidateRect(hwnd, NULL); 83 */ 84 85 return 0; 86 default: 87 break; 88 } 89 90 return DefWindowProc(hwnd, message, wParam, lParam); 91 }
改变字体大小
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 TEXTMETRIC ts; 50 TCHAR* str1 = TEXT("World"); 51 HDC hdc; 52 PAINTSTRUCT pt; 53 TCHAR* str = TEXT("hello"); 54 HFONT hFont; 55 hFont = CreateFont(50, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL); 56 switch (message) 57 { 58 case WM_DESTROY: 59 PostQuitMessage(0);//发送WM_QUIT消息 60 return 0; 61 case WM_PAINT: 62 hdc = BeginPaint(hwnd, &pt); 63 SelectObject(hdc, hFont); 64 SetTextColor(hdc, RGB(0x0, 0xFF, 0)); 65 TextOut(hdc, 0, 0, str, _tcslen(str)); 66 GetTextMetrics(hdc, &ts); 67 TextOut(hdc, 0, ts.tmHeight, str1, _tcslen(str1)); 68 EndPaint(hwnd, &pt); 69 70 /* 第二种 71 hdc = GetDC(hwnd); 72 TextOut(hdc, 0, 0, str, _tcslen(str)); 73 ReleaseDC(hwnd, hdc); 74 ValidateRect(hwnd, NULL); 75 */ 76 77 /* 第三种 78 hdc = GetWindowDC(hwnd); 79 TextOut(hdc, 100, 100, str, _tcslen(str)); 80 ReleaseDC(hwnd, hdc); 81 ValidateRect(hwnd, NULL); 82 */ 83 84 return 0; 85 default: 86 break; 87 } 88 89 return DefWindowProc(hwnd, message, wParam, lParam); 90 }
WM_PAINT消息的来源和处理方式
客户区:客户区是一块应用程序可以自由绘图并向用户传达可视输出的区域。
WM_PAINT何时产生?
当窗口的客户区的部分或全部“无效”且必须“更新”时,应用程序将得到此通知。这也就意味着窗口必须被“重绘”。
何种情况下客户区会变为无效?
①当窗口被首次创建时,整个客户区都是无效的,因为此时应用程序尚未在该窗口上绘制任何东西。第一条WM_PAINT消息(通常在应用程序调用WinMain中的UpdateWindow时出现)将指示窗口过程在窗口客户区进行绘制。
②在调整窗口的尺寸时,客户区也会变为无效。你可能还记得在前面的程序中,我们将窗口类结构的style字段设为了标记CS_HREDRAW和CSVREDRAW。这就指示Windows当窗口尺寸发生变化时,整个窗口都应宣布无效。在此之后,窗口过程将接收到一条WM_PAINT消息。
③如果先最小化窗口,然后再将窗口恢复到原先的尺寸,Windows并不会保存客户区的内容。在图形环境中,这种情况下需要保存的数据太多了。对此,Windows采取的策略是宣布窗口无效。窗口过程接收到WM_PAINT消息后,会自行恢复窗口的内容。
④在屏幕中拖动窗口导致窗口之间发生重叠时,Windows并不负责保存被另一个窗口覆盖的区域。当被覆盖的区域在后来不再被遮挡时,窗口被标记为无效。窗口过程会收到一条WM_PAINT消息,并对窗口的内容进行重绘。
例外情况?
鼠标滑过窗口,此时不发送WM_PAINT消息。这个重绘,由系统完成。
强制窗口重绘的函数:InvalidateRect和InvalidateRgn。
强制制定某一区域无效,需要重绘
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 );