06 Windows编程——设备句柄 和 WM_PAINT消息

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 }
View Code

对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 }
View Code

使用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 }
View Code

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 }
View Code

输出结果

获得字体高度的函数: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 }
View Code

前面讲到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 }
View Code

可以在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 }
View Code

改变字体大小

 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 }
View Code

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 );

 

原文地址:https://www.cnblogs.com/kelamoyujuzhen/p/9302055.html