MFC学习随笔

发布时间 2023-05-05 16:55:39作者: 纤

1.原理

image-20221111113204739

1.1设计窗口

	wc.cbClsExtra = 0; //类的额外内存
	wc.cbWndExtra = 0; //窗口额外内存
	wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); //设置背景 - 白色
	wc.hCursor = LoadCursor(NULL, IDC_HAND); // 设置光标,如果第一个参数为NULL , 代表使用系统提供的光标
	wc.hIcon = LoadIcon(NULL, IDI_ERROR); //图标 如果第一个参数为NULL 代表使用系统提供的图标
	wc.hInstance = hInstance; // 应用程序实例句柄, 传入WinMain 中的形参即可
	//wc.IpfnWndProc = WindowProc; //回调函数 窗口过程
	wc.lpszClassName = TEXT("WIN"); // 指定窗口类名称
	wc.lpszMenuName = NULL; //菜单名称
	wc.style = 0;//显示风格 0代表默认风格

1.2 注册窗口类

	RegisterClass(&wc);

1.3创建窗口

	HWND hwnd = CreateWindow(
		wc.lpszClassName, //类名
		TEXT("WINDOWS"), //标题名
		WS_OVERLAPPEDWINDOW, //风格
		CW_USEDEFAULT, // x坐标 默认
		CW_USEDEFAULT, // y坐标 默认
		CW_USEDEFAULT, // 宽 默认
		CW_USEDEFAULT, // 高 默认
		NULL, //父窗口
		NULL, // hMeanu 菜单
		hInstance, // 实例句柄 hInstance
		NULL //附加值
	);

1.4显示和更新

	ShowWindow(hwnd, SW_SHOWNORMAL); //显示
	UpdateWindow(hwnd); //更新

1.5通过循环获取消息

image-20221111120936349

	MSG msg;
	while (true) {
		// 消息
		//第二个参数为NULL, 表示处理所有窗口的消息
		// 最小和最大的过滤的消息 , 填入0
		// 填0代表捕获所有消息
		if (GetMessage(&msg, NULL, 0, 0) == FALSE) {
			break;
		}
		//翻译消息
		TranslateMessage(&msg);
		//不为false
		//分发消息
		DispatchMessage(&msg);
	}

1.6处理窗口过程

//6. 处理消息(窗口过程) 使用回调函数
LRESULT CALLBACK WindowProc(
	HWND hwnd, // 消息所属的窗口句柄
	UINT uMsg, //具体消息名称 WM_XXX消息名
	WPARAM wParam, // 键盘附加消息
	LPARAM lParam //鼠标附加消息
)
{
	switch (uMsg) {
	case WM_CLOSE:
		DestroyWindow(hwnd); // 发送另一个消息 WM_DESTROY
		break;
	case WM_DESTROY:
		PostQuitMessage(0);
		break;
	case WM_LBUTTONDOWN: // 鼠标左键按下
		int xPos = LOWORD(lParam);
		int yPos = HIWORD(lParam);

		wchar_t buf[1024];
		wsprintf(buf,TEXT("x = %d , y = %d"), xPos, yPos);

		MessageBox(hwnd,TEXT("aaa"),TEXT("鼠标左键按下"),MB_OK);
		break;

	case WM_KEYDOWN: //键盘
		MessageBox(hwnd, TEXT("键盘按下"), TEXT("键盘按下"), MB_OK);
		break;

	case WM_PAINT: //绘图
		PAINTSTRUCT ps;// 绘图结构体
		HDC hdc = BeginPaint(hwnd, &ps);
		TextOut(hdc, 100, 100, TEXT("HELLO", strlen("HELLO")));
		EndPaint(hwnd,&ps);
	}

	return DefWindowProc(hwnd, uMsg, wParam, lParam);
		//返回值用默认处理方式
}

1.7完整代码

#include<Windows.h>


//6. 处理消息(窗口过程) 使用回调函数
LRESULT CALLBACK WindowProc(
	HWND hwnd, // 消息所属的窗口句柄
	UINT uMsg, //具体消息名称 WM_XXX消息名
	WPARAM wParam, // 键盘附加消息
	LPARAM lParam //鼠标附加消息
)
{
	switch (uMsg)
	{
		case WM_CLOSE:
			DestroyWindow(hwnd); // 发送另一个消息 WM_DESTROY
			break;
		case WM_DESTROY:
			PostQuitMessage(0);
			break;
		case WM_LBUTTONDOWN: // 鼠标左键按下
		{
			int xPos = LOWORD(lParam);
			int yPos = HIWORD(lParam);

			wchar_t buf[1024];
			wsprintf(buf, TEXT("x = %d , y = %d"), xPos, yPos);

			MessageBox(hwnd, TEXT("aaa"), TEXT("鼠标左键按下"), MB_OK);
			break;
		}
		case WM_KEYDOWN: //键盘
			MessageBox(hwnd, TEXT("键盘按下"), TEXT("键盘按下"), MB_OK);
			break;

		case WM_PAINT: //绘图
		{
			PAINTSTRUCT ps;// 绘图结构体
			HDC hdc = BeginPaint(hwnd, &ps);
			TextOut(hdc, 100, 100, TEXT("HELLO"), strlen("HELLO"));
			EndPaint(hwnd, &ps);
		}
	}

	return DefWindowProc(hwnd, uMsg, wParam, lParam);
	//返回值用默认处理方式
}

int WINAPI WinMain(
	HINSTANCE hInstance, // 应用程序实例句柄
	HINSTANCE hPrevInstance, //上一个应用程序句柄 在Win32环境下 一般为NULL 不起作用了
	LPSTR lpCmdLine,
	int nShowCmd // 显示命令 最大化 最小化 正常 

)
{
	//1. 设计窗口
	WNDCLASS wc;

	wc.cbClsExtra = 0; //类的额外内存
	wc.cbWndExtra = 0; //窗口额外内存
	wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); //设置背景 - 白色
	wc.hCursor = LoadCursor(NULL, IDC_HAND); // 设置光标,如果第一个参数为NULL , 代表使用系统提供的光标
	wc.hIcon = LoadIcon(NULL, IDI_ERROR); //图标 如果第一个参数为NULL 代表使用系统提供的图标
	wc.hInstance = hInstance; // 应用程序实例句柄, 传入WinMain 中的形参即可
	wc.lpfnWndProc = WindowProc; //回调函数 窗口过程
	wc.lpszClassName = TEXT("WIN"); // 指定窗口类名称
	wc.lpszMenuName = NULL; //菜单名称
	wc.style = 0;//显示风格 0代表默认风格

	//2. 注册窗口
	RegisterClass(&wc);

	//3. 创建窗口
	HWND hwnd = CreateWindow(
		wc.lpszClassName, //类名
		TEXT("WINDOWS"), //标题名
		WS_OVERLAPPEDWINDOW, //风格
		CW_USEDEFAULT, // x坐标 默认
		CW_USEDEFAULT, // y坐标 默认
		CW_USEDEFAULT, // 宽 默认
		CW_USEDEFAULT, // 高 默认
		NULL, //父窗口
		NULL, // hMeanu 菜单
		hInstance, // 实例句柄 hInstance
		NULL //附加值
	);

	//4. 显示和更新
	ShowWindow(hwnd, SW_SHOWNORMAL); //显示
	UpdateWindow(hwnd); //更新

	//5. 通过循环取消息
	MSG msg;
	while (1) {
		// 消息
		//第二个参数为NULL, 表示处理所有窗口的消息
		// 最小和最大的过滤的消息 , 填入0
		// 填0代表捕获所有消息
		if (GetMessage(&msg, NULL, 0, 0) == FALSE) {
			break;
		}
		//翻译消息
		TranslateMessage(&msg);
		//不为false
		//分发消息
		DispatchMessage(&msg);
	}


	return 0;
}

2.MFC

2.1 包含头文件

image-20221111145416054

2.2 简单的一个MFC应用

2.2.1 代码简略

image-20221111145503518

2.2.2 在vs中设置使用共享DLL的MFC

image-20221111150534795

2.2.3 头文件代码

#include<afxwin.h>

class MyApp:public CWinApp //CWinApp应用程序类
{
public:
	//基类的虚函数 派生类只是重写
	//程序入口
	virtual BOOL InitInstance();
};

//框架类 CFrameWnd 子类
class MyFrame:public CFrameWnd //窗口框架类
{
public:
	MyFrame();

};

2.2.4 cpp文件代码

#include"mfc.h"

MyApp app;//有且只有一个全局的应用程序窗口类对象

BOOL MyApp::InitInstance()
{
	//1.创建框架类对象 创建窗口
	MyFrame* frame = new MyFrame;

	//显示和更新
	frame->ShowWindow(SW_SHOWNORMAL); // 显示窗口
	frame->UpdateWindow(); //更新窗口
	
	m_pMainWnd = frame; //保存指向应用程序的主窗口的指针
	return TRUE;

}

MyFrame::MyFrame()
{
	Create(NULL, TEXT("mfc"));
}

2.3 消息映射

2.3.1 简介

image-20221111163933863

2.3.2 简略代码

image-20221111163950556

2.3.3消息映射宏

image-20221111164214133

image-20221111164336139

2.3.4示例代码头文件

#include<afxwin.h>

class MyApp:public CWinApp //CWinApp应用程序类
{
public:
	//基类的虚函数 派生类只是重写
	//程序入口
	virtual BOOL InitInstance();
};

//框架类 CFrameWnd 子类
class MyFrame:public CFrameWnd //窗口框架类
{
public:
	MyFrame();

	//声明宏 提供消息映射机制
	DECLARE_MESSAGE_MAP()

	afx_msg void OnLButtonDown(UINT, CPoint);

	afx_msg void OnChar(UINT, UINT, UINT);

	afx_msg void OnPaint();
};

2.3.5示例代码cpp文件

#include"mfc.h"

MyApp app;//有且只有一个全局的应用程序窗口类对象

BOOL MyApp::InitInstance()
{
	//1.创建框架类对象 创建窗口
	MyFrame* frame = new MyFrame;

	//显示和更新
	frame->ShowWindow(SW_SHOWNORMAL); // 显示窗口
	frame->UpdateWindow(); //更新窗口
	
	m_pMainWnd = frame; //保存指向应用程序的主窗口的指针
	return TRUE;

}

//分界宏
BEGIN_MESSAGE_MAP(MyFrame, CFrameWnd)

	ON_WM_LBUTTONDOWN() //鼠标左键按下

	ON_WM_CHAR() //键盘

	ON_WM_PAINT()//绘图宏
END_MESSAGE_MAP()

MyFrame::MyFrame()
{
	Create(NULL, TEXT("mfc"));
}

void MyFrame::OnLButtonDown(UINT, CPoint point)
{
	//mfc里的字符数组
	TCHAR buf[1024];

	//wsprintf(buf, TEXT("x = %d, y = %d"), point.x, point.y);

	////对话框
	//MessageBox(buf);

	//mfc 中的字符串 CString
	CString str;
	str.Format(TEXT("x = %d,,, y = %d"), point.x, point.y);
	MessageBox(str);
}

void MyFrame::OnChar(UINT key, UINT, UINT)
{
	CString str;
	str.Format(TEXT("按下了 %c 键"), (char)key);

	MessageBox(str);
}

void MyFrame::OnPaint()
{
	CPaintDC dc(this); //指定绘图的设备

	dc.TextOutW(100, 100, TEXT("为了部落"));

	//画椭圆
	dc.Ellipse(10, 10, 100, 100);
}

2.4 字符编码

2.4.1 统计宽字节的字符串长度

image-20221111210736538

2.4.2 char*与CString之间的转换

image-20221111210817688

2.5 利用向导创建MFC

通过vs创建

image-20221111211808891

2.6 使用

image-20221111212533105

image-20221111212545641

选择所需要的窗口事件 , 右键添加

image-20221111212518698

如果有了OnDraw 再有OnPaint 会覆盖掉

  • MFC中后缀名为Ex的函数都是扩展函数
  • MFC中以Afx为前缀的函数都是全局函数 , 可以在程序的任何地方调用他们

view 视类 相片 MainFram类 相框

OnCreate相应创建窗口-设置风格属性等 Create创建窗口 WM_CREATE 消息是由Create函数调用的 一个窗口(Create)后会向系统发送WM_CREATE消息,OnCreate响应此消息

2.7 基于对话框进行操作

2.7.1 查找主窗口路径

image-20221111215234899

image-20221111215302201

2.7.2 模态对话框

image-20221113175958108

创建类 , 去创建一个和该按钮对应的类

image-20221113180607433

三种添加事件的方法

右键属性 - 控件事件

右键 - 添加事件处理程序

双击该按钮

image-20221113180839371

在头文件引入刚才创建的那个对话框的类的头文件

//弹出模态对话框
	CDlgExec dlg;
	dlg.DoModal();

2.7.3 非模态对话框

  • 创建视图对应类

  • 添加触发事件

  • 导入头文件

  • 写弹出的方法

    void CMFCApplication2Dlg::OnBnClickedButton2()
    {
    	// TODO: 在此添加控件通知处理程序代码
    
    	//弹出非模态对话框
    	CDlgShow dlg;
    	//创建
    	dlg.Create(IDD_DIALOG2);//创建一个窗口只能创建一次 , 多次会崩
    	//显示
    	dlg.ShowWindow(SW_SHOWNORMAL);
    
    }
    

因为生存周期的问题 , 方法执行完这个窗口类会释放, 所以需要在大对话框的头文件中去申明他

image-20221113191435872

同时 大的对话框的头文件中, 需要引入这个非模态对话框的头文件

image-20221113191629290

而且这只能创建一次 , 再创建一次会崩溃

所以需要放到初始化函数里,防止二次执行创建操作

找到初始化方法

image-20221113191916677

image-20221113192032996

后面其他UI组件的用法其实大差不差直接看着文档写或者就看着demo代码来写就行了,懒得记录了,有一说一 , 这玩意是真的辣鸡