引言

本文致力于提供MFC的相关知识,以方便大家更好地认识MFC的使用方法。介绍将会分为以下几个部分:MFC初始文件的理解、MFC我们所使用的框架理解、MFC的进阶用法、MFC我在使用过程中遇到的问题及解决方法。

MFC初始文件的理解

MFC的初始文件中有两项文件是我们经常需要使用的,其余文件可以暂时忽略,我们基本不会用上。一个是MFCApplicationView,我们简称View类,一个是MFCApplicationDoc,我们简称Doc类。

Doc类是Document的缩写,是用来处理程序与计算机文件的关系的,我们读取、保存文件就是通过这个类实现的,我们如果想要获取读取的图像信息,也都是通过Doc类进行读取的。例如以下这个我们常用的代码段。

 CMFCApplication1Doc* pDoc = GetDocument();// 获取文档      //long  lSrcLineBytes;      //图象每行的字节数long  lSrcWidth;      //图象的宽度和高度long  lSrcHeight;int     lpSrcBitCount;       //图像的位深LPSTR    lpSrcDib;       //指向源图象的指针  LPSTR   lpSrcStartBits; //指向源像素的指针lpSrcDib = (LPSTR) ::GlobalLock((HGLOBAL)pDoc->GetHObject());// 锁定DIBif (!lpSrcDib) return;/*if (pDoc->m_dib.GetColorNum(lpSrcDib) != 256)// 判断是否是8-bpp位图{AfxMessageBox(L"对不起,不是256色位图!");// 警告::GlobalUnlock((HGLOBAL) pDoc->GetHObject());// 解除锁定return;                                 //返回}                                       //判断是否是8-bpp位图,不是则返回*/lpSrcStartBits = pDoc->m_dib.GetBits(lpSrcDib);           // 找到DIB图象像素起始位置    lSrcWidth = pDoc->m_dib.GetWidth(lpSrcDib);                 // 获取图象的宽度      lSrcHeight = pDoc->m_dib.GetHeight(lpSrcDib);                   // 获取图象的高度  lpSrcBitCount = pDoc->m_dib.GetBitCount(lpSrcDib);                    //获取图像位深lSrcLineBytes = pDoc->m_dib.GetReqByteWidth(lSrcWidth * lpSrcBitCount);       // 计算图象每行的字节数
///

其中GetDocument()函数是View类的函数,其功能就是提取先前Doc类已经读取好的内容(通过指针直接读取Doc类的内存)而此后的pDoc->m_dib是CDib类,CDib的功能是存储图像信息。

为什么信息存放在CDib中而不是直接存放在Doc类中,这是个值得思考的问题,大家可以通过查看两个类中定义好的函数,感知一下两个类功能上的差别,这个差别很难准确描述。

View类是一个用于与用户交互的类,其功能包含很广泛,比如用户按下某个选项后应该进行什么函数操作(其实就是我们做的部分)、弹窗、鼠标的形状改变等。

如果要进行一个比较形象的比喻,View类是前端,Doc类是后端。

MFC我们所使用的框架理解

我们使用的MFC框架基本流程如下:

在菜单MENU中(你可以理解为View类给出的对话框),我们可以定义选项卡,命名为ID_名字。我们在View类事件中直接添加COMMAND,可以添加该ID的On函数,并自己编写改函数。我们所编写的函数体将会在这个选项卡被点击后执行。执行的内容可以是直接进行某项操作,例如弹出对话框,也可以调用指定的对话框类函数(可以不调用)。

其实以上这一部分理解了之后我们就已经可以进行很多功能的实现了,只是为了让我们与用户的交互性更强,我们需要定义对话框类来收集用户想要输入的信息。(一般情况下,对话框类只负责收集信息,收集完信息后,我们仍需要在View类中处理这个输入对应的结果)

搭建对话框类的时候,我们需要在Dialog中创建一个IDD_名字,这个东西是我们的设计页面。

在进行页面设计的过程中,最好对同一组物体按照顺序生成,如我想要创建三个单选框,我就直接按顺序创建IDC_RADIO1、IDC_RADIO2、IDC_RADIO3,而不是在创建IDC_RADIO1后创建一个文本框,再创建IDC_RADIO2,或者创建IDC_RADIO1、IDC_RADIO2之后,删掉IDC_RADIO2再创建一个。设计页面的时候最好提前构思,少做修改,因为我们创建的所有控件都会在后台有一个数字ID,例如IDC_RADIO1可能对应1001,那么IDC_RADIO2就会对应1002,用于让电脑快速识别,不按照顺序创建可能会打乱这个ID,影响以后的操作。

在设计完页面之后,我们需要先创建类,右键对话框直接创建一个CDlg名字类就行。创建完毕后,我们可以直接在IDD页面添加成员变量,在CDlg类中添加对话框函数与控件函数,也可以通过类向导构建。类向导构建的速度更快,上手之后使用会很方便。

下图就是类向导页面,我们可以观察资源这里是不是我们想要的IDD名称,如果是ABOUTBOX,说明你还没有添加类,一定要添加类才能使用类向导。类向导有五个部分组成,命令、消息、虚函数、成员变量、方法。方法一般用不到,我不做解释。

其中,命令是用于添加控件函数的,包含了所有的ID,里面有很多是不需要我们管的,我也不知道为什么他不进行一个筛选。我们可以手动翻看IDC开头的所有ID,如果某个对象的消息函数不是只有上图所示的这两个消息的时候,就说明这个ID是我们的IDD页面里面的控件,可以放心添加函数了。

消息包含了所有的对话框的消息函数,比如你按下鼠标的时候(OnLButtonDown)、抬起鼠标的时候(OnLButtonUp),移动鼠标的时候对应的函数。(OnMouseMove)。虚函数则是系统定义过了,我们可以重写的函数,比如OnInitDialog(初始化函数)、OnOK(按下确定按钮后发生的事情)。消息和虚函数的差别就是,消息函数都是可有可无的函数,我移动鼠标可以有函数,也可以没有。而虚函数都是必须有的函数,你没写,系统就会用他默认的那一套。

成员变量就不用细说了,每个控件可以添加一个值与一个CButton类的控件。CButton类的控件可以控制这个控件的状态。下面这个框里的可见,禁用,只读什么的应该都能控制。值就是值,是控件的内容,是编辑框的值,是单选框的序号。

针对单选框,有一个需要注意的地方。单选框是有组选项的,我们可以通过设置第一个单选框的组为TRUE,第N+1个为TRUE,来让第一个到第N个单选框的成为一组。如果不需要分多组,只需要让第一个单选框的组为TRUE,其余全为FALSE即可。这一切的大前提是你的RADIO的ID是按照顺序来的,没有乱,不然计算机就没法将他们识别为一组了。

在类向导中,一组的单选框只有第一个能设置成员变量与函数,我也不知道为什么,但是你可以通过手动添加函数的方式,在CDlg类中直接添加。对于单选框来说,值就是他们的序号,当你按下第一个单选框,值会变成0,按下第二个,值会变成1,按下第N个,值会变成N-1。

在创建完对话框类类,添加完对话框类函数、每个控件的变量与函数之后,我们需要将对话框类添加到View类中。我们需要在View类中添加头文件以导入对话框类,然后通过函数去调用,一般函数如下:

 CDIG名字 dlgPara;// 创建对话框     dlgPara.变量= View里的变量;//导入一些对话框需要的变量,比如图像数据之类的if (dlgPara.DoModal() != IDOK)// 显示对话框, {return;}View里的变量 = dlgPara.变量;//将对话框的变量导出来,我们可以通过这个知道用户输入了什么,并进行相应的操作//此处有处理函数pDoc->SetModifiedFlag(true);pDoc->UpdateAllViews(NULL);//是否保存更改后的图像

其中if(dlgPara.DoModal()!=IDOK){return;}的作用是,打开对话框,并在关闭对话框后结束这个语句。

综上所述,实际上整个框架的流程是:View类控制Doc类读取文件内容,点击选项卡,(View类调用对话框,人输入信息),View类处理相关操作。

MFC的进阶用法

一些常规的操作使用MFC的基本框架是很难实现的,我分享一些我用到的、大家经常看到但是不知道什么用的函数与操作。
        1、UpdateData()

此函数经常出现于对话框类中,UpdateData其实是用于控制控件上显示的值(如编辑框中用户输入的值)与后台存储的值之间转化用的。UpdateData(TRUE)会将编辑框中的值全部复制到后台存储的值(其实就是你这个控件添加的那个值变量);UpdateData(FALSE)会将后台存储的值复制到编辑框中,形成一个交互的作用。

2、BeginWaitCursor()

这个函数是View类中的函数,用处是将鼠标变成转圈圈的等待状态,可以用EndWaitCursor()取消等待状态。如果有些函数的时间复杂度比较高,可以考虑在函数前BeginWaitCursor(),结束后EndWaitCursor()。

3、预览图像

预览图像的操作在传统框架中很难实现。因为按照我们之前的框架的逻辑,我们在结束对话框前是不会进行图像的处理操作的,因为我们的对话框只是收集数据。如果我们想要在对话框内修改数据,就必须面临一个问题:如果将在对话框中调用pDoc的函数,毕竟我们至少要使用

pDoc->SetModifiedFlag(true);
    pDoc->UpdateAllViews(NULL);//是否保存更改后的图像

这两个函数才可以。

方法很简单,就是传参。我们在对话框.h文件中加入头文件#include "MFCApplication1Doc.h",并在对话框类的public中添加    CMFCApplication1Doc* m_pDoc;成员变量,最后只需要在View类中输入    dlgPara.m_pDoc = pDoc;即可。以下是我编写的一个View类中的选项函数的例子:

void CMFCApplication1View::OnStylize()
{CMFCApplication1Doc* pDoc = GetDocument();// 获取文档 CDlgStylize dlgPara;// 创建对话框    dlgPara.m_pDoc = pDoc;if (dlgPara.DoModal() != IDOK)// 显示对话框 {return;}
}

剩下的我们就只需要在对话框类中预览图像按钮的OnClickButton函数中加入我们的处理函数即可。取消预览只需要交换后台数据即可。(我们还需要重写OnOK函数,OnOK函数只需要调用我们的预览图像函数即可)

以上方法是通过小改动实现的预览图像,效果并不是很好。加入我们通过平移操作处理了这幅图像,然后预览了这幅图像的油画效果,这时候我们点取消预览,结果连平移效果也没有了。有什么方法可以解决这个问题吗?有的,理论可行,我没实现,方法如下:

给每一个操作编号,使用栈存储用户输入的操作,预览与确定即入栈,取消预览与取消即出栈,我们每次更新视图的时候,将图像与后台交换,并从栈底按照操作编号操作到栈顶即可。

4、存储并读取对话框中的数据

#include <fstream>
//存储
CFileDialog fileDlg(TRUE, _T("txt"), NULL, 0, _T("*.txt|All Files (*.*) |*.*|"), this);
fileDlg.DoModal();
CString strFilePath = fileDlg.GetPathName();       //文件路径
ofstream fout;
fout.open(strFilePath, ios::out);
if (!fout.is_open())
{AfxMessageBox(L"无法打开文件");return;
}
char buff[1024] = { 0 };
fout << 数据<<" ";fout.close();//读取
CFileDialog fileDlg(TRUE, _T("txt"), NULL, 0, _T("*.txt|All Files (*.*) |*.*|"), this);
fileDlg.DoModal();
CString strFilePath = fileDlg.GetPathName();       //文件路径
ifstream fin;
fin.open(strFilePath, ios::in);
if (!fin.is_open())
{AfxMessageBox(L"无法打开文件");return;
}
fin >> 数据;fin.close();
UpdateData(FALSE);

MFC过程中遇到的问题

暂时就遇到一个比较严重的问题:当你在CDlg类中同时包含Doc类与function类时,由于View类中有function类,会重定义。修改所有function类中的函数,添加static即可。

其他的内存读取冲突问题可能是空指针

MFC基础知识与课程设计思路相关推荐

  1. 七日掌握设计配色基础_掌握正确的基础知识:如何设计网站的导航,搜索和首页...

    七日掌握设计配色基础 by Anant Jain 通过Anant Jain 掌握正确的基础知识:如何设计网站的导航,搜索和首页 (Get the basics right: how to design ...

  2. Sketch Essential Training: The Basics Sketch基本训练:基础知识 Lynda课程中文字幕

    Sketch Essential Training: The Basics 中文字幕 Sketch基本训练:基础知识 中文字幕Sketch Essential Training: The Basics ...

  3. MFC 基础知识:对话框背景添加图片和按钮Button添加图片

    很长时间没有接触MFC相关的知识了,我大概是在大二时候学习的MFC相关知识及图像处理,现在由于要帮个朋友完成个基于C++的程序,所以又回顾了下相关知识.的确,任何知识一段时间过后都比较容易忘记,但回顾 ...

  4. MFC 基础知识:主对话框与子对话框(二)

    (仅供使用VS MFC初学者学习,高手莫见笑) 接"MFC 基础知识:主对话框与子对话框(一)"的内容 在"MFC 基础知识:主对话框与子对话框(一)"中Edi ...

  5. 数字电路基础知识——乘法器的设计(二)( 串行、流水线、有符号数八位乘法器)

    数字电路基础知识--乘法器的设计(二)( 串行.流水线.有符号数八位乘法器) 前面一节关于乘法器的具体实现方式有很多种方法,均有各自的优缺点. 本节将再介绍一下两种乘法器的设计,分别用Verilog语 ...

  6. 计算机基础知识操作培训教案,计算机基础知识培训教案设计

    计算机基础知识培训教案设计 (67页) 本资源提供全文预览,点击全文预览即可全文预览,如果喜欢文档就下载吧,查找使用更方便哦! 19.90 积分 计算机基础知识 培 训 教 案 第一课时 发 展 史 ...

  7. VC++6.0及MFC基础知识

    VC++6.0及MFC基础知识 这是早期的学习笔记,今天翻出来,觉得还有点价值,就转发到这里. Visual C++ 6.0的主界面 VC++6.0的MFC Windows 的三大模块就是以DLL( ...

  8. 计算机基础知识的看法,关于《计算机应用基础知识》课程教学的看法

    [摘要] <计算机应用基础知识>不仅是教师继续教育培训教材,也是许多计算机专业和非专业学生必学的教材.本文主要分析了中等职业学校<计算机应用基础知识>在教学.培训中存在的一些问 ...

  9. 吉林大学微型计算机技术,微型计算机基础知识-吉林大学课程中心.ppt

    微型计算机基础知识-吉林大学课程中心 * 位寻址区--图3-11特殊功能寄存器SFR中位地址 特殊功能寄存器中位地址范围: 80H-0FFH. 图3-11特殊功能寄存器中的位地址 * 用户RAM和堆栈 ...

最新文章

  1. java http close,okhttpclient-close
  2. ListT 循环修改其中的数据
  3. Android 8.0 中如何读取内部和外部存储以及外置SDcard
  4. VS Code阅读Android源码
  5. [html] 说说你对HTML5中“一次编写,全体使用”的理解
  6. 高可用-软件heartbeat的入门介绍
  7. Linux做施压机的最大线程数,关于性能测试的几个要点
  8. python django 数据库查询方法总结
  9. 【java】Thread.start 它是怎么让线程启动的呢
  10. 深度学习2.0-41.GRU原理及实战
  11. 编译原理:有穷自动机(DFA与NFA)
  12. 利用Linux系统实现VLAN间的单臂路由及安全网关的功能
  13. java jsession,JSession
  14. matlab lte rsrp,为什么选择 FieldFox 手持式分析仪?- 更宽带宽,更高精度
  15. 使用hexo发布文章
  16. 【毕设教程】python区块链实现 - proof of work工作量证明共识算法
  17. SpringCloud微服务实战——搭建企业级开发框架(二十七):集成多数据源+Seata分布式事务+读写分离+分库分表
  18. [NewStarCTF] Word-For-You
  19. 走进C++程序世界-----指针(动态申请空间和释放空间)
  20. 10分钟带你了解MSTP协议,附加配置MSTP实验

热门文章

  1. 计算机网络之(7):TCP流量控制、拥塞控制 + 网络层
  2. 小微企业内部用服务器应该怎么选择配置
  3. 回答网友的几个跟帖和感想
  4. 车载滤波器组件焊锡开裂失效分析
  5. java对接portal协议_Portal协议分析
  6. 果壳格言——偶像的力量近在眼前
  7. word里贴代码神器(不需要下载)
  8. (2021 ICCV)Specificity-preserving RGB-D Saliency Detection(A类)
  9. 标签宽度确定,让文字在标签内平均分布
  10. 下载多张图片并压缩成压缩包