1. 概述

  • MFC程序由CWinApp、MainFrm(含Menu,可用CSplitterWndEx分割)、众多Dialog等组成。
  • MFC既可以使用纯Dialog的形式,也可以使用Document+View的形式进行开发
    • 纯Dialog
    • Document+View
      • 类似于MVVM的模式
      • 可视化创建了FormView形式的Dialog后,可以使用Project->Class Wizard创建这个FormView相应的ModelView类
  • MFC应用程序的入口函数(初始化函数)
    • BOOL XXXApp::InitInstance()
    • MFC对WindowsAPI进行了封装。MFC提供给编程人员的第一个裸露程序入口就是CWinApp的InitInstance(),其实最终的入口函数还是WindowsAPI的WinMain()函数
    • 所以在自定义了主界面的Init()等函数时,通常就是在InitInstance()中调用它

2. 通过代码控制界面

  • 并没有主界面的可视化设计界面?只能通过Resource View下的Menu去修改Menu??
  • 通过代码中的CSplitterWndEx等进行界面的切割
    • 在头文件MainFrm.h,中定义分割类对象和相关初始化函数(HeaderView是生成的Class的名字):
// Overrides
public:
    virtual BOOL OnCreateClient(LPCREATESTRUCT lpcs, CCreateContext* pContext);
protected:  // control bar embedded members
    CSplitterWndEx   m_wndSplitterHoriz1;
private:
    BOOL CreateSplitterWindow(CCreateContext* pContext);
* 在MainFrm.cpp中给出splitter及view的设置:
    BOOL CMainFrame::Init()
    {
        // set default
        INT iYCur  = 300;
        INT iYMin  = 0;

        m_wndSplitterHoriz1.SetRowInfo(0, iYCur, iYMin);
        m_wndSplitterHoriz1.RecalcLayout();

        return TRUE;
    }

    BOOL CMainFrame::OnCreateClient(LPCREATESTRUCT /*lpcs*/,
        CCreateContext* pContext)
    {
        //SetAMMWindowTitle(); // no project

        BOOL bRet = CreateSplitterWindow(pContext);
        return bRet;
    }

    // -----------------------------------------------------------
    // function builds the splitter and the own views together
    BOOL CMainFrame::CreateSplitterWindow(CCreateContext* pContext)
    {
        //将主窗口分割为2行1列,
        if (!m_wndSplitterHoriz1.CreateStatic(this, 2, 1))
        {
            return FALSE;
        }
        //然后在主窗口的第2行第1列中绑定view
        m_wndSplitterHoriz1.CreateView(0,0,RUNTIME_CLASS(HeaderView),CSize(100,100),pContext);
        m_wndSplitterHoriz1.SetRowInfo(0,200,0);
        m_wndSplitterHoriz1.CreateView(1,0,RUNTIME_CLASS(HeaderView),CSize(100,100),pContext);
        m_wndSplitterHoriz1.SetRowInfo(1,200,0);

        return TRUE;
    }
* 设置切割布局时需要制定分割线两侧是什么View(MFC的文档,是一种特殊的Dialog,在Resource View中的Dialog文件夹右击选择Add Resource时,弹出窗的Dialog节点可以展开,下面有一个FormView节点,用于创建这种View,并且可以在属性窗口修改ID)

3. 可视化设计界面

  • 可在Resource View看到所有的界面
  • 主界面的菜单
    • 主界面的菜单UI是XXX.rc/Menu/IDR_MAINFRAME,可以直接可视化的增删改菜单项,设置文本(用@标识用于多语言替换?)、ID、TEXT等。
    • 在主界面MainFrm.cpp中可以用菜单的ID来进行消息映射绑定,消息绑定的事件中也可以Qt的界面
  • 右键菜单
    • 可以在XXX.rc/Menu/IDR_CONTEXT_MENU中进行可视化设置,可以设置ID如IDR_CONTEXT_MENU
    • 可以包含多个右键菜单,有各自的ID如IDX_CONTEXT_MENU_LOCAL_LIST_VIEW,代码中动态获得应该显示哪一个右键菜单
    UINT uiRessourceIDContextMenus = IDR_CONTEXT_MENU; 

    int iIdxContextMenu = -1; // -1 = undefined

    switch (contextMenu)
    {
    case ContextMenuLocalListView:
        iIdxContextMenu = IDX_CONTEXT_MENU_LOCAL_LIST_VIEW;
        break;
    case ContextMenuLocalTreeView:
        iIdxContextMenu = IDX_CONTEXT_MENU_LOCAL_TREE_VIEW;
        break;
    case ContextMenuRemoteListView:
        iIdxContextMenu = IDX_CONTEXT_MENU_REMOTE_LIST_VIEW;
        break;
    case ContextMenuRemoteTreeView:
        iIdxContextMenu = IDX_CONTEXT_MENU_REMOTE_TREE_VIEW;
        break;
    case ContextMenuEmpty:
        iIdxContextMenu = IDX_CONTEXT_MENU_EMPTY;
        break;
    case ContextMenuOutputWindow:
        iIdxContextMenu = IDX_CONTEXT_MENU_OUTPUT_VIEW;
        break;
    default:
        assert(false); // implementation error -> undefined context menu
        PRINT_TRACE(AMMCOMP_TRACE_LIB_DIALOGS, AMMCOMP_TRACE_LAYER_GUI, AMMCOMP_TRACE_LEVEL_ERROR, FUNCTION_SIGNATURE + " undefined context menu");
        break;
    }

    CMenu oContextMenus;
    if (FALSE != oContextMenus.LoadMenu(uiRessourceIDContextMenus)) // contains all context menus
    {
        CMenu* pPopup = oContextMenus.GetSubMenu(iIdxContextMenu);  // get the wanted context menu
        if(NULL != pPopup)
        {
            if (NULL != pWndParent)
            {
                while (pWndParent->GetStyle() & WS_CHILD)
                {
                    if (NULL != pWndParent)
                    {
                        pWndParent = pWndParent->GetParent();
                    }
                }
            }

            if (NULL != pWndParent)
            {
                pPopup->TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON, point.x, point.y, pWndParent);
            }
        }
    }
  • 对话框

    • 所有的Dialog都在XXX.rc/Dialog/下面
    • 在可视化设计界面中的某个控件上右击可以增加:选择"Add Variable..."
    • 添加、设计Dialog
      • 使用PROJECT->Class Wizard...按步骤设计生成MFC界面

        • 点击"Add Class..."按钮,在弹窗中输入想要创建的窗口名字(也就是Class name,.h和.cpp文件会自动同步)
      • 也可以直接在Resource View的Dialog等文件夹上直接右击添加
        • 保存后会直接在_header/resource.h文件中生成相应的宏、常量,在.rc文件中生成界面相关代码
      • 绑定Dialog弹出的消息映射
        • 菜单点击触发:
        • 页面上的按钮点击触发:
      • 可以使用Toolbox进行界面设计

4. 数据及事件绑定(通过Variable)

  • 数据绑定(MFC中叫数据交换和检验/校验,winform中直接通过控件获取text什么的,相当于已经帮你绑好了)

    • 代码中通过DoDataExchange进行数据双向绑定:
    void CDlgTabMaintenance::DoDataExchange(CDataExchange* pDX)
    {
      CRCSBasicProjectDialogTab::DoDataExchange(pDX);
      DDX_Control(pDX, IDC_TREE_FILES_MAINTENANCE, m_ctrlTreeFiles);
    }
    • 可视化操作中,右键控件选择"Add Variable...",同样会在cpp和头文件中生成DoDataExchange部分代码,将控件和变量绑定在一起,也会在.rc和Resource.h文件中生成对应的常量等

      • 如果勾选"Control Variable",那么添加变量为控件变量,可以操作控件,变量类型将固定为控件类型;如果不勾选,则让控件关联了一个变量,不可以修改控件。
      • 将在头文件中声明相应的变量。
      • 同时如果是控件变量,则会在cpp文件中生成DoDataExchange代码段;如果不是控件变量,那么将在.cpp文件的类定义的继承后面多一段, edit_binded_data(0)。
      • 完成变量绑定后,就不需要管它了,在文本变化等事件的处理函数中,会自动把变量值变成控件中用户填的新值
  • 在Class中通过消息映射表进行事件绑定
    • 可以手动写事件处理函数和向消息映射表添加记录
    • 可以在设计窗口右击控件选择"Add Event Handler..."
    • 可以在控件的属性窗口中选择事件tab,然后在想要加的事件右侧填函数名
  • 打开一个新的MFC Dialog可以用CreateProcess,比如按钮点击触发或菜单按钮点击触发

5. 其他

  • MainFrm.cpp中的Init()等函数在定义前,都需要现在.h头文件中声明函数原型,否则无法识别报错
  • 可以在函数中任意位置临时#include?? -- 不行,即使vs中可以找到,编译也可能不通过,可能要写到函数中的话,需要特殊定义方法或者当成了内部类?
  • 如果Resource.h或者.rc文件被打开了,那么Resource View不能展开,同时这两个文件和设计窗口不能被同时打开
  • 有时Resource View下面节点无法展开,可以先把编辑窗口所有打开的文件关掉再试,可能是rc文件被打开等问题?
  • 给主界面的菜单项绑定的事件,必须声明、定义和绑定分别要放在MainFrm.h和MainFrm.cpp中,否则运行后菜单会一直是灰色,并不是enable的原因
    • Resource View中给菜单项添加Event Handler时COMMAND的Class List中要选CMainFrame?
  • 报错"unexpected #endif"或者"unexpected end of file while looking for precompiled header. Did you forget to add '#include "stdafx.h"' to your source?"
    • 通常是因为微软忽略掉实现文件中stdafx.h包含头文件之前的一切指令
    • 所谓头文件预编译,就是把一个工程(Project)中使用的一些MFC标准头文件(如Windows.H、Afxwin.H)预先编译,以后该工程编译时,不再编译这部分头文件,仅仅使用预编译的结果。这样可以加快编译速度,节省时间。
    • 编译器通过一个头文件stdafx.h来使用预编译头文件。stdafx.h这个头文件名是可以在project的编译设置里指定的。编译器认为,所有在指令#include "stdafx.h"前的代码都是预编译的,它跳过#include "stdafx. h"指令,使用projectname.pch编译这条指令之后的所有代码。
    • 解决
      • #include "stdafx.h"要放在最前面
      • 不使用预编译头文件(stdafx.h)
      • 在stdafx.h文件中增加预编译处理
      • 还有一种说法是:project_name[right click] -> C/C++ -> Precompiled Header -> Precompiled Header (Choose Not Using Precompiled Headers)
    • 参考,参考2

MFC学习(三):项目学习的更多相关文章

  1. java_web学习(三) eclipse_jsp学习

    1.首先打开eclipse,新建一个Dynamac web project项目文件 2.在WebContent单击右键创建JSP File 3.过程 4.简单的jsp代码 运行结果: 5.导出war文 ...

  2. Html学习(三) 分类学习

    代码: <h1>这是一级分类吗</h1> <h2>这是二级分类吗</h2> <h3>这是三级分类吗 </h3> 效果: 介绍: ...

  3. 中小研发团队架构实践之生产环境诊断工具WinDbg 三分钟学会.NET微服务之Polly 使用.Net Core+IView+Vue集成上传图片功能 Fiddler原理~知多少? ABP框架(asp.net core 2.X+Vue)模板项目学习之路(一) C#程序中设置全局代理(Global Proxy) WCF 4.0 使用说明 如何在IIS上发布,并能正常访问

    中小研发团队架构实践之生产环境诊断工具WinDbg 生产环境偶尔会出现一些异常问题,WinDbg或GDB是解决此类问题的利器.调试工具WinDbg如同医生的听诊器,是系统生病时做问题诊断的逆向分析工具 ...

  4. Spring Boot 项目学习 (三) Spring Boot + Redis 搭建

    0 引言 本文主要介绍 Spring Boot 中 Redis 的配置和基本使用. 1 配置 Redis 1. 修改pom.xml,添加Redis依赖 <!-- Spring Boot Redi ...

  5. 20145337《Java程序设计》第三周学习总结

    20145337 <Java程序设计>第三周学习总结 教材学习内容总结 类与对象 类与对象的关系:要产生对象必须先定义类,类是对象的设计图,对象是类的实例.我觉得在视频中对类与对象关系的描 ...

  6. 转: 学习开源项目的若干建议(infoq)

    转: http://www.infoq.com/cn/news/2014/04/learn-open-source 学习开源项目的若干建议 作者 崔康 发布于 2014年4月11日 | 注意:GTLC ...

  7. 华为章宇:如何学习开源项目及Ceph的浅析

    转自http://www.csdn.net/article/2014-04-10/2819247-how-to-learn-opensouce-project-&-ceph 摘要:开源技术的学 ...

  8. DjangoRestFramework学习三之认证组件、权限组件、频率组件、url注册器、响应器、分页组件

    DjangoRestFramework学习三之认证组件.权限组件.频率组件.url注册器.响应器.分页组件   本节目录 一 认证组件 二 权限组件 三 频率组件 四 URL注册器 五 响应器 六 分 ...

  9. 20175227张雪莹 2018-2019-2 《Java程序设计》第三周学习总结

    20175227张雪莹 2018-2019-2 <Java程序设计>第三周学习总结 教材学习内容总结 (仅在此列举个性化学习总结) 一.编程语言的几个发展阶段. 1.面向机器语言:汇编语言 ...

  10. 20175314 《Java程序设计》第三周学习总结

    20175314 <Java程序设计>第三周学习总结 教材学习内容总结 编程语言的发展事是从面向机器(汇编.机器)到面向过程(C)再到面向对象(Java) 成员变量: 1.成员变量定义在类 ...

随机推荐

  1. 【311】Python 构建 ArcMap 标注表达式

    参考:构建标注表达式(官方帮助) 参考:计算字段示例(官方帮助) 说明:以上两者的方法略有不同,一个是通过字段表达式显示标注,一个通过字段计算新的字段,使用的工具方法也不同,前者通过 Layer.la ...

  2. Lenovo SplitScreen联想分屏软件只能在联想电脑运行,如何破解

    1.正常安装软件,重启电脑. 2.打开安装目录 C:\Program Files\Lenovo\Lenovo SplitScreen\SplitScreen 找到 MachineChecker.dll ...

  3. 编码总结,以及对BOM的理解

    一.前言 在跨平台.跨操作系统或者跨区域之间,经常会涉及到编码的问题,因为前段时间在项目中,遇到了因为编码而产生乱码的问题,以前对编码也是一知半解,所以决定对编码有一个更为深入的了解,因此才有了这篇自 ...

  4. 压缩包法安装mysql

    之前一直安装mysql,我一直是用压缩包安装的.如果之前安装过Mysql,必须要删除注册文件,才能把Mysql彻底删除了. 先在官网下载mysql的版本.下载package版本,即.zip版本的.下载 ...

  5. shell编程之sed语法

    首先插播条广告:  想要进一个文件夹去 看下面有那些文件 必须对这个文件夹有执行权限. sed p  打印对应的行  2p 打印第二行. -n  只输出经过sed 命令处理的行 看图吧 不太会擅长言语 ...

  6. Part2_lesson2---ARM处理器工作模式

    arm公司发布的学习手册:ARM Architecture Reference Manual. 打开之: 找到Programmers' Model->A2.2 Processor modes. ...

  7. 白盒测试实践项目(day6)

    胡俊辉负责JUint测试部分,了解JUint测试的方法,并对其他成员介绍JUint的使用,负责JUnit部分相关文档的编写,负责博客园博客的维护,负责小组成员的任务分类与管理. 李建文负责代码复审部分 ...

  8. JS中立即执行函数的理解

    1.匿名函数不能单独定义,必须进行赋值操作或者立即执行,否则会被JS引擎定义为语法错误 function(){alert(dada);} VM229:1 Uncaught SyntaxError: U ...

  9. 05 Computing GC Content

    Problem The GC-content of a DNA string is given by the percentage of symbols in the string that are ...

  10. java免费空间!最简单的openshift免费空间上传代码教程!和FTP一样简单!

    史上最简单的openshift免费空间上传代码教程!没有之一! 最近因为想弄一个免费的空间,而且最好是Java的空间,找了一大片,jsp的空间少不说,免费的更是寥寥无几. 找了一大推垃圾空间,终于让我 ...