我是靠谱客的博主 贤惠身影,这篇文章主要介绍Windows编程第一课:纯手工创建一个窗体,现在分享给大家,希望可以做个参考。

第一节 创建应用程序主窗体

1 创建消息处理函数

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
LRESULT CALLBACK fWinProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { switch (uMsg){ case WM_CLOSE: //处理关闭按钮消息 DestroyWindow(hWnd); //销毁窗口 break; case WM_DESTROY: PostQuitMessage(0); //发送退出消息 break; } //将不处理的函数交给系统默认处理 return DefWindowProc(hWnd, uMsg, wParam, lParam); }

这个函数不用自己调用,赋值给窗体后会自动调用这个函数

关键是第二个参数,这个参数是获取到的消息标识

本例只处理两个消息:

(1) 当按下窗体右上角的关闭按钮时的消息: WM_CLOSE

(2) 当窗体进行真正销毁时:WM_DESTROY

消息队列只有在收到:WM_QUIT GetMessage()函数才会返回false值.因此必须要有一个行为能够发送这个消息.

此例中,我们在接到受到销毁窗口时发送这个消息:PostQuitMessage(0)

本例中消息处理函数:

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
LRESULT CALLBACK fWinProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { switch (uMsg){ case WM_CLOSE: //处理关闭按钮消息 DestroyWindow(hWnd); //销毁窗口 break; case WM_DESTROY: PostQuitMessage(0); //发送退出消息 break; } //将不处理的函数交给系统默认处理 return DefWindowProc(hWnd, uMsg, wParam, lParam); }

返回值类型为: LRESULT

限定词CALLBACK作用同WINAPI 用来设定参数的入栈方式(从右往左,以及参数的管理者:调用者)

第一个参数: 窗体句柄

第二个参数: 消息事件标识ID

第三个参数: 附加消息

第四个参数: 附加消息

返回值: 系统消息处理函数(对于不处理的消息,交回给系统处理,并返回调用结果的返回值

2 创建窗体结构体实例并设置相关属性

2.1 窗体结构体: WNDCLASS

复制代码
1
2
WNDCLASS wc;

2.2 设置窗体实例属性

​ 所有属性都要设置

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
typedef struct tagWNDCLASS { UINT style; WNDPROC lpfnWndProc; int cbClsExtra; int cbWndExtra; HINSTANCE hInstance; HICON hIcon; HCURSOR hCursor; HBRUSH hbrBackground; LPCTSTR lpszMenuName; LPCTSTR lpszClassName; } WNDCLASS, *PWNDCLASS;
2.2.1 窗体显示风格
复制代码
1
2
UINT style

style的值为下列值的组合

描述
CS_DBLCLKS接受双击事件的窗体
CS_HREDRAW调整大小后自动重绘的窗体
CS_NOCLOSE禁用窗口菜单上的关闭按钮
CS_PARENTDC
CS_VREDRAW客户区移动或大小调整后重绘
CS_SAVEBITS保存被窗体挡住部分的图像,以便恢复

​ 可以上以上风格的任意组合,用(|) 连接即可

本例中设置为:

复制代码
1
2
wc.style = CS_VREDRAW | CS_HREDRAW;
2.2.2 消息处理函数
复制代码
1
2
WNDPROC lpfnWndProc;

就是第一步我们定义的消息处理函数,传入函数名即可

本例我们设置为:

复制代码
1
2
wc.lpfnWndProc = fWinProc; //消息处理函数
2.2.3 窗体扩展额外空间
复制代码
1
2
int cbClsExtra;

本例赋值为0

复制代码
1
2
wc.cbClsExtra = 0;
2.2.4 窗体额外空间
复制代码
1
2
int cbWndExtra;

本例赋值为0

复制代码
1
2
wc.cbWndExtra = 0; //窗口的窗外扩展空间
2.2.5 应用程序句柄
复制代码
1
2
HINSTANCE hInstance;

本例赋值为当前程序实例句柄

复制代码
1
2
wc.hInstance = hInstrance; //当前应用程序句柄

这个变量为WinMain 函数的第一个参数

2.2.6 窗体左上角图标资源句柄
复制代码
1
2
HICON hIcon

如果用系统默认的图标,设置为NULL

复制代码
1
2
wc.hIcon = NULL;

如果用自己的资源

复制代码
1
2
wc.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_ICON));

函数: LoadIcon用来加Icon资源

第一个参数: 应用程序句柄

第二个参数: 一个字符串, MAKEINTRESOURCE将资源的ID转换为资源对应的字符串

2.2.7 窗体鼠标形状

​ 如果用系统默认的鼠标图标,设置为NULL

复制代码
1
2
wc.hCursor = NULL;

​ 如果用自定义的资源

复制代码
1
2
wc.hCursor = LoadCursor(hInstance, MAKEINTRESOURCE(IDC_CURSOR));

函数LoadCursor用来加载鼠标形状资源

第一个参数: 应用程序句柄

第二个参数: 资源字符串,一般用MAKEINTRESOURCE将资源对应的资源标识(IDC_CURSOR)转化为对应的字符串

2.2.8 客户区背景
复制代码
1
2
HBRUSH hbrBackground;

​ 设置客户区背景为红色

复制代码
1
2
wc.hbrBackground = CreateSolidBrush(RGB(255, 0, 0 ));
2.2.9 菜单名

菜单 名: LPCTSTR lpszMenuName;

复制代码
1
2
wc.lpszMenuName = NULL; //不设置没有菜单
2.2.10 类名

窗体类名: LPCTSTR lpszClassName;

复制代码
1
2
wc.lpszClassName = L"MyWindowClass"; //随便写,暂时不知道什么用,用中文也是可以的

3 注册窗体

函数: RegisterClass

复制代码
1
2
3
4
ATOM WINAPI RegisterClass( _In_ const WNDCLASS *lpWndClass );

参数: 窗体类地址

复制代码
1
2
RegisterClass(&wc);

在实际应用中要对返回值做一个判断,以确认是否正确注册

复制代码
1
2
3
4
5
if (0 == RegisterClass(&wc)) { MessageBox(NULL, L"注册失败", L"温馨提示", MB_OK); return 0; //注册失败结束程序 }

4 创建窗体句柄

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
HWND hWnd = CreateWindow( LPCTSTR lpClassName, //类名 字符串 LPCTSTR lpWindowName, //窗体标题 字符串 DWORD dwStyle, //显示风格 int x, //左上角x坐标 int y, //左上角y坐标 int nWidth, //窗体宽度 int nHeight, //窗体高度 HWND hWndParent, //父窗体句柄,没有设置为NULL HMENU hMenu, //菜单栏句柄,没有设置为NULL HANDLE hInstance, //所属应用程序句柄 PVOID lpParam //附加参数,没有设置为NULL );

本例设置如下:

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
HWND hWnd = CreateWindow( L"MyWindowClass", //窗口类型名 L"第一个窗体", //窗口s标题 //带标题栏 系统菜单(关闭按钮) 最小化按钮 最大按钮 WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX,//带标题栏的窗体 0, //左上角x坐标 0, //左上角y坐标 600, //窗体宽度 600, //窗体高度 NULL, //没有父窗体 NULL, //没有菜栏 hInstance, //所属应用程序句柄 NULL, //附加参数 );

第一个参数要求必须与窗体类定义时的类名一致

第三个参数: 窗体风格,可以是如下值的组合

描述
WS_BORDER带边框的窗口
WS_CAPTION带标题栏的窗口(包含WS_BORDER)
WS_CHILD子窗口(必须含父窗口), 不能与WS_POPUP 共用
WS_CLIPCHILDREN父窗口使用,在绘制含本属性的窗口时会排除子窗口占用的区域
WS_CLIPSIBLINGS
WS_DISABLED最初禁用的窗体(禁用指不能接受用户输入,包括按钮点击等事件)
WS_DLGFRAME不能标题栏但有边框的窗体(一般用于对话框)
WS_GROUP指定一组控件的第一个控件,后续不带WS_GROUP的控件为后续控件,直到下一个使用WS_GROUP的控件出现
WS_HSCROLL带水平滚动条
WS_OVERLAPPED带标题栏与边框的重叠窗口
WS_OVERLAPPEDWINDOW创建重叠窗口
WS_POPUP弹出窗口,不能与WS_CHILD同时使用
WS_SIZEBOX可调节大小同, WS_THICKFRAME
WS_SYSMENU在非客户区带关闭(X)按钮的窗体
WS_TABSTOP可通过TAB切换控件焦点
WS_THICKFRAME可调节大小同, WS_SIZEBOX
WS_VISIBLE最初可见
WS_VSCROLL带垂直滚动条

第四个参数: 窗品显示的左上角x坐标(相对于屏幕左上角)

第五个参数: 窗品显示的左上角y坐标(相对于屏幕左上角)

第六个参数: 窗口的宽度

第七个参数: 窗口的高度

第八个参数: 父窗口,如果是顶级窗口没有父窗口,值为NULL

第九个参数: 菜单句柄,如果没有菜单栏,值为NULL

第十个参数: 应用程序句柄

第十一个参数: 附加参数 ,没有设置为NULL

注意: 在使用的时候,在后续的操作中要判断句柄是否创建成功,以免空指针成生的不良后果

复制代码
1
2
3
4
5
if (hWnd == NULL){ MessageBox(NULL, L"窗体创建失败", L"警告", MB_ICONWARNING); return 0; }

5 显示窗体

函数原型

复制代码
1
2
BOOL ShowWindow(HWND hWnd, nCmdShow)

第一个参数: 要显示的窗体句柄

第二个参数: 显示方式

显示方式列表:

描述
SW_HIDE隐藏本窗体并激活另一个
SW_SHOW正常显示
SW_SHOWNA显示窗体带不激活(焦点仍在上一个窗体)
SW_SHOWNORMAL如果窗体最小化了或者最大化了,会被还原成正常的大小

本例代码 :

复制代码
1
2
ShowWindow(hWnd, SW_SHOW);

5 更新窗体

函数原型:

复制代码
1
2
BOOL UpdateWindow(HWND hWnd);

参数: 要更新的窗体句柄

本例代码:

复制代码
1
2
UpdateWindow(hWnd);

6 消息循环

6.1 消息类型MSG

定义一个消息对象(结构体)

复制代码
1
2
MSG msg;

6.2 获取消息: GetMessage

函数原型:

复制代码
1
2
3
4
5
6
7
BOOL WINAPI GetMessage( _Out_ LPMSG lpMsg, _In_opt_ HWND hWnd, _In_ UINT wMsgFilterMin, _In_ UINT wMsgFilterMax );

第一个参数: 消息对象指针

第二个参数: 消息传入窗体句柄

第三个参数: 消息过滤器, 消息标识的最小值

第四个参数: 消息过滤器,消息标识的最大值

注意:

(1)最后两个参数如果不想过滤,统一设置成0. 如果设置了,不在范围内的消息将不被接收

(2) 本函数只在获取消息WM_QUIT时才会返回false,否则都为true

因此,要想中止消息队列循环,必须在适当的时机发送WM_QUIT消息

发送方式为调用函数:

复制代码
1
2
PostQuitMessage(0);

6.3 消息循环

复制代码
1
2
3
4
5
while(GetMessage(&msg, NULL, 0, 0)){ TranslateMessage(&msg); //将虚拟键消息转换为字符消息 DispatchMessage(&msg); //将虚拟键消息分发给窗口处理函数 }

循环体里的两个函数:

(1) 函数原型

复制代码
1
2
3
4
BOOL TranslateMessage( const MSG* lpMsg );

函数功能: 将虚拟按键消息转换为字符消息, 即将按键翻译字符,即处理GetMessage函数接收到的消息(msg)对象

使之能够在后续的处理中以字符的消息来处理

(2)函数原型

复制代码
1
2
3
4
LONG DispatchMessage( const MSG* lpmsg );

函数功能: 调用消息处理函数来处理消息

完整示例代码

(1)main.cpp

复制代码
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
#include<Windows.h> #include "resource.h" //窗口应用程序入口函数: WinMain //命令行程序入入口函数: main LRESULT CALLBACK fWinProc(HWND, UINT,WPARAM, LPARAM); int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPreinstance, LPSTR lpCmdline, int nCmdShow){ WNDCLASS wc; LPCTSTR lpClassName = L"MyWindowClass"; wc.style = CS_VREDRAW | CS_HREDRAW; //设置显示风格 wc.lpfnWndProc = fWinProc; //消息处理函数 wc.cbClsExtra = 0; //窗口类的额外扩展空间 wc.cbWndExtra = 0; //窗口的窗外扩展空间 wc.hInstance = hInstance; //当前应用程序句柄 //wc.hIcon = NULL; //不设置窗口图标 wc.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_ICON)); //wc.hCursor = NULL; //不设置光标 wc.hCursor = LoadCursor(hInstance, MAKEINTRESOURCE(IDC_CURSOR)); wc.hbrBackground = CreateSolidBrush(RGB(255, 0, 0)); wc.lpszMenuName = NULL; wc.lpszClassName = lpClassName; //(3)注册窗体类 if (0 == RegisterClass(&wc)){ MessageBox(NULL, L"注册失败", L"警告", MB_OK || MB_ICONERROR); return 0; } // (4) 创建窗口句柄 HWND hWnd = CreateWindow( //lpClassName, //窗口类型名 lpClassName, L"第一个窗体", //窗口s标题 //带标题栏 系统菜单(关闭按钮) 最小化按钮 最大按钮 WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX,//带标题栏的窗体 0, //左上角x坐标 0, //左上角y坐标 600, //窗体宽度 600, //窗体高度 NULL, //没有父窗体 NULL, //没有菜栏 hInstance, //所属应用程序句柄 NULL, //附加参数 ); if (hWnd == NULL){ MessageBox(NULL, L"窗体创建失败", L"警告", MB_ICONWARNING); return 0; } //(5)显示窗体 ShowWindow(hWnd, SW_SHOW); //(4)更新窗体 UpdateWindow(hWnd); //(5) 消息队列 MSG msg; while (GetMessage(&msg, NULL, 0, 0)){ TranslateMessage(&msg); //将虚拟键消息转换为字符消息 DispatchMessage(&msg); //将虚拟键消息分发给窗口处理函数 } return 0; } LRESULT CALLBACK fWinProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { switch (uMsg){ case WM_CLOSE: //处理关闭按钮消息 DestroyWindow(hWnd); //销毁窗口 break; case WM_DESTROY: PostQuitMessage(0); //发送退出消息 break; } //将不处理的函数交给系统默认处理 return DefWindowProc(hWnd, uMsg, wParam, lParam); }

资源文件: resource.h

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
//{{NO_DEPENDENCIES}} // Microsoft Visual C++ 生成的包含文件。 // 供 Demo01创建窗口.rc 使用 // #define IDI_ICON 101 //这两行是关键 #define IDC_CURSOR 102 //这两行是关键 // Next default values for new objects #ifdef APSTUDIO_INVOKED #ifndef APSTUDIO_READONLY_SYMBOLS #define _APS_NEXT_RESOURCE_VALUE 103 #define _APS_NEXT_COMMAND_VALUE 40001 #define _APS_NEXT_CONTROL_VALUE 1001 #define _APS_NEXT_SYMED_VALUE 101 #endif #endif

最后

以上就是贤惠身影最近收集整理的关于Windows编程第一课:纯手工创建一个窗体的全部内容,更多相关Windows编程第一课内容请搜索靠谱客的其他文章。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(68)

评论列表共有 0 条评论

立即
投稿
返回
顶部