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<windows.h> //底层实现窗口的文件

//程序的入口
//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<windows.h> //底层实现窗口的文件

//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)、运行界面

3、利用MFC创建窗口:

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

MFC创建窗口步骤

1、首先包含头文件#include<afxwin.h>

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

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

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

mfc.h

#include<afxwin.h> //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<afxwin.h> //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)、分界宏之间的消息映射的查找

(例如查找绘图椭圆)

(3)、椭圆的绘制过程

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

5、Windows字符集:

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

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

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

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

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

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
MFC(Microsoft Foundation Classes)是面向Windows操作系统的C++应用程序框架,它提供了大量的类库和函数,简化了程序开发过程,提高了开发效率。其中,基于对话框的程序开发MFC应用程序开发中的一种常见方式,本文将介绍基于对话框的MFC程序开发经验以及常用函数。 一、对话框的创建 1. 创建对话框资源文件 在Visual Studio中创建MFC项目时,可以选择“对话框”模板,这样会自动生成一个对话框资源文件。如果需要手动创建,可以在资源视图中右键单击“对话框”文件夹,选择“添加”->“对话框”,然后在弹出的对话框中设置对话框的属性,如对话框标题、大小等。 2. 创建对话框类 要在程序中使用对话框,需要创建对话框类。在资源视图中双击对话框资源文件,Visual Studio会自动生成一个对话框类,一般以CDlg开头。在对话框类中可以添加响应对话框消息的函数,如OnInitDialog()、OnOK()等。 3. 显示对话框 要显示对话框,可以在程序中创建对话框类的对象,并调用DoModal()函数。例如: ``` CDlgDemo dlg; dlg.DoModal(); ``` 这样就会显示一个名为“DlgDemo”的对话框。 二、常用控件 在对话框中可以添加各种控件,如按钮、文本框、列表框等。以下是MFC中常用的控件及其类名: 1.按钮:CButton 2.文本框:CEdit 3.单选按钮:CRadioButton 4.多选框:CCheckBox 5.列表框:CListBox 6.组合框:CComboBox 7.进度条:CProgressCtrl 8.滚动条:CScrollBar 9.静态文本:CStatic 三、常用函数 1.获取控件对象 在对话框类中,可以使用GetDlgItem()函数获取对应控件的指针。例如: ``` CButton* pBtn = (CButton*)GetDlgItem(IDC_BUTTON1); ``` 这样就可以获取ID为IDC_BUTTON1的按钮控件的指针。 2.设置控件文本 可以使用控件对象的SetWindowText()函数设置控件的文本。例如: ``` pBtn->SetWindowText(_T("Click Me")); ``` 这样就会将按钮的文本设置为“Click Me”。 3.获取控件文本 可以使用控件对象的GetWindowText()函数获取控件的文本。例如: ``` CString strText; pBtn->GetWindowText(strText); ``` 这样就可以获取按钮的文本并存储在strText变量中。 4.控件消息响应 在对话框类中可以添加响应控件消息的函数,例如OnClickButton1()。在函数中可以使用控件对象的GetCheck()、SetCheck()等函数获取或设置控件的状态。例如: ``` void CDlgDemo::OnClickButton1() { CButton* pBtn = (CButton*)GetDlgItem(IDC_BUTTON1); BOOL bChecked = pBtn->GetCheck(); pBtn->SetCheck(!bChecked); } ``` 这样就可以实现点击按钮时切换按钮的选中状态。 总之,基于对话框的MFC程序开发是一种简单易用的方式,可以通过添加各种控件和响应函数来实现各种功能。以上介绍的是基本的开发经验和常用函数,更深入的内容需要更多的学习和实践。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值