第三课——MFC编程
一、MFC概述
1. MFC简述
MFC不仅仅是一套基础类库,更是一种编程方式。
2. MFC由来
1987年微软公司推出了第一代Windows产品,并为应用程序设计者提供了Win16(16位Windows操作系统)API,在此基础上推出了Windows GUI(图形用户界面),然后采用面向对象技术对API进行封装。
1992年推出应用程序框架产品AFX(Application Frameworks),并在AFX的基础上进一步发展为MFC产品。故在用MFC应用程序向导创建的程序中仍然保留stdafx.h头文件包含,它是每个应用程序所必有的预编译头文件,程序所用到的Visual C++头文件包含语句一般均添加到这个文件中。
3. MFC类的基本层次结构
图示:

CObject类是MFC提供的绝大多数类的基类。该类完成动态空间的分配与回收,支持一般的诊断、出错信息处理和文档序列化等。
CCmdTarget类主要负责将系统事件(消息)和窗口事件(消息)发送给响应这些事件的对象,完成消息发送、等待和派遣(调度)等工作,实现应用程序的对象之间协调运行。
CWinApp类是应用程序的主线程类,它是从CWinThread类派生而来。CWinThread类用来完成对线程的控制,包括线程的创建、运行、终止和挂起等。
CDocument类是文档类,包含了应用程序在运行期间所用到的数据。
CWnd类是一个通用的窗口类,用来提供Windows 中的所有通用特性、对话框和控件。
CFrameWnd 类是从 CWnd 继承来的,并实现了标准的框架应用程序。
CDialog 类用来控制对话框窗口。
CView 是用于让用户通过窗口来访问文档以及负责文档内容的显示。
CMDIFrameWnd和CMDIChildWnd类分别用来多文档应用程序的主框架窗口和文档子窗口的显示和管理。
CMiniFrameWnd类是一种简化的框架窗口,它没有最大化和最小化窗口按钮,也没有窗口系统菜单,一般很少用到它。
4. MFC的优势
读到本文最后,可得出如下结论:使用MFC
①可减少Windows应用程序的代码量;
②通过消息映射机制使消息处理更为方便;
③能很好地体现面向对象编程的优点。
二、MFC程序框架
——写在理解MFC机制之前
下面是一个MFC应用程序:
#include <afxwin.h> // MFC头文件
class CHelloApp : public CWinApp // 声明应用程序类
{
public:
virtual BOOL InitInstance();
};
CHelloApp theApp; // 建立应用程序类的实例
class CMainFrame: public CFrameWnd // 声明主窗口类
{
public:
CMainFrame()
{
// 创建主窗口
Create(NULL, "我的窗口", WS_OVERLAPPEDWINDOW, CRect(0, 0, 480, 320));
}
protected:
afx_msg void OnPaint();
DECLARE_MESSAGE_MAP()
};
// 消息映射入口
BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd)
ON_WM_PAINT() // 绘制消息宏
END_MESSAGE_MAP() //定义消息映射函数
void CMainFrame::OnPaint()
{
CPaintDC dc(this);
CRect rc;
GetClientRect(&rc);
dc.DrawText(_T("Hello MFC!"), -1, &rc, DT_SINGLELINE | DT_CENTER | DT_VCENTER);
}
// 每当应用程序首次执行时都要调用的初始化函数
BOOL CHelloApp::InitInstance()
{
m_pMainWnd = new CMainFrame();
m_pMainWnd->ShowWindow(m_nCmdShow);
m_pMainWnd->UpdateWindow();
return TRUE;
}
三、程序运行机制
0. 上面程序中的关系梳理
- 应用程序类:CHelloApp(公有继承自CWinApp)
- 应用程序类的实例:theApp
- 主窗口类:CMainFrame(公有继承自CFrameWnd)
1. MFC使用afxwin.h来代替头文件windows.h,在此程序中看不到Windows应用程序所必须的入口函数WinMain,这是因为MFC将它隐藏在应用程序框架内部了。
2. 当用户运行应用程序时,Windows会自动调用应用程序框架内部的WinMain函数,并自动查找应用程序类CHelloApp(从CWinApp派生)的全局变量theApp,然后自动调用CHelloApp的虚函数InitInstance,该函数会进一步调用相应的函数来完成主窗口的构造和显示工作。
- 重点:运行应用程序→WinMain+theApp→InitInstance(Create/ShowWindow/UpdateWindow)
3. 上面程序中InitInstance的执行过程(创建窗口+显示窗口+更新窗口)如下:
① m_pMainWnd = new CMainFrame();
该语句的作用:创建从CFrameWnd类派生而来的用户框架窗口CMainFrame类对象,继而调用该类的构造函数,使得Create函数被调用,完成窗口创建工作。
② m_pMainWnd->ShowWindow(m_nCmdShow);
m_pMainWnd->UpdateWindow();
此两条语句的作用:用作窗口的显示和更新
③ 返回TRUE,表示窗口创建成功
4. InitInstance完成初始化工作之后,接下来就是调用CWinApp的成员函数Run,执行应用程序的消息循环,即重复执行接收消息并转发消息的工作。
笔记:InitInstance之后是Run,Run是用来处理消息的。
当Run检查到消息队列为空时,将调用基类CWinApp的成员函数OnIdle进行空闲时的后台处理工作。若消息队列为空且又没有后台工作要处理时,则应用程序一直处于等待状态,一直等到有消息为止。
5. 当程序结束后,调用基类CWinApp的成员函数ExitInstance,完成终止应用程序的收尾工作。
6. 尚待考究:既然MFC方式使用消息映射机制,那为何还要使用Run来处理消息?
四、消息映射
1. 区别于之前的消息处理机制
在MFC中,不再使用消息循环代码以及在窗口过程函数中的switch结构来处理Win32的消息,而是使用独特的消息映射机制。
2. 何为消息映射
所谓消息映射(Message Map)机制,就是将MFC类中的消息与消息处理函数一一对应起来的机制。
在MFC中,任何一个从CCmdTarget派生的类理论上均可处理消息,且都有相应的消息映射函数。(即每个类都有相应的消息映射函数)
3. 映射一个消息的过程
① 在处理消息的类中,使用消息宏DECLARE_MESSAGE_MAP()声明对消息映射的支持,并在该宏之前声明消息处理函数。
举例:
protected:
afx_msg void OnPaint();
DECLARE_MESSAGE_MAP()
② 使用BEGIN_MESSAGE_MAP和END_MESSAGE_MAP宏在类声明之后的地方定义该类支持的消息映射入口点,所有消息映射宏都添加在这里,当然不同的消息MFC都会有不同的消息映射宏。
举例:
BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd)
...
END_MESSAGE_MAP()
其中,BEGIN_MESSAGE_MAP带有两个参数。第一个参数:用来指定需要支持消息映射的用户派生类;第二个参数:指定该类的基类。
③ 定义消息处理函数(此例中OnPaint为消息处理函数)
void CMainFrame::OnPaint()
{
CPaintDC dc(this);
CRect rc;
GetClientRect(&rc);
dc.DrawText(_T("Hello MFC!"), -1, &rc, DT_SINGLELINE | DT_CENTER | DT_VCENTER);
}
注意:为了使该消息能被其他对象接收并处理,在函数中常常需要调用基类中的相关消息处理函数。
补充:
应用程序类:继承自CWinApp类
消息映射机制:将消息与消息处理函数相对应的机制
消息宏:DECLARE_MESSAGE_MAP(),使用它声明对消息映射的支持
消息映射入口点:由BEGIN_MESSAGE_MAP和END_MESSAGE_MAP宏在类声明之后定义入口点,而所有消息映射宏都添加在此
消息映射宏:不同的消息MFC都有不同的消息映射宏,如ON_WM_PAINT
消息处理函数:如OnPaint,该函数的声明必须在消息宏之前
彩蛋:
在Visual C++ 6.0中不需要输入上述程序代码(其实不需要输入任何代码),就能创建所需要的应用程序!!
这就是MFC应用程序向导(MFC AppWizard)的功能。
上面只是拓宽你的视野!!!
具体MFC对应用程序项目的管理方式见下一课。
第三课——MFC编程的更多相关文章
- Python编程学习第三课之编程从Hello World开始
在搞定了前几节课的情况下,大家是否有一种想要跃跃欲试的赶脚,接下来就是我们开始练手的实战时刻. 每个编程人员入门编程的第一课都是向我们马上要进入的编程世界问好,"你好,世界"英文说 ...
- 第三课 java编程入门
java特点: 1.面对象性 2.可移植性/跨平台性 java组成: jdk(java工具开发工具包) / \ \ jre 指令集合 api和常用 ...
- VS2010/MFC编程入门教程之目录和总结
鸡啄米的这套VS2010/MFC编程入门教程到此就全部完成了,虽然有些内容还未涉及到,但帮助大家进行VS2010/MFC的入门学习业已足够.以此教程的知识为基础,学习VS2010/MFC较为深入的内容 ...
- MFC学习-第一课 MFC运行机制
最近由于兴趣爱好,学习了孙鑫的MFC教程的第一课.看完视频了,自己便用visual studio 2010尝试了MFC编程,其中遇到了一些问题. 1.vs2010不像vs6.0那样可以新建一个空的MF ...
- shellKali Linux Web 渗透测试— 初级教程(第三课)
shellKali Linux Web 渗透测试— 初级教程(第三课) 文/玄魂 目录 shellKali Linux Web 渗透测试—初级教程(第三课) 课程目录 通过google hack寻找测 ...
- MFC编程基础
http://www.cnblogs.com/lzmfywz/archive/2012/03/15/2399403.html 一.MFC类库概述 MFC(Microsoft Foundation cl ...
- VS2010/MFC编程入门之五(MFC消息映射机制概述)
VS2010/MFC编程入门之五(MFC消息映射机制概述)-软件开发-鸡啄米 http://www.jizhuomi.com/software/147.html 上一讲鸡啄米为大家简单分析了MFC应用 ...
- VS2010/MFC编程入门之二(利用MFC向导生成单文档应用程序框架)
VS2010/MFC编程入门之二(利用MFC向导生成单文档应用程序框架)-软件开发-鸡啄米 http://www.jizhuomi.com/software/141.html 上一讲中讲了VS20 ...
- VS2010/MFC编程入门之一(VS2010与MSDN安装过程图解)
原文地址: VS2010/MFC编程入门之一(VS2010与MSDN安装过程图解)-软件开发-鸡啄米 http://www.jizhuomi.com/software/139.html 上一讲中鸡 ...
随机推荐
- TinyMCE插件:RESPONSIVE filemanager 9 文件名统一格式化
上传图片方法(filemanager/UploadHandler.php) 在上传图片的函数中查看,发现$file->name是一个完整的[文件名.后缀名],所以使用explode(),文件名和 ...
- JSP工作流程
情况1:第一次请求一个页面 情况2:该页虽然是再次请求,但已经过修改 情况3:该页面是再次请求且未被修改
- 新人成长之入门Vue.js常用指令介绍(一)
写在前面 作为一个刚步入职场工作的新人,对于公司中所用的技术和框架基本上不懂,只能从最基础的开始做起,进入公司接触的第一个框架就是前端框架Vue.js,几个功能做下来,觉得Vue.js首先学习起来真的 ...
- 【淘宝客】批量提取QQ号
1:打开QQ群官方,网址:http://qun.qq.com/ 2.点击导航栏:群管理 3.点击成员管理,选择需要提取QQ号的群 4.全选复制群成员 5.打开网址:http://tool.oschin ...
- MP3 编码解码 附完整c代码
近期一直不间断学习音频处理,一直也没想着要去碰音频编解码相关. 主要是觉得没什么实际的作用和意义. 不管视频编解码,图像编解码,音频编解码,都有很多组织基金在推动. 当然,在一些特定的情景下,需要用起 ...
- java 获取目标时间到当前时间中间的月份和每月最大时间
话不多说自己上代码: Date firstDate = DateUtil.formate("2018-01-01", "yyyy-MM-dd"); Date c ...
- canvas画的文字在安卓移动设备上可以显示,但是在ios移动设备上无法显示
不用担心iOS Safari不支持canvas,查看https://caniuse.com/ 发现是支持的 ctx.font = "0.16rem Arial"; 为了适配移动端直 ...
- 长沙Uber优步司机奖励政策(12月28日到1月3日)
滴快车单单2.5倍,注册地址:http://www.udache.com/ 如何注册Uber司机(全国版最新最详细注册流程)/月入2万/不用抢单:http://www.cnblogs.com/mfry ...
- SDWebImage的原理 和 实现机制 --- tableView 滑动卡的问题
一.原理 1)当我门需要获取网络图片的时候,我们首先需要的便是URl没有URl什么都没有,获得URL后我们SDWebImage实现的并不是直接去请求网路,而是检查图片缓存中有没有和URl相关的图片,如 ...
- [Jmeter]jmeter之BeanShell Sampler测试应用
前言: 在做接口测试的时候,有些接口做了签名校验,而签名是根据某算法进行加密,这时候,简单的接口测试工具无法完成该工作,所以想到了Jmeter,他是java编写,有强大的扩展性,足矣完成我们需要的操作 ...