[toc]

使用GDI在VM_PAINT消息中画图

1.在窗口程序中画一个像素点

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
#include <windows.h>

// 窗口过程函数
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
switch (uMsg) {
case WM_PAINT: {
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hwnd, &ps);
// 设置像素颜色为红色
SetPixel(hdc, 40, 40, RGB(255, 0, 0));
EndPaint(hwnd, &ps);
} break;

case WM_DESTROY:
PostQuitMessage(0);
return 0;

default:
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
return 0;
}

// WinMain 函数
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd) {
const char CLASS_NAME[] = "Sample Window Class";

WNDCLASS wc = {0 };
wc.lpfnWndProc = WindowProc;
wc.hInstance = hInstance;
wc.lpszClassName = CLASS_NAME;

RegisterClass(&wc);

HWND hwnd = CreateWindowEx(
0, CLASS_NAME, "SetPixel Example",
WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 400, 400,
NULL, NULL, hInstance, NULL
);

ShowWindow(hwnd, nShowCmd);

// 消息循环
MSG msg;
while (GetMessage(&msg, NULL, 0, 0)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}

return 0;
}

2.在窗口程序中通过像素点画条线

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
#include <windows.h>

// 窗口过程函数
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
switch (uMsg) {
case WM_PAINT: {
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hwnd, &ps);

// 使用 SetPixel 绘制像素点

for (int y = 50; y < 200; y++) {
// 设置像素颜色为红色
SetPixel(hdc, 50, y, RGB(255, 0, 0));
}


EndPaint(hwnd, &ps);
} break;

case WM_DESTROY:
PostQuitMessage(0);
return 0;

default:
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
return 0;
}

// WinMain 函数
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd) {
const char CLASS_NAME[] = "Sample Window Class";

WNDCLASS wc = { 0 };
wc.lpfnWndProc = WindowProc;
wc.hInstance = hInstance;
wc.lpszClassName = CLASS_NAME;

RegisterClass(&wc);

HWND hwnd = CreateWindowEx(
0, CLASS_NAME, "SetPixel Example",
WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 400, 400,
NULL, NULL, hInstance, NULL
);

ShowWindow(hwnd, nShowCmd);

// 消息循环
MSG msg;
while (GetMessage(&msg, NULL, 0, 0)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}

return 0;
}

3.在窗口程序中通过像素点画正方形

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
#include <windows.h>

// 窗口过程函数
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
switch (uMsg) {
case WM_PAINT: {
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hwnd, &ps);

// 使用 SetPixel 绘制正方形
for (int x = 50; x < 200; x++) {
for (int y = 50; y < 200; y++) {
// 设置像素颜色为红色
SetPixel(hdc, x, y, RGB(255, 0, 0));
}
}

EndPaint(hwnd, &ps);
} break;

case WM_DESTROY:
PostQuitMessage(0);
return 0;

default:
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
return 0;
}

// WinMain 函数
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd) {
const char CLASS_NAME[] = "Sample Window Class";

WNDCLASS wc = {0 };
wc.lpfnWndProc = WindowProc;
wc.hInstance = hInstance;
wc.lpszClassName = CLASS_NAME;

RegisterClass(&wc);

HWND hwnd = CreateWindowEx(
0, CLASS_NAME, "SetPixel Example",
WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 400, 400,
NULL, NULL, hInstance, NULL
);

ShowWindow(hwnd, nShowCmd);

// 消息循环
MSG msg;
while (GetMessage(&msg, NULL, 0, 0)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}

return 0;
}

4. 在窗口程序中通过画笔画直线

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
#include <windows.h>

// 用于注册的窗口类名
const char g_szClassName[] = "myWindowClass";

void Paint(HWND hwnd)
{
// paint struct 绘图结构体,存储目标窗口可以绘图的客户端区域(client area)
PAINTSTRUCT ps;
HDC hdc; // DC(可画图的内存对象) 的句柄
HPEN hpen; // 画笔

// 通过窗口句柄获取该窗口的 DC
hdc = BeginPaint(hwnd, &ps);
// 创建画笔
hpen = CreatePen(PS_SOLID, 1, RGB(255, 0, 0));
// DC 选择画笔
SelectObject(hdc, hpen);
// (画笔)从初始点移动到 50,50
MoveToEx(hdc, 50, 50, NULL);
// (画笔)从初始点画线到 100,100
LineTo(hdc, 150, 100);

EndPaint(hwnd, &ps);
}
/*
* 第四步,窗口过程
*/
LRESULT CALLBACK MyWindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch (msg)
{
// 窗口绘制消息
case WM_PAINT:
Paint(hwnd); // 调用我们的 GDI 绘制函数
break;
// 窗口关闭消息
case WM_CLOSE:
DestroyWindow(hwnd);
break;
// 窗口销毁消息
case WM_DESTROY:
PostQuitMessage(0); // 发送离开消息给系统
break;
// 其他消息
default:
// pass 给系统,咱不管
return DefWindowProc(hwnd, msg, wParam, lParam);
}
return 0;
}

/*
* 第一步,注册窗口类
*/
void RegisterMyWindow(HINSTANCE hInstance)
{
WNDCLASSEX wc;

// 1)配置窗口属性
wc.cbSize = sizeof(WNDCLASSEX);
wc.style = 0;
wc.lpfnWndProc = MyWindowProc; // 设置第四步的窗口过程回调函数
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
wc.lpszMenuName = NULL;
wc.lpszClassName = g_szClassName;
wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION);

// 2)注册
if (!RegisterClassEx(&wc))
{
MessageBox(NULL, TEXT("窗口注册失败!"), TEXT("错误"), MB_ICONEXCLAMATION | MB_OK);
exit(0); // 进程退出
}
}

/*
* 第二步,创建窗口
*/
HWND CreateMyWindow(HINSTANCE hInstance, int nCmdShow)
{
HWND hwnd;
hwnd = CreateWindowEx(
WS_EX_CLIENTEDGE,
g_szClassName,
TEXT("我的窗口名称"),
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT, 400, 300, // 出现坐标 x,y 默认分配 窗口宽 400 高 300
NULL, NULL, hInstance, NULL);

if (hwnd == NULL)
{
MessageBox(NULL, TEXT("窗口创建失败!"), TEXT("错误"), MB_ICONEXCLAMATION | MB_OK);
exit(0); // 进程退出
}

// 显示窗口
ShowWindow(hwnd, nCmdShow);
UpdateWindow(hwnd);

return hwnd;
}

/*
* 主函数
*/
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpCmdLine, int nCmdShow)
{
HWND hwnd;
MSG Msg;

// 第一步,注册窗口类
RegisterMyWindow(hInstance);
// 第二步:创建窗口
hwnd = CreateMyWindow(hInstance, nCmdShow);
// 第三步:消息循环
while (GetMessage(&Msg, NULL, 0, 0) > 0)
{
TranslateMessage(&Msg);
DispatchMessage(&Msg);
}
return Msg.wParam;
}

5.使用画刷画圆形与矩形

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
#include <windows.h>

// 用于注册的窗口类名
const char g_szClassName[] = "myWindowClass";

void Paint(HWND hwnd)
{
// paint struct 绘图结构体,存储目标窗口可以绘图的客户端区域(client area)
PAINTSTRUCT ps;
HDC hdc; // DC(可画图的内存对象) 的句柄

// 通过窗口句柄获取该窗口的 DC
hdc = BeginPaint(hwnd, &ps);
//1.自制画刷
HBRUSH hBrush1 = CreateSolidBrush(RGB(30, 30, 30));
HBRUSH hBrush2 = CreateSolidBrush(RGB(20, 210, 20));

//2.画刷给画家
SelectObject(hdc, hBrush1);
Rectangle(hdc, 10, 10, 100, 100);

SelectObject(hdc, hBrush2);
Ellipse(hdc, 200, 200, 400, 400);

EndPaint(hwnd, &ps);
}
/*
* 第四步,窗口过程
*/
LRESULT CALLBACK MyWindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch (msg)
{
// 窗口绘制消息
case WM_PAINT:
Paint(hwnd); // 调用我们的 GDI 绘制函数
break;
// 窗口关闭消息
case WM_CLOSE:
DestroyWindow(hwnd);
break;
// 窗口销毁消息
case WM_DESTROY:
PostQuitMessage(0); // 发送离开消息给系统
break;
// 其他消息
default:
// pass 给系统,咱不管
return DefWindowProc(hwnd, msg, wParam, lParam);
}
return 0;
}

/*
* 第一步,注册窗口类
*/
void RegisterMyWindow(HINSTANCE hInstance)
{
WNDCLASSEX wc;

// 1)配置窗口属性
wc.cbSize = sizeof(WNDCLASSEX);
wc.style = 0;
wc.lpfnWndProc = MyWindowProc; // 设置第四步的窗口过程回调函数
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
wc.lpszMenuName = NULL;
wc.lpszClassName = g_szClassName;
wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION);

// 2)注册
if (!RegisterClassEx(&wc))
{
MessageBox(NULL, TEXT("窗口注册失败!"), TEXT("错误"), MB_ICONEXCLAMATION | MB_OK);
exit(0); // 进程退出
}
}

/*
* 第二步,创建窗口
*/
HWND CreateMyWindow(HINSTANCE hInstance, int nCmdShow)
{
HWND hwnd;
hwnd = CreateWindowEx(
WS_EX_CLIENTEDGE,
g_szClassName,
TEXT("我的窗口名称"),
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT, 800, 600, // 出现坐标 x,y 默认分配 窗口宽 400 高 300
NULL, NULL, hInstance, NULL);

if (hwnd == NULL)
{
MessageBox(NULL, TEXT("窗口创建失败!"), TEXT("错误"), MB_ICONEXCLAMATION | MB_OK);
exit(0); // 进程退出
}

// 显示窗口
ShowWindow(hwnd, nCmdShow);
UpdateWindow(hwnd);

return hwnd;
}

/*
* 主函数
*/
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpCmdLine, int nCmdShow)
{
HWND hwnd;
MSG Msg;

// 第一步,注册窗口类
RegisterMyWindow(hInstance);
// 第二步:创建窗口
hwnd = CreateMyWindow(hInstance, nCmdShow);
// 第三步:消息循环
while (GetMessage(&Msg, NULL, 0, 0) > 0)
{
TranslateMessage(&Msg);
DispatchMessage(&Msg);
}
return Msg.wParam;
}

使用GetHDC在任意地方画图

1.在窗口程序上画一个三角形

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
#include <windows.h>

// 用于注册的窗口类名
const char g_szClassName[] = "myWindowClass";

void Paint(HWND hwnd)
{
HDC hdc=GetDC(hwnd);
//绘制像素点
for (int i = 1; i <= 100; i++) {
SetPixel(hdc, 100 + i, 100, RGB(255, 0, 0));
}
POINT oldPos;
MoveToEx(hdc, 200, 100, NULL);
LineTo(hdc, 300, 300);
//保存(300,300)的位置,并且移动到(100,100)的位置
MoveToEx(hdc, 100, 100, &oldPos);
//画线到(300,300)的位置
LineTo(hdc, oldPos.x, oldPos.y);
//形成一个三角形
ReleaseDC(hwnd, hdc);
}
/*
* 第四步,窗口过程
*/
LRESULT CALLBACK MyWindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch (msg)
{
// 窗口绘制消息
case WM_PAINT:
Paint(hwnd); // 调用我们的 GDI 绘制函数
break;
// 窗口关闭消息
case WM_CLOSE:
DestroyWindow(hwnd);
break;
// 窗口销毁消息
case WM_DESTROY:
PostQuitMessage(0); // 发送离开消息给系统
break;
// 其他消息
default:
// pass 给系统,咱不管
return DefWindowProc(hwnd, msg, wParam, lParam);
}
return 0;
}

/*
* 第一步,注册窗口类
*/
void RegisterMyWindow(HINSTANCE hInstance)
{
WNDCLASSEX wc;

// 1)配置窗口属性
wc.cbSize = sizeof(WNDCLASSEX);
wc.style = 0;
wc.lpfnWndProc = MyWindowProc; // 设置第四步的窗口过程回调函数
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
wc.lpszMenuName = NULL;
wc.lpszClassName = g_szClassName;
wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION);

// 2)注册
if (!RegisterClassEx(&wc))
{
MessageBox(NULL, TEXT("窗口注册失败!"), TEXT("错误"), MB_ICONEXCLAMATION | MB_OK);
exit(0); // 进程退出
}
}

/*
* 第二步,创建窗口
*/
HWND CreateMyWindow(HINSTANCE hInstance, int nCmdShow)
{
HWND hwnd;
hwnd = CreateWindowEx(
WS_EX_CLIENTEDGE,
g_szClassName,
TEXT("我的窗口名称"),
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT, 800, 600, // 出现坐标 x,y 默认分配 窗口宽 400 高 300
NULL, NULL, hInstance, NULL);

if (hwnd == NULL)
{
MessageBox(NULL, TEXT("窗口创建失败!"), TEXT("错误"), MB_ICONEXCLAMATION | MB_OK);
exit(0); // 进程退出
}

// 显示窗口
ShowWindow(hwnd, nCmdShow);
UpdateWindow(hwnd);

return hwnd;
}

/*
* 主函数
*/
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpCmdLine, int nCmdShow)
{
HWND hwnd;
MSG Msg;

// 第一步,注册窗口类
RegisterMyWindow(hInstance);
// 第二步:创建窗口
hwnd = CreateMyWindow(hInstance, nCmdShow);
// 第三步:消息循环
while (GetMessage(&Msg, NULL, 0, 0) > 0)
{
TranslateMessage(&Msg);
DispatchMessage(&Msg);
}
return Msg.wParam;
}

2.在桌面上画一个三角形

将窗口句柄设为0就可以在桌面上绘制图形

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
#include <windows.h>

// 用于注册的窗口类名
const char g_szClassName[] = "myWindowClass";

void Paint(HWND hwnd)
{
HDC hdc = GetDC(0);
//绘制像素点
for (int i = 1; i <= 100; i++) {
SetPixel(hdc, 100 + i, 100, RGB(255, 0, 0));
}
POINT oldPos;
MoveToEx(hdc, 200, 100, NULL);
LineTo(hdc, 300, 300);
//保存(300,300)的位置,并且移动到(100,100)的位置
MoveToEx(hdc, 100, 100, &oldPos);
//画线到(300,300)的位置
LineTo(hdc, oldPos.x, oldPos.y);
//形成一个三角形
ReleaseDC(hwnd, hdc);
}
/*
* 第四步,窗口过程
*/
LRESULT CALLBACK MyWindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch (msg)
{
// 窗口绘制消息
case WM_PAINT:
Paint(hwnd); // 调用我们的 GDI 绘制函数
break;
// 窗口关闭消息
case WM_CLOSE:
DestroyWindow(hwnd);
break;
// 窗口销毁消息
case WM_DESTROY:
PostQuitMessage(0); // 发送离开消息给系统
break;
// 其他消息
default:
// pass 给系统,咱不管
return DefWindowProc(hwnd, msg, wParam, lParam);
}
return 0;
}

/*
* 第一步,注册窗口类
*/
void RegisterMyWindow(HINSTANCE hInstance)
{
WNDCLASSEX wc;

// 1)配置窗口属性
wc.cbSize = sizeof(WNDCLASSEX);
wc.style = 0;
wc.lpfnWndProc = MyWindowProc; // 设置第四步的窗口过程回调函数
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
wc.lpszMenuName = NULL;
wc.lpszClassName = g_szClassName;
wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION);

// 2)注册
if (!RegisterClassEx(&wc))
{
MessageBox(NULL, TEXT("窗口注册失败!"), TEXT("错误"), MB_ICONEXCLAMATION | MB_OK);
exit(0); // 进程退出
}
}

/*
* 第二步,创建窗口
*/
HWND CreateMyWindow(HINSTANCE hInstance, int nCmdShow)
{
HWND hwnd;
hwnd = CreateWindowEx(
WS_EX_CLIENTEDGE,
g_szClassName,
TEXT("我的窗口名称"),
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT, 800, 600, // 出现坐标 x,y 默认分配 窗口宽 400 高 300
NULL, NULL, hInstance, NULL);

if (hwnd == NULL)
{
MessageBox(NULL, TEXT("窗口创建失败!"), TEXT("错误"), MB_ICONEXCLAMATION | MB_OK);
exit(0); // 进程退出
}

// 显示窗口
ShowWindow(hwnd, nCmdShow);
UpdateWindow(hwnd);

return hwnd;
}

/*
* 主函数
*/
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpCmdLine, int nCmdShow)
{
HWND hwnd;
MSG Msg;

// 第一步,注册窗口类
RegisterMyWindow(hInstance);
// 第二步:创建窗口
hwnd = CreateMyWindow(hInstance, nCmdShow);
// 第三步:消息循环
while (GetMessage(&Msg, NULL, 0, 0) > 0)
{
TranslateMessage(&Msg);
DispatchMessage(&Msg);
}
return Msg.wParam;
}

3.在其他窗口程序上画一个三角形

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
#include <windows.h>

// 用于注册的窗口类名
const char g_szClassName[] = "myWindowClass";

void Paint()
{
HWND hwnd = FindWindowW(L"Notepad", NULL);
HDC hdc = GetDC(hwnd);
//绘制像素点
for (int i = 1; i <= 100; i++) {
SetPixel(hdc, 100 + i, 100, RGB(255, 0, 0));
}
POINT oldPos;
MoveToEx(hdc, 200, 100, NULL);
LineTo(hdc, 300, 300);
//保存(300,300)的位置,并且移动到(100,100)的位置
MoveToEx(hdc, 100, 100, &oldPos);
//画线到(300,300)的位置
LineTo(hdc, oldPos.x, oldPos.y);
//形成一个三角形
ReleaseDC(hwnd, hdc);
}
/*
* 第四步,窗口过程
*/
LRESULT CALLBACK MyWindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch (msg)
{
// 窗口绘制消息
case WM_PAINT:
Paint(); // 调用我们的 GDI 绘制函数
break;
// 窗口关闭消息
case WM_CLOSE:
DestroyWindow(hwnd);
break;
// 窗口销毁消息
case WM_DESTROY:
PostQuitMessage(0); // 发送离开消息给系统
break;
// 其他消息
default:
// pass 给系统,咱不管
return DefWindowProc(hwnd, msg, wParam, lParam);
}
return 0;
}

/*
* 第一步,注册窗口类
*/
void RegisterMyWindow(HINSTANCE hInstance)
{
WNDCLASSEX wc;

// 1)配置窗口属性
wc.cbSize = sizeof(WNDCLASSEX);
wc.style = 0;
wc.lpfnWndProc = MyWindowProc; // 设置第四步的窗口过程回调函数
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
wc.lpszMenuName = NULL;
wc.lpszClassName = g_szClassName;
wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION);

// 2)注册
if (!RegisterClassEx(&wc))
{
MessageBox(NULL, TEXT("窗口注册失败!"), TEXT("错误"), MB_ICONEXCLAMATION | MB_OK);
exit(0); // 进程退出
}
}

/*
* 第二步,创建窗口
*/
HWND CreateMyWindow(HINSTANCE hInstance, int nCmdShow)
{
HWND hwnd;
hwnd = CreateWindowEx(
WS_EX_CLIENTEDGE,
g_szClassName,
TEXT("我的窗口名称"),
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT, 800, 600, // 出现坐标 x,y 默认分配 窗口宽 400 高 300
NULL, NULL, hInstance, NULL);

if (hwnd == NULL)
{
MessageBox(NULL, TEXT("窗口创建失败!"), TEXT("错误"), MB_ICONEXCLAMATION | MB_OK);
exit(0); // 进程退出
}

// 显示窗口
ShowWindow(hwnd, nCmdShow);
UpdateWindow(hwnd);

return hwnd;
}

/*
* 主函数
*/
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpCmdLine, int nCmdShow)
{
HWND hwnd;
MSG Msg;

// 第一步,注册窗口类
RegisterMyWindow(hInstance);
// 第二步:创建窗口
hwnd = CreateMyWindow(hInstance, nCmdShow);
// 第三步:消息循环
while (GetMessage(&Msg, NULL, 0, 0) > 0)
{
TranslateMessage(&Msg);
DispatchMessage(&Msg);
}
return Msg.wParam;
}

加载位图与绘制文本

1.加载bmp格式的位图

准备一张bmp图片

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
#include <windows.h>

// 用于注册的窗口类名
const char g_szClassName[] = "myWindowClass";

//2. 贴图
void putImg(HWND hwnd) {
HDC hdc = GetDC(hwnd);
HINSTANCE hInstanc = GetModuleHandle(NULL);

//1. 加载图片
HANDLE p1 = LoadImageW(hInstanc, L"D:\\Users\\3\\Pictures\\picture\\Bitmap.bmp", IMAGE_BITMAP, 207, 293, LR_LOADFROMFILE);

//2. 创建兼容DC
HDC hDc1 = CreateCompatibleDC(NULL);//与指定设备兼容的DC

//3. 把图片选择到兼容DC
SelectObject(hDc1, p1); //将对象选择到按指定的设备上下文中

//4. 从兼容DC绘制到HDC
BitBlt(hdc, 10, 10, 207, 293, hDc1, 0, 0, SRCCOPY);

}

/*
* 第四步,窗口过程
*/
LRESULT CALLBACK MyWindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch (msg)
{
// 窗口绘制消息
case WM_PAINT:
putImg(hwnd); // 调用我们的 GDI 加载位图
break;
// 窗口关闭消息
case WM_CLOSE:
DestroyWindow(hwnd);
break;
// 窗口销毁消息
case WM_DESTROY:
PostQuitMessage(0); // 发送离开消息给系统
break;
// 其他消息
default:
// pass 给系统,咱不管
return DefWindowProc(hwnd, msg, wParam, lParam);
}
return 0;
}

/*
* 第一步,注册窗口类
*/
void RegisterMyWindow(HINSTANCE hInstance)
{
WNDCLASSEX wc;

// 1)配置窗口属性
wc.cbSize = sizeof(WNDCLASSEX);
wc.style = 0;
wc.lpfnWndProc = MyWindowProc; // 设置第四步的窗口过程回调函数
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
wc.lpszMenuName = NULL;
wc.lpszClassName = g_szClassName;
wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION);

// 2)注册
if (!RegisterClassEx(&wc))
{
MessageBox(NULL, TEXT("窗口注册失败!"), TEXT("错误"), MB_ICONEXCLAMATION | MB_OK);
exit(0); // 进程退出
}
}

/*
* 第二步,创建窗口
*/
HWND CreateMyWindow(HINSTANCE hInstance, int nCmdShow)
{
HWND hwnd;
hwnd = CreateWindowEx(
WS_EX_CLIENTEDGE,
g_szClassName,
TEXT("我的窗口名称"),
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT, 800, 600, // 出现坐标 x,y 默认分配 窗口宽 400 高 300
NULL, NULL, hInstance, NULL);

if (hwnd == NULL)
{
MessageBox(NULL, TEXT("窗口创建失败!"), TEXT("错误"), MB_ICONEXCLAMATION | MB_OK);
exit(0); // 进程退出
}

// 显示窗口
ShowWindow(hwnd, nCmdShow);
UpdateWindow(hwnd);

return hwnd;
}

/*
* 主函数
*/
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpCmdLine, int nCmdShow)
{
HWND hwnd;
MSG Msg;

// 第一步,注册窗口类
RegisterMyWindow(hInstance);
// 第二步:创建窗口
hwnd = CreateMyWindow(hInstance, nCmdShow);
// 第三步:消息循环
while (GetMessage(&Msg, NULL, 0, 0) > 0)
{
TranslateMessage(&Msg);
DispatchMessage(&Msg);
}
return Msg.wParam;
}

2.使用多级缓冲绘图,解决闪烁问题

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
#include <windows.h>

#pragma comment(lib,"Msimg32.lib")
// 用于注册的窗口类名
const char g_szClassName[] = "myWindowClass";

// 2. 贴图
void putImg(HWND hwnd) {
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hwnd, &ps); // 使用 BeginPaint 获取 HDC

// 填充背景为白色
FillRect(hdc, &ps.rcPaint, (HBRUSH)(COLOR_WINDOW + 1));

HINSTANCE hInstanc = GetModuleHandle(NULL);
HANDLE p1 = LoadImageW(hInstanc, L"D:\\Users\\3\\Pictures\\picture\\Bitmap.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);

if (p1 == NULL) {
// 如果加载位图失败,显示错误信息
MessageBox(hwnd, L"位图加载失败!", L"错误", MB_OK | MB_ICONERROR);
EndPaint(hwnd, &ps);
return;
}

// 创建一个内存设备上下文
HDC hDcMem = CreateCompatibleDC(hdc);
HBITMAP hOldBitmap = (HBITMAP)SelectObject(hDcMem, p1);

// 创建一个兼容位图
HBITMAP hBit1 = CreateCompatibleBitmap(hdc, 800, 600); // 窗口大小
HDC hDst = CreateCompatibleDC(hdc);
SelectObject(hDst, hBit1);

// 将位图绘制到兼容DC中
BitBlt(hDst, 0, 0, 207, 293, hDcMem, 0, 0, SRCCOPY);

// 使用 TransparentBlt 绘制到窗口的 HDC
// 假设我们希望将白色 (0, 0, 0) 作为透明色
TransparentBlt(hdc, 0, 0, 800, 600, hDst, 0, 0, 800, 600, RGB(0, 0, 0));

// 清理资源
SelectObject(hDcMem, hOldBitmap);
DeleteDC(hDcMem);
DeleteDC(hDst);
DeleteObject(hBit1);
EndPaint(hwnd, &ps); // 使用 EndPaint 结束绘制
}


/*
* 第四步,窗口过程
*/
LRESULT CALLBACK MyWindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch (msg)
{
// 窗口绘制消息
case WM_PAINT:
putImg(hwnd); // 调用我们的 GDI 绘图函数
break;
// 窗口关闭消息
case WM_CLOSE:
DestroyWindow(hwnd);
break;
// 窗口销毁消息
case WM_DESTROY:
PostQuitMessage(0); // 发送离开消息给系统
break;
// 其他消息
default:
// pass 给系统,咱不管
return DefWindowProc(hwnd, msg, wParam, lParam);
}
return 0;
}

/*
* 第一步,注册窗口类
*/
void RegisterMyWindow(HINSTANCE hInstance)
{
WNDCLASSEX wc;

// 1)配置窗口属性
wc.cbSize = sizeof(WNDCLASSEX);
wc.style = 0;
wc.lpfnWndProc = MyWindowProc; // 设置第四步的窗口过程回调函数
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
wc.lpszMenuName = NULL;
wc.lpszClassName = g_szClassName;
wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION);

// 2)注册
if (!RegisterClassEx(&wc))
{
MessageBox(NULL, TEXT("窗口注册失败!"), TEXT("错误"), MB_ICONEXCLAMATION | MB_OK);
exit(0); // 进程退出
}
}

/*
* 第二步,创建窗口
*/
HWND CreateMyWindow(HINSTANCE hInstance, int nCmdShow)
{
HWND hwnd;
hwnd = CreateWindowEx(
WS_EX_CLIENTEDGE,
g_szClassName,
TEXT("我的窗口名称"),
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT, 800, 600, // 出现坐标 x,y 默认分配 窗口宽 400 高 300
NULL, NULL, hInstance, NULL);

if (hwnd == NULL)
{
MessageBox(NULL, TEXT("窗口创建失败!"), TEXT("错误"), MB_ICONEXCLAMATION | MB_OK);
exit(0); // 进程退出
}

// 显示窗口
ShowWindow(hwnd, nCmdShow);
UpdateWindow(hwnd);

return hwnd;
}

/*
* 主函数
*/
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpCmdLine, int nCmdShow)
{
HWND hwnd;
MSG Msg;

// 第一步,注册窗口类
RegisterMyWindow(hInstance);
// 第二步:创建窗口
hwnd = CreateMyWindow(hInstance, nCmdShow);
// 第三步:消息循环
while (GetMessage(&Msg, NULL, 0, 0) > 0)
{
TranslateMessage(&Msg);
DispatchMessage(&Msg);
}
return Msg.wParam;
}

3.绘制文本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
#include <windows.h>

#pragma comment(lib,"Msimg32.lib")
// 用于注册的窗口类名
const char g_szClassName[] = "myWindowClass";

// 2. 贴图
void text(HWND hwnd) {
PAINTSTRUCT ps;
HDC hdc=BeginPaint(hwnd, &ps);
HFONT hFont1 = CreateFont(48, 0, 0, 0, FW_DONTCARE, FALSE, TRUE, FALSE, DEFAULT_CHARSET, OUT_OUTLINE_PRECIS,
CLIP_DEFAULT_PRECIS, CLEARTYPE_QUALITY, VARIABLE_PITCH, TEXT("Impact"));
SelectObject(hdc, hFont1);
wchar_t buff[256] = L"这是一段文字";
TextOut(hdc, 100, 100, buff, wcslen(buff));

EndPaint(hwnd, &ps);
}



/*
* 第四步,窗口过程
*/
LRESULT CALLBACK MyWindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch (msg)
{
// 窗口绘制消息
case WM_PAINT:
text(hwnd);
break;
// 窗口关闭消息
case WM_CLOSE:
DestroyWindow(hwnd);
break;
// 窗口销毁消息
case WM_DESTROY:
PostQuitMessage(0); // 发送离开消息给系统
break;
// 其他消息
default:
// pass 给系统,咱不管
return DefWindowProc(hwnd, msg, wParam, lParam);
}
return 0;
}

/*
第一步,注册窗口类
*/
void RegisterMyWindow(HINSTANCE hInstance)
{
WNDCLASSEX wc;

// 1)配置窗口属性
wc.cbSize = sizeof(WNDCLASSEX);
wc.style = 0;
wc.lpfnWndProc = MyWindowProc; // 设置第四步的窗口过程回调函数
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
wc.lpszMenuName = NULL;
wc.lpszClassName = g_szClassName;
wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION);

// 2)注册
if (!RegisterClassEx(&wc))
{
MessageBox(NULL, TEXT("窗口注册失败!"), TEXT("错误"), MB_ICONEXCLAMATION | MB_OK);
exit(0); // 进程退出
}
}

/*
* 第二步,创建窗口
*/
HWND CreateMyWindow(HINSTANCE hInstance, int nCmdShow)
{
HWND hwnd;
hwnd = CreateWindowEx(
WS_EX_CLIENTEDGE,
g_szClassName,
TEXT("我的窗口名称"),
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT, 800, 600, // 出现坐标 x,y 默认分配 窗口宽 400 高 300
NULL, NULL, hInstance, NULL);

if (hwnd == NULL)
{
MessageBox(NULL, TEXT("窗口创建失败!"), TEXT("错误"), MB_ICONEXCLAMATION | MB_OK);
exit(0); // 进程退出
}

// 显示窗口
ShowWindow(hwnd, nCmdShow);
UpdateWindow(hwnd);

return hwnd;
}

/*
* 主函数
*/
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpCmdLine, int nCmdShow)
{
HWND hwnd;
MSG Msg;

// 第一步,注册窗口类
RegisterMyWindow(hInstance);
// 第二步:创建窗口
hwnd = CreateMyWindow(hInstance, nCmdShow);
// 第三步:消息循环
while (GetMessage(&Msg, NULL, 0, 0) > 0)
{
TranslateMessage(&Msg);
DispatchMessage(&Msg);
}
return Msg.wParam;
}