学习MFC(1)

在B站上看的是“黑马程序猿MFC教程”

第一集:课程安排

第二集:学习的内容如下图。

  1. 底层实现窗口
    1.1 SDK API 句柄
    1.2 消息处理机制
    1.3 头文件 windows.h
    1.4 程序入口 winMain
  2. 创建窗口程序的6个步骤
    2.1 设计窗口
    2.2 注册窗口
    2.3 创建窗口
    2.4 显示和更新
    2.5 通过循环取消息
        2.5.1 写循环
        2.5.2 GetMessage == false 退出循环
        2.5.3 翻译消息
        2.5.4 分发消息
    2.6 窗口过程
        在下面

        说明,windows应用程序API函数是通过C语言实现的,所以创建底层程序时是用.c为后缀的。这一集的内容是名词解释,windows消息处理机制(重点,可以查看其它资料深入理解,其整个过程下面有图片展示),窗口程序必须包含的头文件,程序的入口winMain及它的参数和创建一个有图形窗口程序的六个步骤。

第三集:学习的内容是上面六个步骤的前五个步骤。

代码如下(下面的代码包括第六个步骤的):

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

//6.处理窗口过程
//CALLBACK   代表__stdcall参数的传递的顺序:从右到左以此入栈,并且在函数返回前清空堆栈
LRESULT CALLBACK WindowProc(
	HWND hwnd,     //消息所属窗口句柄
	UINT uMsg,     //具体消息名称,WM_XXX 消息名
	WPARAM wParam, //键盘附加消息
	LPARAM lParam  //鼠标附加消息
	)
{
	switch(uMsg)
	{
	case WM_CLOSE:
		DestroyWindow(hwnd); //DestroyWindow 发送另一个消息 WM_DESTROY
		break;
	case WM_DESTROY:
		PostQuitMessage(0);
		break;

	case WM_LBUTTONDOWN:    //鼠标左键按下
		{
			int xPos = LOWORD(lParam);
			int yPos = HIWORD(lParam);

			char buf[1024];
			wsprintf((LPTSTR)buf, TEXT("x = %d,y = %d"), xPos, yPos);
			MessageBox(hwnd, (LPTSTR)buf, 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);
			break;
		}
	}

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


//程序入口函数
//WINAPI 代表__stdcall参数的传递顺序:从右到左以此入栈
int WINAPI WinMain(
	HINSTANCE hInstance, //应用程序实例句柄,用来跟踪资源的指针
	HINSTANCE hPrevInstance,//上一个运用程序实例句柄,在win32环境下参数一般为NULL,不起作用
	LPSTR lpCmdLine,//char * argv[]
	int nShowCmd) //窗口的显示命令;有最大化、最小化和正常三种
{
	//1.设计窗口
	//2.注册窗口
	//3.创建窗口
	//4.显示和更新
	//5.通过循环取消息
	//6.处理消息

	HWND hwnd;

	/*MSG结构体成员变量的意义
    HWND        hwnd;    主窗口句柄
    UINT        message; 具体消息名称
    WPARAM      wParam;  附加消息,比如键盘的具体消息
    LPARAM      lParam;  附加消息;鼠标消息,判断左右键
    DWORD       time;    消息产生的时间
    POINT       pt;      附加消息,确定鼠标的位置(x,y)
	*/
	MSG msg;

	//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           附加值 NULL
	*/
	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.通过循环取消息
	while(1)
	{
		/*
		 _Out_ LPMSG lpMsg,       消息
                 _In_opt_ HWND hWnd,      捕获窗口 填NULL代表捕获所有窗口
                 _In_ UINT wMsgFilterMin, 最小和最大的过滤的消息 一般填0
                 _In_ UINT wMsgFilterMax  填0代表捕获所有消息
		*/
		if(GetMessage(&msg, NULL, 0, 0) == FALSE)
		{
			break;
		}
		//翻译消息
		TranslateMessage(&msg);
		//分发消息
		DispatchMessage(&msg);
	}
	//6.处理窗口过程
	return 0;
}

学习MFC(1)_第1张图片 windows信息处理机制

        说明:最重的是不懂的函数要学会查帮助文档。用windows应用程序API方法编码的时候可以查看MSDN(离线两个多G,可以查看在线文档)。在消息处理机制中,从应用程序到操作系统之间,有个分发信息,但是在分发信息之前需要进行信息的翻译,翻译后经过传递又会去消息队列排队。之所以需要翻译,是因为用户在用键盘输入的时候会用到组合键,比如Ctrl+C/V等,需要翻译成对应操作,而不是单纯的字符。

第四集:内容是写出处理窗口过程代码,即写出在窗口设计注释掉的那行代码的回调函数(回调函数的名字可以是其他,只要保证申明定义和调用一致就行)。具体代码如上面。

窗口过程如下:

  1. LRESULT CALLBACK WindowProc
  2. 返回默认处理
  3. return DefWindowProc(hwnd,uMsg,WParam,lParam)
  4. 点击叉子 WM_CLOSE destroy
  5. WM_DESTROY postQuitMessage(0)
  6. 鼠标左键按下
  7. 鼠标按下
  8. 绘图文字

部分代码截图如下:

case WM_CLOSE:
        //所有以xxxWindow为结尾的方法都不会进入消息队列中,而是直接执行
	DestroyWindow(hwnd); //DestroyWindow 发送另一个消息 WM_DESTROY
	break;
case WM_DESTROY:
	PostQuitMessage(0);
	break;

        说明:上面有注释的代码是重点。它的完整过程是这样的:点击窗口的有上面的叉叉按钮,windows系统接收到消息,按照流程第一步、第二步、这个窗口的应用程序处理这个信息,运行到switch()中,DestroyWindow(hwnd)方法运行,发送一个WM_DESTROY的信息,windows系统接收到它,但现在并不去消息列队中排序,而是直接运行第四步窗口过程。(这个只是我自己想的,有待证实)

第五集:开始真的MFC学习了,现在使用的是C++,内容如下:

利用mfc创建窗口:

  1. mfc头文件 afxwin.h
  2. 自定义类 继承与 CWinApp 运用程序类 MyApp app 运用程序对象,有且仅有一个
  3. 程序初始化 InitInstance
  4. 入口类 创建窗口
  5. 窗口类 MyFrame 继承与 CFrameWind
  6. MyFrame 构造中 Create(NULL,标题名称)
  7. 创建窗口对象
  8. 显示和更新
  9. m_pMainWnd = frame  //保存指向运用程序的主窗口的指针
  10. return TRUE
  11. 对项目进行配置 在共享DLL中使用MFC

代码如下:
 

学习MFC(1)_第2张图片

        说明:在写MFC程序时,可能有些函数不懂如何使用,可以下载“VC++之MFC中文类库中文手册”。在查询的具体方法时,可能会找不到,这时候就需要确定该方法的作用域了,有时候可能要确定父类。(需要注意:右键项目 属性->常规->MFC的使用,选择在共享DLL使用MFC)

代码如下:

//mfc.h文件
#include //mfc头文件

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

};

 
//框架类CFrameWnd,派生类(子类)
class MyFrame:public 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(NULL, TEXT("mfc")); //创建窗口
}

第六集:消息映射机制

  1. 声明宏 写到.h中
  2. 分界宏 写到.cpp中
  3. 找消息宏 写到分界宏中间
  4. 把函数原型 声明写到.h中
  5. 函数的实现写到.cpp中
  6. 下面的代码简单实现了鼠标、键盘、绘图事件

mfc.h代码如下:

#include//mfc头文件

//应用程序类CWinApp,派生类(子类)
class MyApp:public CWinApp
{
public:
	//基类的虚函数,派生类只是重写
	//MFC程序的入口函数
	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();
};

mfc.cpp文件代码如下:

#include"mfc.h" //对应类声明的头文件

MyApp app;//全局应用程序对象,有且仅有一个

BOOL MyApp::InitInstance()
{
	//创建窗口
	MyFrame* frame = new MyFrame;
	
	//显示和更新
	frame->showWindow(SW_SHDWNDRMAL);
	fram->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];
	wspprintf(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键"), key);
	
	MessageBox(str);
}

void MyFrame::OnPaint()
{
	CPaintDC dc(this);
	
	dc.TextOutW(100,100,TEXT("为了部落"));
	
	//画椭圆
	dc.Ellipse(10,10,100,100);
	
}

第七集:windows字符集

  1. 多字节 字符串 转宽字节
  2. 声明 宽字节字符串 wchar_t
  3. 统计宽字节字符串 wcslen
  4. TEXT做了自适应编码转换
  5. char* CString之间转换

代码如下:

//字母 1个字符对应一个1字节 多字节
//中文 1个字符对应多个字节 宽字节 (编码不同占用字节也就不同)

//MessageBox("aaa");//这样会报错,因为“aaa”是多字节,而一般vs使用的Unicode编码的(即用的宽字节)
//MessageBox(L"aaa");//就能通过行,和MessageBox(TEXT("aaa"))一样的效果
//TEXT()和TCHER()是自适应编码的转换



//统计字符串长度
int num = 0;
char *p = "aaaa";
num = strlen(p);
	
//统计宽字节的字符串长度
wchar_t *p2 = L"bbbb";
num = wcslen(p2);
	
//char * 与 CString 之间的装换. char * 是string和CString之间的桥梁
//char* -> CString
char *p3 = "ccc";
CString str = CString(p3);
//CString   -> char *
CStringA tmp;
tmp = str;
char *pp = tmp.GetBuffer();

第八集:利用向导创建Mfc项目

  1. view类可以理解成相片,MainFrame类可以理解成相框。所有需要显示的都应该放在view类中,放在MainFrame类中会被view类遮住,看不到。
  2. Create负责注册并产生窗口,创建之后向系统发送WM_Ceate消息,onCreate 响应WM_Ceate。WM_Ceate不产生窗口,只是在窗口显示前设置窗口的属性(如风格,位置等)。
  3. OnDraw和OnPaint如果同时存在,Onpaint会覆盖OnDraw。
  4. MFC中后缀名为Ex的函数都是扩展函数。
  5. 在MFC中,以Afx为前缀的函数都是全局函数,可以在任意地方调用它们(例如:AfxMessageBox()和MessageBox()的区别)。注意小写的afx是不具有这样的属性的。
学习MFC(1)_第3张图片 创建初始界面
学习MFC(1)_第4张图片 注意是单个文档,MFC标准选项

第10,11集:模态(有阻塞)和非模态

基于对话框学习控件:

  1. 两种类型的对话框:模态和非模态。
  2. 学习了按钮这个控件,修改它的的外观名字可以右键选择属性->captain(修改内容);单击选择他直接输入内容。
  3. 点击触发事件->右侧属性->闪电图标;右键按钮->添加事件处理程序;双击按钮
  4. 插入窗口 窗口 右键 添加类
  5. 模态窗口创建 CDlgExec dlg
    5.1 dlg.DoModal()
  6. 非模态创建
    6.1 CDlgShow dlg写到.h做成员
    6.2 dlg.Create写到初始化(oninitDialog)中,保证只创建一次
    6.3 dlg.showWindow()

这次创建的是基于对话框的MFC,所以向导上有所不同,如下:

学习MFC(1)_第5张图片

效果如下:

学习MFC(1)_第6张图片

部分代码如下:

//弹出模态对话框
void CCDialog01Dlg::OnBnClickedButton1()
{
	// TODO: 在此添加控件通知处理程序代码

	CDlgExec dlg;
	dlg.DoModal();
}

//弹出非模态对话框
void CCDialog01Dlg::OnBnClickedButton2()
{
	// TODO: 在此添加控件通知处理程序代码
	//CDlgShow dlg;         //如果写到这里,窗口会一闪而过。所以需要放到CDialog01Dlg.h文件中
	//dlg.Create(IDD_SHOW); //只能创建一次,多次就会崩掉,所以需要放到OnInitDialog()函数中
	dlg.ShowWindow(SW_SHOWNORMAL);
}

 

你可能感兴趣的:(MFC)