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

概述

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

1 创建消息处理函数

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)

本例中消息处理函数:

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

WNDCLASS wc;

2.2 设置窗体实例属性

​ 所有属性都要设置

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 窗体显示风格
UINT style

style的值为下列值的组合

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

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

本例中设置为:

wc.style = CS_VREDRAW | CS_HREDRAW;
2.2.2 消息处理函数
WNDPROC   lpfnWndProc;

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

本例我们设置为:

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

本例赋值为0

wc.cbClsExtra = 0;	
2.2.4 窗体额外空间
int       cbWndExtra;

本例赋值为0

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

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

wc.hInstance = hInstrance;							//当前应用程序句柄

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

2.2.6 窗体左上角图标资源句柄
HICON hIcon

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

wc.hIcon = NULL;

如果用自己的资源

wc.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_ICON));

函数: LoadIcon用来加Icon资源

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

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

2.2.7 窗体鼠标形状

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

wc.hCursor = NULL;

​ 如果用自定义的资源

wc.hCursor = LoadCursor(hInstance, MAKEINTRESOURCE(IDC_CURSOR));

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

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

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

2.2.8 客户区背景
HBRUSH    hbrBackground;

​ 设置客户区背景为红色

wc.hbrBackground = CreateSolidBrush(RGB(255, 0, 0 ));
2.2.9 菜单名

菜单 名: LPCTSTR lpszMenuName;

wc.lpszMenuName = NULL; //不设置没有菜单
2.2.10 类名

窗体类名: LPCTSTR lpszClassName;

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

3 注册窗体

函数: RegisterClass

ATOM WINAPI RegisterClass(
  _In_  const WNDCLASS *lpWndClass
);

参数: 窗体类地址

RegisterClass(&wc);

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

if (0 == RegisterClass(&wc)) {
	MessageBox(NULL, L"注册失败", L"温馨提示", MB_OK);
	return 0; //注册失败结束程序
}

4 创建窗体句柄

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

本例设置如下:

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

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

if (hWnd == NULL){
    MessageBox(NULL, L"窗体创建失败", L"警告", MB_ICONWARNING);
    return 0;
}

5 显示窗体

函数原型

BOOL ShowWindow(HWND hWnd, nCmdShow)

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

第二个参数: 显示方式

显示方式列表:

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

本例代码 :

ShowWindow(hWnd, SW_SHOW);

5 更新窗体

函数原型:

BOOL UpdateWindow(HWND hWnd);

参数: 要更新的窗体句柄

本例代码:

UpdateWindow(hWnd);

6 消息循环

6.1 消息类型MSG

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

MSG msg;

6.2 获取消息: GetMessage

函数原型:

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消息

发送方式为调用函数:

PostQuitMessage(0);

6.3 消息循环

while(GetMessage(&msg, NULL, 0, 0)){
    TranslateMessage(&msg); 	//将虚拟键消息转换为字符消息
	DispatchMessage(&msg);		//将虚拟键消息分发给窗口处理函数
}

循环体里的两个函数:

(1) 函数原型

BOOL TranslateMessage(
  const MSG* lpMsg 
);

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

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

(2)函数原型

LONG  DispatchMessage( 
  const MSG* lpmsg 
);

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

完整示例代码

(1)main.cpp

#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

//{{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编程第一课:纯手工创建一个窗体所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

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

评论列表共有 0 条评论

立即
投稿
返回
顶部