MFC程序开发

目录

1、底层实现窗口:

(1)、SDK

(2)、API

(3)、窗口和句柄

(4)、消息和消息队列

(5)、WinMain函数

2、窗口实现具体的六个步骤:

(1)、设计窗口  WNDCLASS 

(2)、注册窗口 Registerclass

(3)、创建窗口 creatWindow

(4)、显示和更新 showWindow updateWindow

(5)、通过循环取消息 MSG msg

(6)、窗口过程,消息处理(回调函数)

(7)、底层窗口实现全部代码

(8)、运行界面

3、利用MFC创建窗口:

4、消息映射:

(1)、具体代码实现 

(2)、分界宏之间的消息映射的查找

(3)、椭圆的绘制过程

5、Windows字符集:

(1)、多字节转换为宽字节

(2)、TCHAR自适应编码转换

(3)、统计字符串长度

(4)、char *和CString之间的转换


1、底层实现窗口:

(1)、SDK

软件开发工具包(第三方写好的东西,直接用)。

(2)、API

Windows操作系统提供给应用程序编程的接口。Windows应用程序API函数通过C语言实现,所有主要的Windows函数都在Window.h头文件中声明

(3)、窗口和句柄

窗口:分为客户区和非客户区,窗口可以有父窗口。

句柄:在Windows程序中,各种各样的资源(窗口、图标、光标)都会在创建时候分配内存,然后返回一个标识,标识就是句柄(每个句柄都是独立的),句柄都是以H开头。

(4)、消息和消息队列

例如关闭一个文档,操作系统首先捕获到关闭消息,放入消息队列中,文档程序来接收先进先出的消息,也就是关闭消息。文档把这个消息给操作系统来处理。

(5)、WinMain函数

底层实现,类似于C/C++的main函数。首先头文件Windows.h。

创建一个窗口,并且在窗口中实现键盘鼠标消息,程序的实现步骤为:

1)、WinMain函数的定义

2)、创建一个窗口

3)、进行消息循环(也就是消息和消息队列的循环)

4)、编写窗口过程函数。

2、窗口实现具体的六个步骤:

(1)、设计窗口  WNDCLASS 

首先包含头文件windows.h,然后进入程序入口也就是WinMain函数

#include //底层实现窗口的文件

//程序的入口
//WINAPI代表参数的传递顺序,从右到左,以此入栈,并且在函数返回前清空堆栈

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

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

(3)、创建窗口 creatWindow

//3、创建窗口
	/*
	lpClassName,类名
	lpWindowName,标题名
	dwStyle,WS_OVERLAPPEDWINDOW 风格
	x, y,显示坐标 CW_USEDEFAULT 默认值
	nWidth,宽高
	nHeight,
	hWndParent,父窗口 NULL
	hMenu,菜单 NULL
	hInstance,实例句柄 hInstance
	lpParam
	*/
	HWND hwnd = CreateWindow(
		wc.lpszClassName, TEXT("WINDOWS"), WS_OVERLAPPEDWINDOW,
		CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
		NULL, NULL, hInstance, NULL
	);

(4)、显示和更新 showWindow updateWindow

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

(5)、通过循环取消息 MSG msg

写循环while(1),GetMessage == false 退出循环,翻译消息,分发消息

//5、通过循环取消息

	/*
	HWND        hwnd;主窗口的句柄
	UINT        message;具体的消息名称
	WPARAM      wParam;附加消息,键盘消息
	LPARAM      lParam;附加消息,鼠标消息
	DWORD       time;消息产生出的时间
	POINT       pt;附加消息,鼠标消息x,y
	*/

	MSG msg;

	while (1)
	{
		/*
		_Out_ LPMSG lpMsg, 消息
		_In_opt_ HWND hWnd,捕获窗口,NULL代表捕获所有的窗口
		_In_ UINT wMsgFilterMin,最小和最大过滤的消息
		_In_ UINT wMsgFilterMax 0代表捕获所有的消息
		*/
		if (GetMessage(&msg, NULL,  0, 0) == FALSE)
		{
			break;
		}
		//翻译消息,例如消息是ctrl+c组合键得先翻译。
		TranslateMessage(&msg);
		
		//不为false
		//分发消息
		DispatchMessage(&msg);
	}

(6)、窗口过程,消息处理(回调函数)

补充:

windows API中很多接口都是宽字节版本所以使用多字节编码

1、多字节字符串,使用单字节字符编码(ASCII / UTF-8)在C语言中以NULL结尾。

2、宽字节字符串,使用多字节字符编码(UTF-16 / UTF-32)在C中以null结尾。

3、多字节转换为宽字节:宽字节用TEXT("鼠标按下")或者可以用L"鼠标按下了"。

例如wchar_t wstr[] = L"你好!"(UTF-16编码)

处理宽字节字符串要以w开头例如wprintf

可以通过判断系统是否支持宽字节

#ifdef  _UNICODE

//编译器支持宽字节

#else

//不支持宽字节

#endif

//6、处理消息(窗口过程)
//CALLBACK代表参数的传递顺序,从右到左,以此入栈,并且在函数返回前清空堆栈
LRESULT CALLBACK WindowProc
(
	HWND hwnd,//消息所属的窗口句柄
	UINT uMsg,//具体的消息名称 WM__XXX消息名称
	WPARAM wParam,//键盘附加消息
	LPARAM lparam//鼠标附加消息
)
{
	switch (uMsg)
	{
	case WM_CLOSE:
//所有以xxxWindow为结尾的方式都不会进入到消息队列而是直接执行
		DestroyWindow(hwnd);//发送另一个消息WM_DESTROY
		break;
	case WM_DESTROY://接收之后关闭窗口
		PostQuitMessage(0);
		break;
	case WM_LBUTTONDOWN://鼠标左键按下
	{
		int xPos = LOWORD(lparam);
		int yPos = HIWORD(lparam);

		char buf[1024];
		
		//wsprintf用于宽字节字符串拼接。
		wsprintf(buf,TEXT("x = %d,y = %d"), xPos, yPos);
		
		MessageBox(hwnd, buf, TEXT("鼠标左键按下"), MB_OK);
		//MessageBox需要接收宽字节的字符串作为参数
		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);//结束绘图
		break;
	}
	}
	

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

(7)、底层窗口实现全部代码

#include //底层实现窗口的文件

//6、处理消息(窗口过程)
//CALLBACK代表参数的传递顺序,从右到左,以此入栈,并且在函数返回前清空堆栈
LRESULT CALLBACK WindowProc
(
	HWND hwnd,//消息所属的窗口句柄
	UINT uMsg,//具体的消息名称 WM__XXX消息名称
	WPARAM wParam,//键盘附加消息
	LPARAM lparam//鼠标附加消息
)
{
	switch (uMsg)
	{
	case WM_CLOSE:
		//所有以xxxWindow为结尾的方式都不会进入到消息队列而是直接执行
		DestroyWindow(hwnd);//发送另一个消息WM_DESTROY
		break;
	case WM_DESTROY://接收之后关闭窗口
		PostQuitMessage(0);
		break;
	case WM_LBUTTONDOWN://鼠标左键按下
	{
		int xPos = LOWORD(lparam);
		int yPos = HIWORD(lparam);

		char buf[1024];
		
		//wsprintf用于宽字节字符串拼接。
		wsprintf(buf,TEXT("x = %d,y = %d"), xPos, yPos);
		
		MessageBox(hwnd, buf, TEXT("鼠标左键按下"), MB_OK);
		//MessageBox需要接收宽字节的字符串作为参数
		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);//结束绘图
		break;
	}
	}
	

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

//程序的入口
//WINAPI代表参数的传递顺序,从右到左,以此入栈,并且在函数返回前清空堆栈

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、创建窗口
	/*
	lpClassName,类名
	lpWindowName,标题名
	dwStyle,WS_OVERLAPPEDWINDOW 风格
	x, y,显示坐标 CW_USEDEFAULT 默认值
	nWidth,宽高
	nHeight,
	hWndParent,父窗口 NULL
	hMenu,菜单 NULL
	hInstance,实例句柄 hInstance
	lpParam
	*/
	HWND hwnd = CreateWindow(
		wc.lpszClassName, TEXT("WINDOWS"), WS_OVERLAPPEDWINDOW,
		CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
		NULL, NULL, hInstance, NULL
	);

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

	//5、通过循环取消息

	/*
	HWND        hwnd;主窗口的句柄
	UINT        message;具体的消息名称
	WPARAM      wParam;附加消息,键盘消息
	LPARAM      lParam;附加消息,鼠标消息
	DWORD       time;消息产生出的时间
	POINT       pt;附加消息,鼠标消息x,y
	*/

	MSG msg;

	while (1)
	{
		/*
		_Out_ LPMSG lpMsg, 消息
		_In_opt_ HWND hWnd,捕获窗口,NULL代表捕获所有的窗口
		_In_ UINT wMsgFilterMin,最小和最大过滤的消息
		_In_ UINT wMsgFilterMax 0代表捕获所有的消息
		*/
		if (GetMessage(&msg, NULL,  0, 0) == FALSE)
		{
			break;
		}
		//翻译消息,例如消息是ctrl+c组合键得先翻译。
		TranslateMessage(&msg);
		
		//不为false
		//分发消息
		DispatchMessage(&msg);
	}
	return 0;
}

(8)、运行界面

MFC程序开发_第1张图片

MFC程序开发_第2张图片

3、利用MFC创建窗口:

MFC由C++编写,用底层实现窗口采用C语言编写。编写MFC程序需要包含头文件#include

MFC创建窗口步骤

1、首先包含头文件#include

2、在头文件中声明俩个自定义类MyApp和MyFrame,MyApp继承于CWinApp应用程序类,MyFrame继承于CFrameWnd窗口框架类

3、MyApp包含重写程序的入口 virtual BOOL InitInstance();MyFrame构造函数来初始化窗口

4、在.cpp文件中定义。InitInstance函数创建窗口,显示更新,指针指向自定义窗口,返回正常的初始化。MyFrame构造函数定义初始化窗口。

mfc.h

#include //mfc的头文件

class MyApp:public CWinApp //继承于CWinApp应用程序类
{
public:
	//程序入口
	virtual BOOL InitInstance();

};
class MyFrame:public CFrameWnd//继承于CFrameWnd窗口框架类
{
public:
	MyFrame();//构造函数用来初始化窗口

};





mfc.cpp

#include"mfc.h"

MyApp app;//全局应用程序对象,有且只有一个。
BOOL MyApp::InitInstance() 
{
	//创建窗口
	MyFrame *frame = new MyFrame;

	//显示更新
	frame->ShowWindow(SW_SHOWNORMAL);
	frame->UpdateWindow();

	//通过指针指向自定义的窗口来实现功能
	m_pMainWnd = frame;

	return TRUE;//返回正常的初始化
}

MyFrame::MyFrame() 
{    
    //Create函数是CFrameWnd的函数
	Create(NULL, TEXT("mfc"));//初始化窗口
}

4、消息映射:

消息映射是将消息和函数相关联的表,包含俩个内容,消息ID(独一无二),和对应处理函数。

消息映射的步骤:

1、声明宏写在.h框架类中。声明可以使用消息映射机制。宏为DECLARE_MESSAGE_MAP.

2、分界宏写在.cpp中。分为开始宏和结束宏,中间时要处理的消息映射宏。

     开始宏为BEGIN_MESSAGE_MAP 将消息处理函数和窗口相关联

     中间宏为待处理的消息映射宏,例如鼠标按下消息映射,键盘,绘图

     结束宏为END_MESSAGE_MAP

3、找消息宏写到分界宏中间

4、把函数原型、声明写到.h中

5、函数的实现写到CPP中

6、鼠标键盘绘图等实现。

(1)、具体代码实现 

mfc.h

#include //mfc的头文件

class MyApp:public CWinApp //继承于CWinApp应用程序类
{
public:
	//程序入口
	virtual BOOL InitInstance();

};
class MyFrame:public CFrameWnd//继承于CFrameWnd窗口框架类
{	
	DECLARE_MESSAGE_MAP(); //声明宏, 提供消息机制
public:
	MyFrame();//构造函数用来初始化窗口
	
	//声明鼠标左键按下的消息处理函数
	afx_msg void OnLButtonDown(UINT, CPoint point);
	//afx_msg宏用于标记MyFrame中的OnLButtonDown函数,当窗口接收到鼠标左键按下的消息时,自动调用该函数
	//UNIT消息的类型,这个函数我们不需要使用消息类型
	//CPoint point 参数类型和名称,CPoint时MFC提供的一个类,用于表示二维坐标中的信息

	afx_msg void OnChar(UINT, UINT, UINT);

	afx_msg void OnPaint();
};





mfc.cpp

#include"mfc.h"

MyApp app;//全局应用程序对象,有且只有一个。
BOOL MyApp::InitInstance() 
{
	//创建窗口
	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) 
{	/*
	TCHAR buf[1024];//TCHAR是mfc中的数组
	//将坐标信息格式化到buf里面。
	wsprintf(buf, TEXT("x =%d,y = %d"), point.x, point.y);

	MessageBox(buf);//显示坐标信息对话框
	*/

	//在mfc中封装了一个CString,类似C++ STL
	CString str;
	//str中的方法Format格式化方便信息传入MessageBox中。
	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键"), key);
	MessageBox(str);
}
void MyFrame::OnPaint() 
{
	CPaintDC dc(this);
	dc.TextOutW(100, 100, TEXT("画字"));
	//画椭圆
	dc.Ellipse(10, 10, 100, 100);
	/*
	x1 指定椭圆外接矩形左上角的X逻辑坐标。
	y1 指定椭圆外接矩形左上角的Y逻辑坐标。
	x2 指定椭圆外接矩形右下角的X逻辑坐标。
	y2 指定椭圆外接矩形右下角的Y逻辑坐标。
		*/

}

(2)、分界宏之间的消息映射的查找

(例如查找绘图椭圆)

MFC程序开发_第3张图片

MFC程序开发_第4张图片

MFC程序开发_第5张图片

MFC程序开发_第6张图片

MFC程序开发_第7张图片

(3)、椭圆的绘制过程

x1,y1和x2,y2俩个坐标确定的长方形中间生成的椭圆。

MFC程序开发_第8张图片

5、Windows字符集:

(1)、多字节转换为宽字节

英文 1个字符对应一个字节称为多字节

中文 1个字符对应多个字节称为宽字节(Unicode ,utf-8 3个字节,GBK 2个字节)

多字节转换成宽字节L例如 TEXT("hello")也可以写成 L"hello"。

MFC程序开发_第9张图片

MFC程序开发_第10张图片

MFC程序开发_第11张图片

(2)、TCHAR自适应编码转换

TCHAR:它是一个宏定义,在不同的环境下自动解释为char或者wchar_t,在Unicode编码环境下,TCHAR会被解释为wchar_t,在非Unicode环境下会被解释为char,这样实现代码可移植性。

(3)、统计字符串长度

在非Unicode编码环境下(也就是多字节编码):

int num = 0;
char *p = "aaaa";
num = strlen(p);

在Unicode编码环境下(也就是宽字节编码):

int num = 0;
wchar_t *p = L"bbbbb";//这里可以写成TEXT("bbbb")
num = wcslen(p);

(4)、char *和CString之间的转换

1、首先在C++中有个string类型和char *类型的转换

string类型转换成char *类型

std::string str = "hello";
const char *cstr = str.c_str();
std::cout<< "cstr = "<< cstr << std::endl;

char*类型转换成string类型

const char *cstr = "hello";
std::string str(cstr)//使用拷贝构造,里面函数已经封装好了

char *类型转换成CString类型

char * str = "hello";
CString cstr(str);

CString类型转换成char *类型

CString str = "hello";
CStringA temp;
temp = str;
char *s = temp.GetBuffer();

总结string类型转换成CString类型

//string类型转换成char *
//char *类型转换成CString

string str = "hello"
CString cstr(str.c_str());

wcout << "cstr: " << (LPCTSTR)cstr << endl;

//LPCTSTR 类型转换操作符,把CString对象转换成const TCHAR*类型,用来支持中文输出

CString类型转换成string类型

//CString类型转换成char *
//char *转换成string类型

CString cstr = "hello";
CStringA temp;
temp = cstr;
char * c = temp.GetBuffer();

你可能感兴趣的:(MFC开发,mfc,c++)