VC驿站

 找回密码
 加入驿站

QQ登录

只需一步,快速开始

搜索
查看: 899|回复: 2

[分享] 简易入门MFC

[复制链接]
80_avatar_middle
最佳答案
0 
在线会员 发表于 2019-3-20 20:22:31 | 显示全部楼层 |阅读模式
工作需要用到MFC,需要能快速上手,中间碰到不懂的简单的看了下源码,参考了些资料。





目标:做一个简单的计算器,代码就不考虑了,主要强调如何上手MFC,和简单了解MFC的框架。







1.如何创建一个MFC工程项目

创建MFC的过程如下:(visual studio 2012)

1>.新建->项目:选择MFC应用程序,名称这里用test(随意,和后面代码那里一致)。然后点确定。






2>.出现MFC生成向导:这里选择基于对话框,其他默认。






2.界面设计方式

2.1.拖拉控件及修改空间属性

1>.界面设计主要是在这个资源文件中修改。



2>.控件在工具箱中拖拽出来放到界面上。




3>.修改控件属性

单击控件后,可以在属性中修改控件的属性。



常用的属性:

Caption 标题

ID 控件标识




2.2.修改控件布局

这个没查资料,感觉可以设置布局。

界面的左边和上方能控制水平和垂直方向上的自动对齐。

可以在设置好位置后,将控件移动对齐到这个方向的位置,后面拖动这个位置的坐标就可以进行整体对齐移动了。






3.控件的事件回调函数处理

双击控件,可自动跳转到点击控件的事件回调处理函数。

可以在跳转到的函数回调上编写处理代码:

void CtestDlg::OnBnClickedButton1()

{

// TODO: 在此添加控件通知处理程序代码

CString str = NULL;

GetDlgItemText(IDC_EDIT1, str);

SetDlgItemText(IDC_EDIT1, str+_T("1"));

}

这里在界面上除自身的代码外比较常用的就是这些属性相关(设置和获取)的函数。

这部分可以通过搜索引擎或者MSDN解决。




4.粗略分析自动生成的代码

4.1.关于自动生成的几个类

这里可能涉及到框架的部分程序了,这里做简单的了解。

首先最简单的Dialog中间有这几个类:CAboutDlg,CtestApp,CtestDlg。

其中CAboutDlg类和CtestDlg类被放到了testDlg.cpp中实现。



1>.CAboutDlg

CAboutDlg是用于应用程序“关于”菜单项的 CAboutDlg 对话框。估计是这个关于的对话框。在.rc的资源中的dialog中的IDD_ABOUTBOX中可修改。。



这部分是CAboutDlg的代码,可以看出一个简单的对话框窗口:

1.继承CDialogEx类;

2.有自己的映射关系;

3.DoDataExchange函数;这个函数在MFC框架中的UpdateData会调用。

参见:https://baike.baidu.com/item/DoDataExchange/4417615?fr=aladdin

4.类中声明的IDD枚举???




class CAboutDlg : public CDialogEx

{

public:

CAboutDlg();

enum { IDD = IDD_ABOUTBOX };// 对话框数据




protected:

virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持




// 实现

protected:

DECLARE_MESSAGE_MAP()

};




CAboutDlg::CAboutDlg() : CDialogEx(CAboutDlg::IDD){}




void CAboutDlg::DoDataExchange(CDataExchange* pDX)

{

CDialogEx::DoDataExchange(pDX);

}




BEGIN_MESSAGE_MAP(CAboutDlg, CDialogEx)

END_MESSAGE_MAP()




2>.CtestDlg

所以CtestDlg应该是主界面的代码。结构和上述类似。只是增加了几个消息回调函数。但中间有结果回调函数比较特殊。应该是和后面几个消息回调连着的,可能不需要给用户自定义,连名字都省略了= =

afx_msg void OnSysCommand(UINT nID, LPARAM lParam);

afx_msg void OnPaint();

afx_msg HCURSOR OnQueryDragIcon();

注:afx_msg 是个标识,来表示MFC的消息处理




OnQueryDragIcon从注释上意思:当用户拖动最小化窗口时系统调用此函数取得光标

OnPaint从注释上意思:来绘制该图标。对于使用文档/视图模型的 MFC 应用程序。在初始化后会向窗口发送WM_PAINT消息,然后框架自动回调。这部分的代码也是由框架封装好的CDialogEx::OnPaint(),可以跳转进去看看,用来绘制图形的。



OnSysCommand不详。。。

另外:BOOL CtestDlg::OnInitDialog()是初始化消息的回调函数。用来初始化窗口。




3>.CtestApp

CtestApp类在test.h/test.c中,继承了CWinApp,定义应用程序的类行为,且有唯一一个对象theApp,在一开始就会被构造。

这个类中的构造函数添加了支持重新启动管理器的flag。

另一个方法是初始化实例InitInstance。




这里需要提到MFC框架的入口和初始化过程:

theApp在一开始就被构造,初始化了一些变量,然后将当前应用指到本身。

MFC的入口在源代码的APPMODUL.CPP文件中的_tWinMain函数中。_tWinMain中调用了AfxWinMain函数。

AfxWinMain为一个MFC框架的全局函数。在这个函数中模仿了WIN32的创建一个应用的过程:

1.获得一个CWinThread和app的指针(CWinApp也是继承CWinThread的,通过宏可知这两个指针一样。)

2.通过APP指针初始化应用(InitApplication),初始化CWinThread指针的实例(InitInstance方法)。

InitApplication做框架的内部管理工作。

这里InitInstance方法就调用CtestApp重写的部分(这部分代码其实也是系统自动生成的)。这个函数完成了窗口CtestDlg创建,显示,并向窗口发送WM_PAINT消息的功能。

注:这里好像不同的写法(使用方式)中间的调用过程也不大一样。如果是前面那种方式在DoModal里就调用了DoDataExchange函数来加载资源??

3.运行theApp




4.2.关于函数回调部分的代码

前面说双击回调后,会自动跳转生成的代码。这里自动生成的部分主要有:

回调处理函数:

void CtestDlg::OnBnClickedButton1()

{

// TODO: 在此添加控件通知处理程序代码

}




关系映射:

BEGIN_MESSAGE_MAP(CtestDlg, CDialogEx)

ON_WM_SYSCOMMAND()

ON_WM_PAINT()

ON_WM_QUERYDRAGICON()

ON_BN_CLICKED(IDC_BUTTON1, &CtestDlg::OnBnClickedButton1)

ON_BN_CLICKED(IDC_BUTTON2, &CtestDlg::OnBnClickedButton2)

ON_BN_CLICKED(IDC_BUTTON3, &CtestDlg::OnBnClickedButton3)

ON_BN_CLICKED(IDC_BUTTON4, &CtestDlg::OnBnClickedButton4)

ON_BN_CLICKED(IDC_BUTTON5, &CtestDlg::OnBnClickedButton5)

ON_BN_CLICKED(IDC_BUTTON6, &CtestDlg::OnBnClickedButton6)

ON_BN_CLICKED(IDC_BUTTON7, &CtestDlg::OnBnClickedButton7)

ON_BN_CLICKED(IDC_BUTTON8, &CtestDlg::OnBnClickedButton8)

ON_BN_CLICKED(IDC_BUTTON9, &CtestDlg::OnBnClickedButton9)

ON_BN_CLICKED(IDC_BUTTON10, &CtestDlg::OnBnClickedButton10)

END_MESSAGE_MAP()




声明:

afx_msg void OnEnChangeEdit1();




调到宏里面看看原理:(截取了一段button的)

// User Button Notification Codes

#define ON_BN_CLICKED(id, memberFxn) \

ON_CONTROL(BN_CLICKED, id, memberFxn)

#define ON_BN_DOUBLECLICKED(id, memberFxn) \

ON_CONTROL(BN_DOUBLECLICKED, id, memberFxn)

#define ON_BN_SETFOCUS(id, memberFxn) \

ON_CONTROL(BN_SETFOCUS, id, memberFxn)

#define ON_BN_KILLFOCUS(id, memberFxn) \

ON_CONTROL(BN_KILLFOCUS, id, memberFxn)




定义了几种动作的宏(每种控件间会有差异),将控件标识和对应的动作类型和对应的响应回调函数连接起来。宏里面的结构如下,看上去像一个表的形式。

// for general controls

#define ON_CONTROL(wNotifyCode, id, memberFxn) \

{ WM_COMMAND, (WORD)wNotifyCode, (WORD)id, (WORD)id, AfxSigCmd_v, \

(static_cast< AFX_PMSG > (memberFxn)) },




5.其他注意事项

5.1.关于命名的问题

命名的规则:










5.2.MFC自定义的类型

第一次用MFC中,出现了一些类型,比如CString,可以在afx.h头文件中查看它的定义。另外使用MSDN可以查看。

另外:这里要注意字符集的问题。可以用_T("XXXX")来统一字符集。




5.3.窗口中定义的控件

拖进界面生成的控件的资源被,按照一定的组织格式放在了test.rc这个文件中。MFC框架中在CtestApp::InitInstance()里就加载这个.rc的文件的部分并进行了显示。

注*:这里的控件也可在窗口创建的回调函数中创建。只不过这里的方法不同。




5.4.关于一些辅助的宏

看到了随便加进来一下:

①.TRACE

TRACE(traceAppMsg, 0, "警告: 对话框创建失败,应用程序将意外终止。\n");

追踪路径,先看TRACE的定义:

#define TRACE ATLTRACE

#define ATLTRACE ATL::CTraceFileAndLineInfo(__FILE__, __LINE__)

        void __cdecl operator()(

        _In_ DWORD_PTR dwCategory,

        _In_ UINT nLevel,

        _In_z_ const char *pszFmt,

        ...) const

        {

        va_list ptr; va_start(ptr, pszFmt);

        ATL::CTrace::s_trace.TraceV(m_pszFileName, m_nLineNo, dwCategory, nLevel, pszFmt, ptr);

        va_end(ptr);

        }

再往下好像封装进去了,大概可以通过这个宏,可以把追踪信息文件,行数,必要的提示,警告等级之类的都显示下来。

TRACE宏只对Debug 版本的工程产生作用。

参考:https://blog.csdn.net/ghevinn/article/details/17550707




②.ASSERT

编写代码时,我们总是会做出一些假设,断言就是用于在代码中捕捉这些假设,可以将断言看作是异常处理的一种高级形式。断言表示为一些布尔表达式,程序员相信在程序中的某个特定点该表达式值为真。可以在任何时候启用和禁用断言验证,因此可以在测试时启用断言,而在部署时禁用断言。同样,程序投入运行后,最终用户在遇到问题时可以重新启用断言。

参考:https://baike.baidu.com/item/assert/10931289?fr=aladdin




看看MFC中的ASSERT。

#define ASSERT(f) DEBUG_ONLY((void) ((f) || !::AfxAssertFailedLine(THIS_FILE, __LINE__) || (AfxDebugBreak(), 0)))

#define DEBUG_ONLY(f) (f)

相当于DEBUG模式下,直接判断ASSERT中的表达式f是否满足条件。如果满足表达式满足,就会调用AfxAssertFailedLine,然后中断退出。




6.相关参考

VC++深入讲解

参考:https://blog.csdn.net/nodeman/article/details/43565921




7.总结

在大致看完之后,MFC其实就是Windows下的API进行进一步的封装。如果直接在.rc文件中设计,只需添加对应的回调函数再加处理即可。这样比较快。

另外一种是对MFC提供出来的框架的部分进行重写(根据自己需求),但大体上也是封装Windows的API的过程,这样会相对麻烦一些。

评分

参与人数 4驿站币 +4 热心值 +4 收起 理由
02_avatar_small leosheng + 1 + 1
05_avatar_small 2239065859 + 1 + 1
03_avatar_small 1481710154 + 1 + 1
06_avatar_small 133008870 + 1 + 1

查看全部评分





上一篇:C++类(Class)总结
下一篇:MFC六大核心机制
60_avatar_middle
最佳答案
0 
在线会员 发表于 2019-6-12 22:28:37 | 显示全部楼层
感谢分享!学习学习啦!好好学习天天向上!
您需要登录后才可以回帖 登录 | 加入驿站 qq_login

本版积分规则

×【发帖 友情提示】
1、请回复有意义的内容,请勿恶意灌水;
2、纯数字、字母、表情等无意义的内容系统将自动删除;
3、若正常回复后帖子被自动删除,为系统误删的情况,请重新回复其他正常内容或等待管理员审核通过后会自动发布;
4、感谢您对VC驿站一如既往的支持,谢谢合作!

关闭

站长提醒上一条 /2 下一条

QQ|小黑屋|手机版|VC驿站 ( 辽ICP备09019393号 )|网站地图wx_jqr

GMT+8, 2020-9-21 00:56

Powered by CcTry.CoM

© 2009-2020 cctry.com

快速回复 返回顶部 返回列表