开启辅助访问 切换到宽版

精易论坛

 找回密码
 注册

QQ登录

只需一步,快速开始

用微信号发送消息登录论坛

新人指南 邀请好友注册 - 我关注人的新帖 教你赚取精币 - 每日签到


求职/招聘- 论坛接单- 开发者大厅

论坛版规 总版规 - 建议/投诉 - 应聘版主 - 精华帖总集 积分说明 - 禁言标准 - 有奖举报

查看: 1104|回复: 2
收起左侧

[其它] 简易入门MFC

[复制链接]
发表于 2022-7-3 11:39:32 | 显示全部楼层 |阅读模式   广东省潮州市
工作需要用到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的过程,这样会相对麻烦一些。

发表于 2022-7-7 21:59:54 | 显示全部楼层   河南省商丘市
回复 支持 反对

使用道具 举报

结帖率:83% (5/6)
发表于 2022-7-3 12:23:03 | 显示全部楼层   四川省遂宁市
火山 mfc
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则 致发广告者

发布主题 收藏帖子 返回列表

sitemap| 易语言源码| 易语言教程| 易语言论坛| 易语言模块| 手机版| 广告投放| 精易论坛
拒绝任何人以任何形式在本论坛发表与中华人民共和国法律相抵触的言论,本站内容均为会员发表,并不代表精易立场!
论坛帖子内容仅用于技术交流学习和研究的目的,严禁用于非法目的,否则造成一切后果自负!如帖子内容侵害到你的权益,请联系我们!
防范网络诈骗,远离网络犯罪 违法和不良信息举报电话0663-3422125,QQ: 793400750,邮箱:wp@125.la
Powered by Discuz! X3.4 揭阳市揭东区精易科技有限公司 ( 粤ICP备12094385号-1) 粤公网安备 44522102000125 增值电信业务经营许可证 粤B2-20192173

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