MFC框架

MFC框架

  • MFC框架
    • 一、什么是MFC?
    • 二、MFC的用途
    • 三、MFC的应用程序的类型
    • 四、MFC主要的类
    • 五、第一个MFC程序
    • 六、MFC的入口函数(程序启动)机制
    • 七、MFC程序的执行过程
    • 八、应用程序类CWinApp的总结
      • 练习重写:
    • 九、MFC的窗口创建机制
    • 十、MFC的消息映射
      • 1.概念
      • 2.实现
      • 3.实现原理
      • 4.MFC的消息分类
    • 十一、MFC菜单
      • 1.相关类
      • 2.CMenu类的使用
    • 十二、MFC工具栏
      • 1.相关类
      • 2.CToolBar类的使用
    • 十三、MFC状态栏
    • 十四、CDialogBar 类
    • 十五、MFC的视图
    • 十六、MFC的视图
    • 十七、运行时类信息
    • 十八、动态创建
    • 十九、MFC的切分窗口
    • 二十、MFC的文档
    • 二十一、文档模板类
    • 二十二、使用文档模板类创建多文档视图程序
    • 二十三、使用文档模板创建多文档视图程序
    • 二十四、MFC绘图
    • 二十五、文件操作
    • 二十六、序列化
    • 二十七、对象的序列化
    • 二十八、MFC对话框
    • 二十九、对话框数据交换技术
    • 三十、MFC的各种控件
    • 三十一、树控件
    • 三十二、Tab控件
    • 三十三、MFC的多线程
    • 三十四、企业的上机题
    • 三十五、基于windows平台的数据库访问技术
  • MFC的第二部分
    • 一、基于windows平台的数据库访问技术
    • 二、案例场景:汽车租赁系统
    • 三、使用Ado访问数据库
  • MFC的第三部分
    • 一、Windows平台的网络通信编程(socket)
    • 二、远程控制项目

MFC的课程极强的连续性,不能缺课,不能走神
不但学习知识点多,更多的还需要掌握阅读代码的能力和调试代码的技巧
Windows平台上,继 Win32核心编程 之后的 基于MFC框架开发
MFC是封装了绝大部分的Win32 API之上的编程框架
QT 和 MFC 的联系区别?
QT是一个跨平台的开发框架,MFC是微软公司开发的专门基于Windows平台的开发框架

MFC框架

MFC课程组成:15天

  1. MFC的机制和原理
    基于MFC的应用程序的组成部分(由哪些类组成)、执行流程、原理和机制。
    例如:消息映射、运行时类信息、动态创建等
  2. Windows平台上的数据访问技术,包括ODBC、ADO
  3. Windows平台上的网络通信编程
  4. 项目

MFC的课程目标:

  1. MFC框架生成的程序的组成部分和执行流程
  2. MFC的机制
    程序启动、窗口创建、消息映射(命令消息的路由)、运行时类信息、
    动态创建
  3. 使用断点调试
    F9、F5、F10、F11、shift+F5、Ctrl+F5
  4. 通过 调用堆栈 窗口查看函数的调用关系
  5. MSDN

一、什么是MFC?

Microsoft Foundation Classes: 微软基础类库

  1. 是一个庞大的类库
  2. 是一个应用程序的编程框架


二、MFC的用途

基于框架编程,提高开发效率,缩短开发周期,降低开发成本



三、MFC的应用程序的类型

窗口应用程序 , 直接面向用户的、双击就可以运行的程序

  1. 单文档程序 (4个类)只能管理一个文档
    CAboutDlg --帮助菜单项下的 关于对应的对话框窗口 不是必须的
    CWinApp 类 – 应用程序类,负责整个应用程序的管理
    CFrameWnd类 – 单文档的框架窗口类
    CView/CEditView类-视图类 – 视图窗口类,用来显示数据
    CDocument类 – 文档类,用来管理数据,包括数据保存和加载
    MFC框架_第1张图片

  2. 多文档程序 (5个类)可以管理多个文档
    CWinApp类 – 应用程序类,负责整个应用程序的管理
    CMDIFrameWnd类 – 多文档的主框架窗口类
    CMDIChildWnd类 – 多文档的子框架窗口类
    CViewCEditView类-视图类 – 视图窗口类,用来显示数据
    CDocument类 – 文档类,用来管理数据,包括数据的保存和加载
    MFC框架_第2张图片

  3. 基于对话框的程序
    CWinApp类 – 应用程序类,负责整个应用程序的管理
    CDialog/CDialogEx类 – 对话框类,创建对话框窗口
    MFC框架_第3张图片

  4. 库程序 面向的用户是程序员
    规则动态库
    接口是规则的,可以被其它的C++程序使用
    (1) 动态链接MFC库
    (2) 静态链接MFC库
    MFC扩展DLL
    接口是MFC的,只能被MFC使用

  5. 控制台程序



四、MFC主要的类

  1. CObject
    继承关系中的顶层父类。主要实现了MFC的一些特性和机制。例如:运行时类信息、动态创建和序列化。

  2. CCmdTarget
    父类是CObject类,该类实现了对命令消息的处理

  3. CWinApp
    应用程序类,管理整个应用程序的运行

  4. CWnd
    父类是CCmdTarget类,提供了窗口的基本操作
    几个不同类型的子类:框架窗口类、视图窗口类、对话框类、控件类、工具栏和状态栏

  5. CDocument
    父类是CCmdTarget类,主要用来管理数据

CObject - CCmdTarget - CWinThread - CWinApp
              |             
              |------- CWnd ------- CFrameWnd - CMDIFrameWnd
              |          |                |---- CMDIChildWnd
              |          |
              |          |-- CView
              |          |
              |          |-- CDialog
              |          |
              |          |-- CButton、CEdit...
              |          |
              |          |-- CControlBar - CToolBar
              |                    |------ CSuatusBar
              |
              |------- CDocument
  1. CException
    异常处理类

  2. CFile类、CFileFind
    文件操作类

  3. CDC类、CGdiObject类及其子类
    绘图设备和绘图对象类

  4. MFC的集合类
    CArray类、CList类、CMap

  5. 非CObject类的子类
    主要定义了在项目中常用的一些数据结构
    例如:CString类、CTime类、CPoint类、CRect类、CSize等



五、第一个MFC程序

创建项目:

  1. 创建 win32桌面应用程序 -》设置项目属性:静态链接MFC \多字节字符集
  2. 在项目中添加cpp文件,文件名MFCbase.cpp.在文件中:
    包含头文件,#include //win32 +mfc
    添加应用程序类,CWinApp类的子类,并且添加全局的应用程序对象theApp
    添加框架窗口类,CFrameWnd类的子类。
    重写CWinApp::InitInstance()函数,在函数中,创建基本的窗口程序。

MFC框架_第4张图片
MFC框架_第5张图片
MFC框架_第6张图片
添加源文件

/*
#include  //Win32
#include 
*/
#include   //写这个已包含  MFC+WIN32

//2.单文档的主框架窗口类
class CMyFrameWnd :public CFrameWnd {
   
};
//1.应用程序类
class CMyWinApp :public CWinApp {
public:
	//初始化操作,用户程序的代码由此开始编写和执行
	virtual BOOL InitInstance();
};

CMyWinApp theApp; //全局的应用程序对象

BOOL CMyWinApp::InitInstance() {
    //创建基本的窗口程序
	CMyFrameWnd* pFrame = new CMyFrameWnd;
	pFrame->Create(NULL, "MFCBase");
	m_pMainWnd = pFrame;
	m_pMainWnd->ShowWindow(SW_SHOW);
	m_pMainWnd->UpdateWindow();

	return TRUE;
}

运行测试
MFC框架_第7张图片

Win32的方式:

 LRESULT CALLBACK WndProc(HWND hWnd,UINT msgID,
     WPARAM  wParam,LPARAM lParam)
 {
    switch(msgID){
       case WM_DESTROY:
          PostQuitMessage(0);
        break;
    }
    return DefWindowProc(hWnd,msgID,wParam,lParam);
 }
 
 int CALLBACK WinMain(HINSTANCE hInstance,HINSTANCE hPrevIns,
     LPSTR lpCmdLine,int nCmdShow)
 {
   WNDCLASS wns = {0};
   wns.cbClsExtra = 0;
   wns.cbWndExtra = 0;
   wns.hCursor = NULL;
   wns.hIcon = NULL;
   wns.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
   wns.hInstance = hInstance;
   wns.lpfnWndProc = WndProc;
   wns.lpszClassName = "Main";
   wns.lpszMenuName = NULL;
   wns.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS;
   RegisterClass(&wns);
   HWND hWnd = CreateWindowE(0,"Main","Window",
       WS_OVERLAPPEDWINDOW,
       100,100,700,500,NULL,NULL,hInstance,NULL);
   ShowWindow(hWnd,SW_SHOW);
   UpdateWindow(hWnd);
   MSG nMsg = {0};
   while(GetMessage(&nMsg,NULL,0,0)){
     TranslateMessage(&nMsg);
     DispatchMessage(&nMsg);
   }      
   return 0;
 }


六、MFC的入口函数(程序启动)机制

与win32程序相同,MFC程序也是由WinMain函数开始执行,只不过,WinMain函数是由MFC框架在底层提供,用户不需要也不能再写WinMain函数。
VS调试相关快捷键:
F9- 设置/取消断点
F5 - 启动调试
Ctrl+F5 -执行程序(不调式)
Shift +F5 - 终止调试
F10 -单步调试,遇到函数调用,当成一条普通语句执行过去
F11 -单步调试,遇到函数调用,跳转到被调用函数内部执行
在调试状态下,调试窗口才能使用,其中一个 “调用堆栈” 窗口,作用是查看函数之间的调用关系



七、MFC程序的执行过程

( 底层代码+用户代码 )
程序启动,调用MFC框架提供的WinMain()函数,在函数中,调用AfxWinMain()函数后,
在函数中执行以下步骤:

  1. 调用AfxGetThread() 和AfxGetApp() 获取全局对象theApp的地址,分别保存在pThread 和 pApp中。
  2. 应用程序框架的内部初始化 和 应用程序的全局初始化
  3. 根据函数机制,调用到CMyWinAPP::InitInstance()虚函数,完成用户代码,创建并显示窗口
  4. 调用Run()函数,进入消息循环,当 点击关闭按钮时,产生WM_QUIT消息,调用ExitInstance()函数,释放和清理资源并返回。
  5. AfxWinMain()返回,WinMain()函数返回 ,程序结束。
    在MFC程序中,通过大量的虚函数使得底层代码在执行时,可以调用到用户代码。
// 1. MFC框架提供的程序入口函数
WinMain(...)
{
   AfxWinMain(hInstance, hPrevInstance, lpCmdLine, nCmdShow)
   {
      // 1 获取theApp的地址,并保存在pThread和pApp中
      CWinThread* pThread = AfxGetThread();
	   CWinApp* pApp = AfxGetApp();
	   
	   // 2 框架的内部初始化和应用程序的全局初始化
	   AfxWinInit(...);
	   pApp->InitApplication();
	   
	   // 3 重写虚函数InitInstance,完成用户特定的初始化操作
	   pThread->InitInstance()               -- 虚函数1
	   {
	      // 用户代码,按照程序员自己的需要编写代码,创建一个基本的窗口
	      return TRUE;
	   }
	   
	   // 4 消息循环
	   pThread->Run()                        -- 虚函数2
	   {
	      CWinApp::Run()
	      {
	         CWinThread::Run()
	         {
	            for (;;)
	            {
	               // 4.1 没有消息时,作空闲处理
	               while(!::PeekMessage(...))
	               {
	                   OnIdle(...);          -- 虚函数3
	               }
	               // 4.2 有消息时,获取、翻译并派发消息
	               do{
	                  if(!PumpMessage())
	                  {
	                     AfxInternalPumpMessage()
	                     {
	                        if(!::GetMessage(...))
	                            return FALSE;
	                        ::TranslateMessage(...);
		                     ::DispatchMessage(...);
		                     return TRUE;
	                     }
	                  }
	                  // 退出前,调用ExitInstance函数
	                  return ExitInstance();    -- 虚函数4
	               }while(::PeekMessage(...));
	            }
	         }
	      }
	   }
   }
}


八、应用程序类CWinApp的总结

  1. 虚函数

    1. InitInstance() – 程序的初始化操作。完成对象的创建、资源的申请和各种库的初始化 – 必须重写
    2. Run() – 消息循环。虽然可以重写,但是重写的机率不大。
    3. OnIdle() – 空闲处理。有时会重写
    4. ExitInstance() – 程序在退出时,释放资源、卸载库等后面三个函数,通常会重写
  2. 成员变量
    m_pMainWnd – 保存应用程序的主窗口

Afx开头的函数,是MFC的全局函数。
::开头的函数,是win32 api函数。

练习重写:

在基本窗口程序的基础上,重写CWinApp的虚函数

#include  //win32+mfc

//2.框架窗口类
class CMyFrameWnd :public CFrameWnd {};

//1. 应用程序类
class CMyWinApp :public CWinApp {
public:
	virtual BOOL InitInstance();
	virtual int ExitInstance(); 
	virtual int Run();
};

CMyWinApp theApp; //全局的应用程序对象

BOOL CMyWinApp::InitInstance() {
	CMyFrameWnd* pFrame = new CMyFrameWnd;
	pFrame->Create(NULL, "MFC基础");
	m_pMainWnd = pFrame;
	m_pMainWnd->ShowWindow(SW_SHOW);
	m_pMainWnd->UpdateWindow();
	return TRUE;
}

int CMyWinApp::ExitInstance() {
	AfxMessageBox("程序退出前,用户的清理工作!");
	return CWinApp::ExitInstance();
}

int CMyWinApp::Run() {
	AfxMessageBox("进入MFC消息循环");
	return CWinApp::Run();
}



九、MFC的窗口创建机制

  1. 回顾Win32窗口的创建过程:
    win32
    设计和注册窗口类 - - > 创建窗口 - - >消息循环 - ->窗口过程函数
    1、设置和注册窗口类 2、使用注册时的窗口类的类名创建窗口 3、显示和更新窗口 4、消息循环 5、窗口过程函数
    MFC
    CWnd::PreCreateWindow(cs) - -> Create() - -> Run() - ->CWnd::WindowProc

  2. MFC创建过程
    ::LoadMenu()加载菜单
    CreateEx(…); 创建带扩展风格的窗口

    1. 调用PreCreateWindow()函数设计和注册窗口类
    2. 调用AfxHookWindowCreate()设置CBT类型的钩子,钩子函数为_AfxCbtFilterHook.
    3. 调用::AfxCtxCreateWindowEx()创建窗口
    4. 一旦窗口创建,满足钩子条件,跳转到钩子函数_AfxCbtFilterHook()中
      1. 调用Attach()函数连接窗口对象地址与句柄
      2. SetWindowLongPtr()函数,将窗口过程函数设置为框架提供的AfxWndProc()函数。
    5. 跳转回第3步以后代码继续执行…
      我们通过重写CWnd::WindowProc()函数, 完成窗口过程函数的实现。
      pFrame->Create(NULL,"MFCWnd");
      {
      // 1. 如果有菜单资源的参数,加载菜单
      ::LoadMenu();
      // 在成员变量m_strTitle中保存窗口标题
      m_strTitle = lpszWindowName;
      
      // 2. 创建带扩展风格的窗口
      CreateEx(dwExStyle,lpszClassName,lpszWindowName,...);
      {
        CREATESTRUCT cs;
        cs.lpszClass = lpszClassName;//窗口类的类名,NULL  
        
       // 2.1 设计和注册窗口类
        PreCreateWindow(cs);
        {
          if (cs.lpszClass == NULL)//满足条件
         {
              // AFX_WNDFRAMEORVIEW_REG的值为8,表示MFC内置的某种类型的窗口
           VERIFY(AfxDeferRegisterClass(AFX_WNDFRAMEORVIEW_REG));
           {
                 WNDCLASS wndcls;
                 // 默认的窗口处理函数
                wndcls.lpfnWndProc = DefWindowProc;
                wndcls.hInstance = AfxGetInstanceHandle();
                wndcls.hCursor = afxData.hcurArrow;
                 ...
                 // 
                   if (fToRegister & AFX_WNDFRAMEORVIEW_REG)
                  {
                      // SDI Frame or MDI Child windows or views - normal colors
                wndcls.style = CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW;
                      wndcls.hbrBackground = (HBRUSH) (COLOR_WINDOW + 1);
                 // 赋值窗口类的类名以及图标
                  if(_AfxRegisterWithIcon(&wndcls, _afxWndFrameOrView,AFX_IDI_STD_FRAME))
                     {
                         //窗口类的类名和图标
                         pWndCls->lpszClassName = lpszClassName;
                         pWndCls->hIcon = ::LoadIcon(NULL, IDI_APPLICATION);
                 }
                      // 注册窗口类
    	               return AfxRegisterClass(pWndCls);
                  }
                  ...          
                }
               //完成了窗口类的注册后,将窗口类的类名保存到cs成员lpszClass
         	     cs.lpszClass = _afxWndFrameOrView;  // COLOR_WINDOW background
              }
          }               
         // 2.2 设置与窗口创建相关的钩子
        AfxHookWindowCreate(this);
        {
           // 2.2.1 设置进程内的WH_CBT类型的钩子
           ::SetWindowsHookEx(WH_CBT,
        	_AfxCbtFilterHook, NULL, ::GetCurrentThreadId());
             //2.2.2 将窗口对象地址保存到线程状态信息的m_pWndInit中
             // m_pWndInit其实就是pFame的值
          pThreadState->m_pWndInit = pWnd; 
        }
       
        // 2.3 使用注册号的窗口类的类名_afxWndFrameOrView,创建窗口
        HWND hWnd = ::AfxCtxCreateWindowEx(cs.dwExStyle, cs.lpszClass,...);
       // 2.4 一旦窗口创建,满足钩子条件,触发钩子函数的调用
        LRESULT CALLBACK  
        _AfxCbtFilterHook(int code, WPARAM wParam, ...);//钩子函数
        {
           //从线程状态信息中获取窗口对象地址 pFrame
           CWnd* pWndInit = pThreadState->m_pWndInit;
           HWND hWnd = (HWND)wParam;   
           // 2.4.1 连接窗口句柄和窗口对象地址
           pWndInit->Attach(hWnd);
           {
              //this就是窗口对象地址,hWndNew就是窗口句柄
              // 将hWndNew保存到窗口对象的成员m_hWnd中
              pMap->SetPermanent(m_hWnd = hWndNew, this);
              {
                // 以窗口句柄为键,窗口对象地址为值建立映射关系
                m_permanentMap[(LPVOID)h] = permOb;
              }
           }
           
          // 2.4.2 将窗口处理函数设置为MFC框架提供的窗口处理函数
           WNDPROC afxWndProc = AfxGetAfxWndProc(); 
           oldWndProc = (WNDPROC)SetWindowLongPtr(hWnd, GWLP_WNDPROC,(DWORD_PTR)afxWndProc);
        }
        
       // 2.5 跳转回2.3这个步骤以下的代码继续执行...
       }
      }
    
      // 消息处理
     LRESULT CALLBACK
     AfxWndProc(HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam)
     {
        // 根据句柄hWnd获取窗口对象地址 pFrame (new CMyFrameWnd)
        CWnd* pWnd = CWnd::FromHandlePermanent(hWnd);
       return AfxCallWndProc(pWnd, hWnd, nMsg, wParam, lParam);
        {   
          // 由于虚函数机制,调用CMyFramWnd::WindowProc函数
           lResult = pWnd->WindowProc(nMsg, wParam, lParam);
             {
              // 用户对消息的处理--------------------用户代码
           }
     }
    }
    
  3. CFrameWnd类的总结

    1. 虚函数
      PreCreateWindow() -重写该函数在创建之前,设置窗口的参数。
      WindowProc() -重写该函数,完成对各种消息的处理。

    2. 成员变量
      m_hWnd- 用来保存窗口句柄

  4. 钩子函数的案例

    1. 相关函数
      设置钩子
      HHOOK SetWindowsHookEx(
          int idHook,        // 钩子类型
          HOOKPROC lpfn,     // 钩子函数,与钩子类型相对应的
          HINSTANCE hMod,    // 进程内钩子,该参数为NULL;远程钩子,该参数为Dll的实例句柄
          DWORD dwThreadId   // 如果是全局钩子,该参数为NULL,否则表示当前线程ID
      );
    
    1. 调用下一个钩子函数(一般是在钩子函数中调用).
     LRESULT CallNextHookEx(
         HHOOK hhk,      // 钩子句柄
         int nCode,      // 钩子类型
         WPARAM wParam,  // 参数1
         LPARAM lParam   // 参数2
     );
    
    1. 卸载钩子
      UnhookWindowsHookEx(HHOOK hhk)

    2. 进程内钩子
      参考代码:

      #include 
      //2.框架窗口类
      class CMyFrameWnd :public CFrameWnd {
      public:
     //窗口过程函数
            virtual LRESULT WindowProc(UINT message, WPARAM wParam, LPARAM lParam);
      };
    
      LRESULT CMyFrameWnd::WindowProc(UINT message, WPARAM wParam, LPARAM lParam) {
       //处理用户关注的消息
       switch (message)
     	{
       case WM_CREATE:
             	AfxMessageBox("WM_CREATE消息处理");
    	        break;
    	case WM_PAINT:
             	//win32方式
        	    //PAINTSTRUCT ps = { 0 };
    	        //HDC hDC = ::BeginPaint(m_hWnd, &ps);
    	       //::TextOut(hDC, 100, 100, "Hello World", 11);
    	      //::EndPaint(m_hWnd, &ps);
    
    	 //MFC方式
         PAINTSTRUCT  ps = { 0 };
    	CDC* pDC = BeginPaint(&ps);
    	pDC->TextOut(100, 100, "Hello World");
    	EndPaint(&ps);
    	break;
     	}
        return CFrameWnd::WindowProc(message, wParam, lParam);
       }
    
        
       //应用程序类
      class CMyWinApp :public CWinApp {
      public:
            virtual BOOL InitInstance();
      };
    
     CMyWinApp theApp;
      
     BOOL CMyWinApp::InitInstance() {
         	CMyFrameWnd* pFrame = new CMyFrameWnd;
            pFrame->Create(NULL, "MFCWnd");
            m_pMainWnd = pFrame;
            m_pMainWnd->ShowWindow(SW_SHOW);
            m_pMainWnd->UpdateWindow();
            return TRUE;
            }	        
    


十、MFC的消息映射

1.概念

指的是消息ID与消息处理函数的对应关系。

2.实现

  1. 实现
    1. 直接或者间接的继承自CCmdTarget类,在类的内部添加消息映射的声明宏
      DECLARE_MESSAGE_MAP()

    2. 在类的外部添加消息映射的实现宏
      BEGIN_MESSAGE_MAP(theClass,baseClass)
      END_MESSAGE_MAP( )

    3. 在实现宏的中间添加具体的消息映射宏
      BEGIN_MESSAGE_MAP(theClass,baseClass)
      ON_MESSAGE(消息ID,处理函数)
      END_MESSAGE_MAP( )

    4. 添加消息处理函数的声明和实现
      afx_msg LRESULT memberFxn(WPARAM, LPARAM);



3.实现原理

  1. 宏替换
    双击选中 -》 DECLARE_MESSAGE_MAP -》Ctrl+table -》注释 粘贴

  2. 成员的作用

    1. GetThisMessageMap() -静态的成员函数。
    2. GetMessageMap() -虚函数。在函数中仅仅只调用了GetThisMessageMap()函数。
    3. GetThisMessageMap()函数的执行过程
      1. _messageEntries[]-静态的具有常属性的结构体类型的数组。类型是AFX_MSGMAP_ENTRY。保存了当前类对消息的处理信息

           struct AFX_MSGMAP_ENTRY {
               UINT nMessage;   //窗口消息的ID
               UINT nCode;      // 通知消息的通知码
               UINT nID;        // 命令消息ID(起始ID)
               UINT nLastID;    // 在一个范围中表示结束的ID
                
               UINT_PTR nSig;    // 消息处理函数的类型(根据参数和返回值区分)
               AFX_PMSG pfn;    // 消息处理函数的指针
           };4个成员表示不同类型的消息ID。
        后2个成员表示消息处理函数的信息(类型和地址)   
        
        
        
      2. messageMap -静态的具有常属性的结构体类型的变量。
        作用是:

        1. 保存父类的GetThisMessageMap()函数的地址
        2. 保存当前类的_messageEntries[]这个数组的地址。
          struct AFX_MSGMAP
          {
           //函数指针
           const AFX_MSGMAP* (PASCAL* pfnGetBaseMap)();
           //AFX_MSGMAP_ENTRY类型的指针 
           const AFX_MSGMAP_ENTRY* lpEntries;
           };  
           
          
          
      3. return &messageMap; //返回3.3.2 messageMap的地址

  3. 成员之间的关系

      GetMessageMap()
      |->GetThisMessageMap()
          |->&messageMap
               |->_messageEntries[],   //保存了当前类对消息的处理信息
                    WM_CREATE <==>OnCreate
                    WM_PAINT <==>OnPaint
               |->&CFrameWnd::GetThisMessageMap() ,父类的GetThisMessageMap()函数指针 
                   |->&CFrameWnd::messageMap
                        |->&CFrameWnd::_messageEntries[],CFrameWnd类对消息处理的信息
                                  WM_CREATE <==>OnCreate
                                  WM_CLOSE <==>OnClose
                                  ......
                           |->&CWnd::GetThisMessageMap 
                                  |->&CWnd::messageMap
                                        |->&CWnd::_messageEntries[],CWnd类对消息的处理信息
                                              WM_CLOSE <==>OnClose
                                              ....
                                        |->&CCmdTarget::GetThisMessageMap
                                             |->&CCmdTarget::messageMap
                                                 |->&CCmdTarget::_messageEntries[], 数组的有效元素为0
                                                 |->NULL
    

    类的继承关系:CMyFrameWnd->CFrameWnd->CWnd->CCmdTarget
    当展开消息映射宏之后,在类的继承层次关系上,形成一个消息处理信息的链表。
    可以简称为"消息链"。根据消息ID查找对应的处理函数,就是通过遍历消息链来完成的。
    参考代码:MsgMap.cpp

    #include 
    //框架窗口类
    class CMyFrameWnd :public CFrameWnd {
       /*
    public:
    	virtual LRESULT WindowsProc(UINT message,WPARAM wParam,LPARAM lParam);	
        */
    public:
    	afx_msg LRESULT OnCreate(WPARAM wParam, LPARAM lParam);
        afx_msg LRESULT OnPaint(WPARAM wParam, LPARAM lParam);
        
        //消息映射的声明宏
        /*DECLARE_MESSAGE_MAP()*/
    protected: 
    	static const AFX_MSGMAP* PASCAL GetThisMessageMap(); 
    	virtual const AFX_MSGMAP* GetMessageMap() const; 
    };
    
    //消息映射的实现宏
    //BEGIN_MESSAGE_MAP(CMyFrameWnd, CFrameWnd)
    //	ON_MESSAGE(WM_CREATE,OnCreate)
    //	ON_MESSAGE(WM_PAINT,OnPaint)
    //END_MESSAGE_MAP()
    
    PTM_WARNING_DISABLE 
    const AFX_MSGMAP* CMyFrameWnd::GetMessageMap() const
    { return GetThisMessageMap(); 
    }
    const AFX_MSGMAP* PASCAL CMyFrameWnd::GetThisMessageMap()
    { 
        typedef CMyFrameWnd ThisClass;
        typedef CFrameWnd TheBaseClass;
        __pragma(warning(push))							   
        __pragma(warning(disable: 4640)) /* message maps can only be called by single threaded message pump */ 
    static const AFX_MSGMAP_ENTRY _messageEntries[] = 
    {
    
    /
    	{ WM_CREATE, 0, 0, 0, AfxSig_lwl,
        	(AFX_PMSG)(AFX_PMSGW) 
        	(static_cast<LRESULT(AFX_MSG_CALL CWnd::*)(WPARAM, LPARAM)> 
        	(OnCreate)) },
    
    	{ WM_PAINT, 0, 0, 0, AfxSig_lwl,
        	(AFX_PMSG)(AFX_PMSGW) 
        	(static_cast<LRESULT(AFX_MSG_CALL CWnd::*)(WPARAM, LPARAM)> 
        	(OnPaint)) },        
    {0, 0, 0, 0, AfxSig_end, (AFX_PMSG)0 } 
    }; 
    __pragma(warning(pop))	
    static const AFX_MSGMAP messageMap = 
    	{ &TheBaseClass::GetThisMessageMap, & _messageEntries[0] }; 
            return &messageMap; 
    }								  
    PTM_WARNING_RESTORE
    LRESULT CMyFrameWnd::OnCreate(WPARAM wParam, LPARAM lParam) {
    	AfxMessageBox("CMyFrameWnd::OnCreate");
    	return 0;
    }
    LRESULT CMyFrameWnd::OnPaint(WPARAM wParam, LPARAM lParam) {
    	PAINTSTRUCT ps = { 0 };
    	CDC* pDC = BeginPaint(&ps);
    	pDC->TextOut(100, 100, "Hello World");
    	EndPaint(&ps);
    	return 0;
    }
    //1. 应用程序类
    class CMyWinApp :public CWinApp {
    public:
    	virtual BOOL InitInstance();
    };
    
    CMyWinApp theApp;
    BOOL CMyWinApp::InitInstance() {
    	CMDIFrameWnd* pFrame = new CMDIFrameWnd;
    	pFrame->Create(NULL, "MFCMsg");
    	m_pMainWnd->ShowWindow(SW_SHOW);
    	m_pMainWnd->UpdateWindow();
    	return TRUE;
    }
    


4.MFC的消息分类

  1. 窗口消息(标准消息)
    与窗口过程相关的消息,以及鼠标、键盘和定时器等消息。
    ON_WM_XXX( )
    例如:
    ON_WM_SIZE()
    ON_WM_CREATE( )
    ON_WM_MOUSEMOVE()
    ON_WM_TIMER( )

  2. 命令消息
    菜单、工具栏和加速键等消息
    ON_COMMAND( 命令ID,处理函数 )

  3. 通知消息
    大部分的控件的消息都属于通知消息
    例如:
    ON_EN_CHANGE(控件ID,处理函数)

  4. 用户自定义消息
    通常用于在两个不同窗口之间传递数据。

    1. 定义消息ID
      #define WM_USE_MYMSG (WM_USER+n)
    2. 消息映射宏
      ON_MESSAGE(消息ID,处理函数)
    3. 添加消息处理函数的声明和实现
      afx_msg LRESULT funName(WPARAM,LPARAM) ;
    4. 触发消息/ 发送消息
      SendMessage/ PostMessage
  5. 参考代码:MsgText.cpp

       #include 
       //定义消息ID
       #define WM_USER_MYMSG (WM_USER+100)
    
       //
       class CMyFrameWnd :public CFrameWnd {
       	afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
       	afx_msg void OnTest();
           afx_msg void OnTestRange(UINT nID);
           afx_msg void OnEnChange();
           afx_msg LRESULT OnMyMsg(WPARAM wParam, LPARAM lParam);
           DECLARE_MESSAGE_MAP()
       };
       
       BEGIN_MESSAGE_MAP(CMyFrameWnd,CFrameWnd)
           ON_WM_CREATE()
           ON_COMMAND(1000,OnTest)
           ON_EN_CHANGE(1010,OnEnChange)
           ON_MESSAGE(WM_USER_MYMSG,OnMyMsg)
           ON_COMMAND_RANGE(1006,1008,OnTestRange)
       END_MESSAGE_MAP()
       LRESULT CMyFrameWnd::OnMyMsg(WPARAM wParam, LPARAM lParam) {
             CString strInfo;
             strInfo.Format("欢迎来到%d公司", wParam + lParam);
              AfxMessageBox(strInfo);
           return 0;
       }
       void CMyFrameWnd::OnEnChange() {
       	CWnd* pEdit = GetDlgItem(1010);
       	CString strText;
       	pEdit->GetWindowText(strText);
       	AfxMessageBox(strText);
       }
       
       void CMyFrameWnd::OnTestRange(UINT nID) {
       	CString strText;
       	// 1. 根据ID,获取控件对象地址
       	CWnd* pButton = GetDlgItem(nID);
       	//2. 获取控件的文本
           pButton->GetWindowText(strText);
       	//3.用消息框显示提示消息
       	AfxMessageBox("您点击了" + strText + "按钮");
       }
       
       void CMyFrameWnd::OnTest() {
       	 //AfxMessageBox("您点击了测试按钮");
       	 //发送信息
           this->SendMessage(WM_USER_MYMSG, 100, 250);
       }
    
       int CMyFrameWnd::OnCreate(LPCREATESTRUCT lpCreateStruct) {
       	//AfxMessageBox("CMyFrameWnd::OnCreate");
           ::CreateWindow("BUTTON", "测试", WS_VISIBLE | WS_CHILD, 100, 100, 100, 40, m_hWnd, (HMENU)1000,           AfxGetInstanceHandle(), NULL);
           ::CreateWindow("BUTTON", "测试6", WS_VISIBLE | WS_CHILD, 100, 200, 100, 40, m_hWnd, (HMENU)1006,           AfxGetInstanceHandle(), NULL);
       	::CreateWindow("BUTTON", "测试7", WS_VISIBLE | WS_CHILD, 100, 300, 100, 40, m_hWnd, (HMENU)1007, AfxGetInstanceHandle(), NULL);
       	::CreateWindow("BUTTON", "测试8", WS_VISIBLE | WS_CHILD, 100, 400, 100, 40, m_hWnd, (HMENU)1008, AfxGetInstanceHandle(), NULL);
       	
       	::CreateWindow("EDIT", "输入框", WS_VISIBLE | WS_CHILD|WS_BORDER, 300, 100, 200, 40, m_hWnd, (HMENU)1010, AfxGetInstanceHandle(), NULL);
       	return 0;
       }
    
       //应用程序类
       class CMyWinApp :public CWinApp {
       public:
           virtual BOOL InitInstance();
       };
       
       CMyWinApp theApp;
       
       BOOL CMyWinApp::InitInstance() {
       	CMyFrameWnd* pFrame = new CMyFrameWnd;
       	pFrame->Create(NULL, "MysgType");
       	m_pMainWnd = pFrame;
       	m_pMainWnd->ShowWindow(SW_SHOW);
       	m_pMainWnd->UpdateWindow();
       	return TRUE;
       }
    


十一、MFC菜单

1.相关类

CMenu类-封装了菜单句柄和操作菜单的API函数。

2.CMenu类的使用

  1. 添加并加载菜单资源
    CMenu::LoadMenu
    MFC框架_第8张图片
    MFC框架_第9张图片

    设置ID : 新建更改ID为ID_NEW ,打开更改ID为 ID_OPEN, 关闭更改ID为ID_CLOSE, 关于更改ID为ID_ABOUT
    MFC框架_第10张图片
    添加源文件

  2. 将菜单设置到窗口
    CWnd::SetMenu

  3. 命令消息
    ON_COMMAND(菜单ID,消息处理函数)
    ON_UPDATE_COMMAND_UI(菜单ID,消息处理函数) //修改菜单的状态

  4. 优先级顺序
    Frame->App

  5. 上下文菜单
    ON_WM_CONTEXTMENU( ),对应的消息处理函数中:

    1. 获取某个菜单项下的子菜单
      CMenu::GetSubMenu

    2. 显示菜单

        BOOL TrackPopupMenu ( 
          UINT nFlags,//对齐方式 
           int x, //左上角的x坐标
           int y, //左上角的y坐标
           CWnd* pWnd, //所属窗口
           LPCRECT lpRect = 0
         );
      

    窗口消息对"消息链"的遍历是在CWnd::OnWndMsg函数中完成的。
    命令消息对"消息链"的遍历是在CCmdTarget::OnCmdMsg函数中完成的
    但是遍历过程是相似的。
    一个类要想处理命令消息,直接或者间接的继承自CCmdTarget类。
    参考代码:MFCMenu.cpp

     #include 
     #include "resource.h"
     
     class CMyFrameWnd :public CFrameWnd {
         DECLARE_MESSAGE_MAP()
     public:
         afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
         afx_msg void OnOpen();
         afx_msg void OnNew();
         afx_msg void OnClose();
         afx_msg void OnAbout();
         afx_msg void OnNewCmdUI(CCmdUI* pCmdUI);
         CMenu m_Menu;  //菜单对象
     };
     BEGIN_MESSAGE_MAP(CMyFrameWnd, CFrameWnd)
        ON_WM_CREATE()
        ON_COMMAND(ID_OPEN,OnOpen)
        ON_COMMAND(ID_NEW,OnNew)
        ON_COMMAND(ID_CLOSE,OnClose)
        ON_COMMAND(ID_ABOUT,OnAbout)  //优先级高于CWinApp 
        ON_UPDATE_COMMAND_UI(ID_NEW,OnNewCmdUI)
     END_MESSAGE_MAP()
     
     //给关于菜单增加命令更新状态信息(10分钟)
     void CMyFrameWnd::OnNewCmdUI(CCmdUI* pCmdUI) {
        pCmdUI->SetCheck(1);   //设置复选状态
     	pCmdUI->SetRadio(TRUE); //  设置单选框
         pCmdUI->SetText("新建文档"); //设置文本
     } 
     
     void CMyFrameWnd::OnAbout() {
         AfxMessageBox("CMyFrameWnd::OnAbout");
     }
     
     void CMyFrameWnd::OnOpen() {
        AfxMessageBox("打开菜单");
     }
     
     void CMyFrameWnd::OnNew() {
        AfxMessageBox("新建菜单");
     }
     
     void CMyFrameWnd::OnClose() {
         ::PostQuitMessage(NULL);
     }
     
      int CMyFrameWnd::OnCreate(LPCREATESTRUCT lpCreateStruct) {
          //添加菜单
         //1.加载菜单资源
         m_Menu.LoadMenu(IDR_MENU1);
     	//2.将菜单设置到窗口
        SetMenu(&m_Menu);
        return 0;
     }
     
     class CMyWinApp :public CWinApp {
     public:
         virtual BOOL InitInstance();
         afx_msg void OnAbout();
     	DECLARE_MESSAGE_MAP()
     };
     
     BEGIN_MESSAGE_MAP(CMyWinApp, CWinApp)
        ON_COMMAND(ID_ABOUT, OnAbout)
     END_MESSAGE_MAP()
     
     CMyWinApp theApp;
     
     void CMyWinApp::OnAbout() {
     	AfxMessageBox("CMyWinApp::OnAbout");
     }
     
     BOOL CMyWinApp::InitInstance() {
        CMyFrameWnd* pFrame = new CMyFrameWnd;
        pFrame->Create(NULL, "MFCMenu");
         m_pMainWnd = pFrame;
        m_pMainWnd->ShowWindow(SW_SHOW);
        m_pMainWnd->UpdateWindow();
        return TRUE;
     }
    


十二、MFC工具栏

1.相关类

CToolBar类-父类是CControlBar类。提供了工具栏的相关操作
#include

2.CToolBar类的使用

  1. 创建工具栏窗口
    CToolBar::Create
  2. 加载工具栏资源
    CToolBar::LoadToolBar
  3. 停靠工具栏
    1. 设置工具栏允许停靠
      CControlBar::EnableDocking

    2. 设置框架窗口允许被停靠
      CFrameWnd::EnableDocking

    3. 停靠工具栏
      CFrameWnd::DockControlBar

    4. 设置工具栏的显示装填
      CFrameWnd::ShowControlBar

    5. 为工具栏按钮添加提示信息
      1> 为工具栏添加风格 CBRS_TOOLTIPS
      2> 为每一个按钮添加提示信息

课堂练习: 创建第二个工具栏,停靠在窗口的右边。通过菜单
设置工具栏的显示状态。



十三、MFC状态栏

1 相关类
CStatusBar类-父类也是CContorolBar类,主要提供状态栏相关操作

2 CStatusBar类的使用
2.1 创建状态栏窗口
CStatusBar::Create
2.2 设置状态栏指示器
CStatusBar::SetIndicators
BOOL SetIndicators(
const UINT* lpIDArray,//数组的地址
int nIDCount//数组长度
);
2.3 设置状态栏信息
CStatusBar::SetPaneText

十四、CDialogBar 类

十五、MFC的视图

1 相关类
CView 类-父类是CWnd类,是专门用于显示数据的窗口。是一个抽象类,
包含了纯虚函数OnDraw()。通常位于框架窗口的客户区。

2 CView类的使用

十六、MFC的视图

1 相关类
CView 类-父类是CWnd类,是专门用于显示数据的窗口。是一个抽象类,
包含了纯虚函数。
2 CView的使用
2.1 窗口销毁问题
CWnd::PostNcDestroy()-该函数会在窗口被销毁后,被默认的
OnNcDestroy()函数调用。派生类通常重写该函数,完成
用户的清理工作,例如:delete this;
void CFrameWnd::PostNcDestroy()
{
delete this;//对象的自销毁
}
void CView::PostNcDestroy()
{
delete this;//对象的自销毁
}
2.2 窗口大小问题,(视图窗口大小能够自适应框架窗口大小)
在框架类中添加WM_SIZE消息的处理函数,在函数中:
调用MoveWindow()函数设置视图窗口的大小。
将视图的ID设置为MFC提供的 AFX_IDW_PANE_FIRST
2.3 对命令消息的处理引入(活动视图)
CFrameWnd::SetActiveView()-设置活动视图
ActiveView->Frame->App
这个顺序是由 CFrameWnd::OnCmdMsg()函数来决定的。
2.4 View、Frame和App之间的关系
CWinApp
|->m_pMainWnd (CFrameWnd)
|->m_pViewActive (CView)
2.5 OnPaint与OnDraw的关系
CMyView::OnPaint()
CView::OnPaint()-> CMyView::OnDraw()

十七、运行时类信息

1 概念
程序在运行的时候,获取对象的类信息以及对象是否属于某个类。
2 条件
2.1 直接或者间接的继承自CObject类
2.2 在类的内部添加声明宏
DECLARE_DYNAMIC(theClass)
在类的外部添加实现宏
IMPLEMENT_DYNAMIC(theClass,baseClass)
3 相关函数
3.1 CObject::GetRuntimeClass()-获取对象的类信息.对象的类信息
保存到一个名为CRuntimeClass的结构体中。
struct CRuntimeClass
{

       LPCSTR m_lpszClassName;//类的名称字符串
       int m_nObjectSize;//对象大小
       UINT m_wSchema; // 类的版本
       
       // 指向创建对象函数的函数指针,目前为NULL
       CObject* (PASCAL* m_pfnCreateObject)(); 
       // 指向父类的相同类型的变量
   	 CRuntimeClass* m_pBaseClass;
   	 ... 
   	}
  3.2 CObject::IsKindOf()-判断对象是否属于某个类 	 

4 实现原理
4.1 宏替换

4.2 成员的作用
4.2.1 classCDog-静态的具有常属性的结构体变量,类型是
CRuntimeClass。作用是保存当前类的名称、
大小和版本。另外还保存了父类的classCAnimal
这个变量的地址。
4.2.2 GetRuntimeClass()-虚函数,作用是获取classCDog的地址。
4.3 成员之间的关系
GetRuntimeClass()
|->&classCDog
|->CDog类的信息,包括类名、大小和版本。
|->&classCAnimal
|->CAnimal类的信息,包括类名、大小和版本
|->&classCObject
|->CObject类的信息,包括类名、大小和版本
|->NULL
形成一个继承层次关系上的类的信息的链表,简称为"信息链"。
4.4 IsKindOf函数的执行过程
dog.IsKindOf(RUNTIME_CLASS(CWnd)) ??
&classCWnd
&classCDog
&classCAnimal TRUE
&classCObject
FALSE

     dog.IsKindOf(RUNTIME_CLASS(CWnd))
     {
        pClassThis <==>&classCDog
        CRuntimeClass* pClassThis = GetRuntimeClass();
        pClass <==>&classCWnd
        return pClassThis->IsDerivedFrom(pClass);
        {
          	// pClassThis <==>&classCDog
          	const CRuntimeClass* pClassThis = this;
          	while (pClassThis != NULL)
          	{
          	   if (pClassThis == pBaseClass)
		             return TRUE;
		         pClassThis = pClassThis->m_pBaseClass;   
          	}
          	return FALSE;   
        }
        
     }

十八、动态创建

1 概念
根据参数的不同,动态的创建对象。
2 条件
2.1 直接或者间接的继承自CObject类
2.2 在类的内部添加动态创建的声明宏
DECLARE_DYNCREATE(theClass)
在类的外部添加动态创建的实现宏
IMPLEMENT_DYNCREATE(theClass,baseClass)
3 实现原理
3.1 展开宏
在运行时类信息的基础上,多了一个创建对象的函数。
3.2 成员的作用
3.2.1 CreateObject()-作用是new 对象。
3.2.2 classCDog-在它的第四个成员 m_pfnCreateObject中
保存了CDog::CreateObject的地址.
3.3 创建过程
CObject* CreateInstance(CRuntimeClass* pClass)
{
return pClass->CreateObject();
{
// 通过函数指针调用它所指向的函数
pObject = (*m_pfnCreateObject)();
{
return new CDog;
}
}
}

十九、MFC的切分窗口

1 分类
1.1 静态切分-在程序编写时,就确定了窗口的切分数量。
1.2 动态切分-在程序编写时,只是指定了窗口切分的最大数量。
在程序运行时,由用户确定窗口具体的切分数量。
2 相关类
CSplitterWnd类-父类是CWnd类。提供了窗口切分的功能。
#include

3 静态切分
3.1 创建静态切分
CSplitterWnd::CreateStatic
BOOL CreateStatic(
CWnd* pParentWnd,//父窗口
int nRows, //行数,最大值为16
int nCols, //列数,最大值为16
DWORD dwStyle = WS_CHILD | WS_VISIBLE,
UINT nID = AFX_IDW_PANE_FIRST
);
3.2 创建视图(视图类一定是支持动态创建的)
CSplitterWnd::CreateView
virtual BOOL CreateView(
int row, //行的索引值
int col, //列的索引值
CRuntimeClass* pViewClass,//RUNTIME_CLASS(类名)
SIZE sizeInit, //初始大小
CCreateContext* pContext//创建上下文
);
3.3 设置活动视图
CSplitterWnd::SetActivePane
3.4 根据索引位置获取视图
CSplitterWnd::GetPane
4 动态切分
BOOL Create(
CWnd* pParentWnd,//父窗口
int nMaxRows, //最大行数,不超过2
int nMaxCols, //最大列出,不超过2
SIZE sizeMin, //最新尺寸
CCreateContext* pContext,//创建上下文,通过它指定所需要的视图类
DWORD dwStyle = WS_CHILD | WS_VISIBLE |WS_HSCROLL |
WS_VSCROLL | SPLS_DYNAMIC_SPLIT,
UINT nID = AFX_IDW_PANE_FIRST
);



二十、MFC的文档

1 文档的概念
用来管理数据的,包括了对数据的保存和加载。
2 相关类
CDocument类-继承自CCmdTarget类,文档类。
3 CDocument类的使用(在视图中显示文档的数据)
3.1 CFrameWnd::InitialUpdateFrame-初始化更新框架。通常在
创建框架窗口之后调用。它会引起所有与该框架相关的视图
的OnInitialUpdate()函数的调用。
3.2 CView::OnInitialUpdate()-是一个虚函数,重写该函数,完成
视图窗口的初始化更新操作。被框架在第一次附加文档之后,
窗口显示之前调用。
3.3 CView::GetDocument()-获取与视图关联的文档
4 创建过程
4.1 框架窗口的WM_CREATE消息处理函数
int CFrameWnd::OnCreate(LPCREATESTRUCT lpcs)
{
return OnCreateHelper(lpcs, pContext);
{
OnCreateClient(lpcs, pContext);
{
CreateView(pContext, AFX_IDW_PANE_FIRST);
{
// 1 动态创建视图对象
CWnd* pView = (CWnd*)pContext->m_pNewViewClass->CreateObject();
// 2 创建视图窗口
pView->Create(…);
}
}
}
}
4.2 视图的WM_CREATE消息处理函数
int CView::OnCreate(LPCREATESTRUCT lpcs)
{
pContext->m_pCurrentDoc->AddView(this);
{
m_viewList.AddTail(pView);
pView->m_pDocument = this;
}
}
一个文档可以保存多个视图地址,文档对视图是一对多。
一个视图可以保存一个视图地址,视图对文档是一对一。
5 四个类之间的关系
CWinApp
|->m_pMainWnd (CFrameWnd)
|->m_pViewActive (CView)
|->m_pDocument (CDocument)
|->m_viewList (CView List)
6 对命令消息的处理顺序
ActiveView->Document->FrameWnd->App

二十一、文档模板类

1 相关类
1.1 CDocTemplate类-抽象基类,定义了文档模板的基本功能。
1.2 CSingleDocTemplate类-父类是CDocTemplate类,用来创建单文档
视图程序。
1.3 CMultiDocTemplate类-父类也是CDocTemplate类,用来创建多文档
视图程序。
2 CSingleDocTemplate 类的使用
CSingleDocTemplate(
UINT nIDResource,//资源ID
CRuntimeClass* pDocClass,//文档类的运行时类信息
CRuntimeClass* pFrameClass,//框架类的运行时类信息
CRuntimeClass* pViewClass//视图类的运行时类信息
);
3 成员之间的关系
CWinApp
|->m_pDocManager (CDocManager)
|->m_templateList (CSingleDocTemplate)
|->m_pOnlyDoc (CDocument)
|->m_pDocTemplate (CSingleDocTemplate)
|->m_pMainWnd (CFrameWnd)
|->m_pViewActive (CView)
|->m_pDocument (CDocument)
|->m_viewList (CView List)

二十二、使用文档模板类创建多文档视图程序

1 相关类
CMultiDocTemplate(
UINT nIDResource,//子框架窗口的资源
CRuntimeClass* pDocClass,
CRuntimeClass* pFrameClass,//子框架窗口的运行时类信息
CRuntimeClass* pViewClass
);
CWinApp类-应用程序类
CMDIFrameWnd-多文档的主框架窗口类
CMDIChildWnd-多文档的子框架窗口类
CView/CEditView类-视图类
CDocument类-文档类
主框架和子框架窗口分别拥有自己的菜单和图标资源
2 创建步骤
2.1 单独创建主框架窗口
2.2 使用文档模板创建文档、子框架和视图(与单文档过程类似)



二十三、使用文档模板创建多文档视图程序

1 相关类
CWinApp类-应用程序类
CMDIFrameWnd类-多文档的主框架窗口类
CMDIChildWnd类-多文档的子框架窗口类
CView/CEditView类-视图类
CDocument类-文档类
2 创建过程
与单文档类似
3 多个视图数据同步的案例
3.1 "新建"菜单-创建新的文档、子框架和视图。
3.2 "新建窗口"菜单-基于原有活动视图对应的文档,创建新的子框架
和视图窗口。产生的效果是一个文档对应多个视图。
1> 获取当前活动文档
CFrameWnd::GetActiveDocument
2> 根据文档获取文档模板
CDocTemplate* GetDocTemplate( ) const;
3> 创建新的子框架(视图会一并创建)
CDocTemplate::CreateNewFrame
4> 初始化更新框架窗口
CFrameWnd::InitialUpdateFrame
在子框架窗口类中实现"新建窗口"的菜单消息
3.3 捕获活动视图内容发生变化的消息
1> 获取与之关联的文档
CView::GetDocument
2> 将用户在视图中输入的数据保存到文档中
CWnd::GetWindowText
3> 更新所有视图(文档通知其它视图数据更新了)
CDocument::UpdateAllViews
3.4 重写CView::OnUpdate函数,在函数中:
4> 获取与之关联的文档
CView::GetDocument
5> 将文档的数据放到视图窗口中显示
CWnd::SetWindowText

二十四、MFC绘图

1 相关类
1.1 绘图设备类(纸)
1.1.1 CDC类-绘图设备类中的顶层父类。提供了绘图设备的基本功能。
可以表示一般的绘图设备。例如:打印机、显示器等。
1.1.2 CClientDC类-父类是CDC类,可以表示指定窗口的客户区。
1.1.3 CPaintDC类-父类也是CDC类,也表示指定窗口的客户区。
只在WM_PAINT的消息处理函数OnPaint中使用。
1.2 绘图对象类 (笔)
2 绘图设备类的使用
2.1 CDC类的使用
2.1.1 创建DC
virtual BOOL CreateDC(
LPCTSTR lpszDriverName,//设备的驱动名称
LPCTSTR lpszDeviceName, //设备名称
LPCTSTR lpszOutput, //设备的接口名称
const void* lpInitData//设备的初始化参数
);
如果表示显示器:
CreateDC(“DISPLAY”,NULL,NULL,NULL);

     2.1.2 使用DC
     MoveTo/LineTo/Arc/Rectangle/Elipse...
     2.1.3 删除DC
     DeleteDC
2.2 CClientDC 、CPaintDC类的使用
    只需要在构造函数的参数中指定窗口对象地址即可。

3 绘图对象类的使用
3.1 CPen类-画笔
3.2 CBrush类-画刷
3.3 CFont类-字体
3.4 CBitmap类-位图
3.5 CPalette类-调色板,本质上,它是一个颜色表。
24位,RGB(0255,0255,0~255)

3.6 CRgn 类-区域(区域的几何运算)
3.6.1 创建区域
CRgn::CreateXXX
3.6.2 几何运算 (可以多次运算)
CRgn::CombineRgn
3.6.3 填充区域
CDC::FillRgn



二十五、文件操作

1 相关类
CFile类-封装了文件句柄和操作文件的API。
CFileFind类-提供了文件查找操作。
2 CFile类的使用
2.1 新建或者打开文件
CFile::Open
2.2 文件读写
CFile::Read/Write
2.3 关闭文件
CFile::Close
2.4 文件指针位置
CFile::SeekToBegin
CFile::SeekToEnd
注意两个问题:1>文件操作通常放到异常处理结构中
2>读写时,注意文件指针位置
3 CFileFind类的实现
3.1 开始查找(指定在哪个目录下查找)
CFileFind::FindFile
3.2 查找下一个(返回值是BOOL,表示下一个文件是否存在)
CFileFind::FindNextFile
3.3 获取/判断文件信息
CFileFind::GetXXX
CFileFind::IsXXX
3.4 关闭查找
CFileFind::Close
案例1:查找并输出指定目录下的文件和子目录。
案例2:查找并输出指定目录下的所有文件和子目录。

二十六、序列化

1 相关类
CArchive类-归档类,可以使用它替代CFile::Read/Write函数完成
具体的读写操作。
2 CArchive类的使用
2.1 新建或者打开文件
CFile::Open
2.2 文件读写
2.2.1 定义CArchive类的对象
2.2.2 读写操作
>> 读操作
<< 写操作
2.2.3 关闭
CArchive::Close( )
2.3 关闭文件
CFile::Close

二十七、对象的序列化

1 概念
将对象作为整体以二进制流的方式依次写入到文件或从文件中读取的过程
2 条件
2.1 直接或者间接的继承自CObject类。
2.2 在类中添加序列化的声明宏
DECLARE_SERIAL(theClass)
在类外添加序列化的实现宏
IMPLEMENT_SERIAL(theClass,baseClass,版本)
2.3 重写CObject::Serialize 函数,在函数中完成类的成员的序列化

作业: 1> 定义一个Car类{band:“奔驰”、“奥迪”、"bmw"等
price:} 版本为:1
写入并读取一个Car对象。
2> 修改Car类,增加一个成员,color: “白色”、"黑色"等
版本:2
写入并读取一个新的Car对象
还能够读取一个原来的Car对象。

二十八、MFC对话框

1 分类
模式对话框-阻塞的
非模式对话框
2 相关类
2.1 CDialog类-继承自CWnd类,提供了对话框的基本操作。
2.2 CCommonDialog类-继承自CDialog类,通用对话框类。包括以下
几个子类,分别是:文件对话框、颜色对话框、字体对话框、
查找替换对话框、打印对话框以及页面设置对话框。
3 模式对话框
3.1 添加对话框资源,并与对话框的类关联
3.2 创建和显示模式对话框
CDialog::DoModal
3.3 关闭
CDialog::OnOK/OnCancel
4 非模式对话框
4.1 添加对话框资源,并与对话框的类关联
4.2 创建和显示非模式对话框
与一般的框架窗口类似
4.3 关闭
4.3.1 重写CDialog::OnOK和OnCancel函数,在函数中:
DestroyWindow();
4.3.2 重写CWnd::PostNcDestroy函数,在函数中:
delete this;
5 在MFC向导生成的Sdi程序中分别窗口模式和非模式对话框



二十九、对话框数据交换技术

1 概念
将控件与对话框类的成员变量绑定,通过操作变量的方式达到
操作控件的目的。
2 实现步骤
2.1 在对话框类中添加与控件相关的变量
变量可以有两种类型:Control类型、Value类型。
如果我们选择Control类型,可以通过调用对象的成员函数操作
控件;如果我们选择Value类型,可以将变量的值与用户在控件中输入
值做交换。
2.2 重写CWnd::DoDataExchange函数,在函数中完成控件与变量的
绑定。
2.3 如果选择的是控件类型,就可以调用对象的成员函数操作控件。
如果选择的是值类型, 还需要调用 UpdateData(BOOL)
UpdateData(TRUE)-将用户在控件中输入的值传递给变量。
控件=>变量
UpdateData(FALSE)-将变量放到控件中显示。
变量=>控件

三十、MFC的各种控件

1 静态控件
包括静态文本、分组框和图标。自动生成的ID都为IDC_STATIC。
2 按钮控件
下压式按钮、单选按钮和复选按钮。控件类都是CButton类。
3 编辑框控件 控件类是CEdit
4 组合框控件和列表框控件
组合框控件对应的控件类CComboBox类
列表框控件对应的控件类是CListBox类。
这个两个控件都可以包含多个选项,每个选项都是字符串。
不同的是组合框控件可以选择也可以输入,但是结果只有一个选项。
列表控件可以在多个选项中选择一项也可以选择多项。
5 旋转按钮、进度条和滑块控件
5.1 旋转按钮-控件类是CSpinButtonCtrl类。
5.2 进度条-控件类是CProgressCtrl类。
5.3 滑块-控件类是CSliderCtrl类。
6 列表控件-控件类是CListCtrl类。
6.1 设置控件的图标列表



三十一、树控件

1 相关类
CTreeCtrl类
2 CTreeCtrl类的使用
2.1 设置树控件的图标列表
CTreeCtrl::SetImageList
2.2 插入树节点
CTreeCtrl::
HTREEITEM InsertItem(
LPCTSTR lpszItem, //节点文本
int nImage,//节点图标
int nSelectedImage,//节点被选中时图标
HTREEITEM hParent = TVI_ROOT,//如果采用缺省值,表示插入的节点是根节点;如果插入的是非根节点,通过该参数指定父节点。
HTREEITEM hInsertAfter = TVI_LAST//如果采用缺省值,表示在末尾添加节点;否则,在该参数指定的节点后添加新插入的节点。
);
2.3 获取当前选中节点
CTreeCtrl::GetSelectedItem
2.4 删除节点
CTreeCtrl::DeleteItem
2.5 修改节点
CTreeCtrl::SetItemText

三十二、Tab控件

三十三、MFC的多线程

1 分类
1.1 工作者线程
在创建的子线程中不包含用户界面。主要完成后台耗时的操作。
1.2 用户界面线程
在创建的子线程可以包含用户界面。
2 实现
2.1 工作者线程的实现
CWinThread* AfxBeginThread(
AFX_THREADPROC pfnThreadProc,//线程函数
LPVOID pParam, //参数,用来在主子线程之间传递数据
int nPriority = THREAD_PRIORITY_NORMAL,//线程的优先级
UINT nStackSize = 0, //栈的大小
DWORD dwCreateFlags = 0, //创建标志
LPSECURITY_ATTRIBUTES lpSecurityAttrs = NULL//安全属性
);
线程函数的原型:
UINT MyControllingFunction( LPVOID pParam );
2.2 用户界面线程
CWinThread* AfxBeginThread(
CRuntimeClass* pThreadClass, //线程类
int nPriority = THREAD_PRIORITY_NORMAL,
UINT nStackSize = 0,
DWORD dwCreateFlags = 0,
LPSECURITY_ATTRIBUTES lpSecurityAttrs = NULL
);

三十四、企业的上机题

三十五、基于windows平台的数据库访问技术

1 ODBC-Open Database Connectivity,微软开放式数据互联。一组用于
访问和操作数据库的API。可以使用一组API访问不同类型的数据库,
前提是首先需要将数据库设置为ODBC数据源。MFC将这组API做了封装,
提供了ODBC类。
2 ODBC数据源的设置
2.1 32位操作系统
控制面板\系统和安全\管理工具\数据源ODBC
2.2 64位操作系统
C:\Windows\SysWOW64\odbcad.exe
3 相关类
3.1 CDatabase类-主要提供了连接和关闭数据库的功能。
3.2 CRecordset类-主要提供了对数据表的操作。
#include
4 使用步骤
4.1 连接数据库
CDatabase::Open
4.2 关闭数据库
CDatabase::Close



MFC的第二部分

一、基于windows平台的数据库访问技术

1 ODBC-Open Database Connectivity,微软开放式数据互联。一组用于
访问和操作数据库的API。可以使用一组API访问不同类型的数据库,
前提是首先需要将数据库设置为ODBC数据源。MFC将这组API做了封装,
提供了ODBC类。
2 ODBC数据源的设置
2.1 32位操作系统
控制面板\系统和安全\管理工具\数据源ODBC
2.2 64位操作系统
C:\Windows\SysWOW64\odbcad.exe
3 相关类
3.1 CDatabase类-主要提供了连接和关闭数据库的功能。
3.2 CRecordset类-主要提供了对数据表的操作。
#include
4 使用步骤
4.1 连接数据库
CDatabase::Open
4.2 关闭数据库
CDatabase::Close
4.3 打开记录集(将表的数据读取到记录集(内存的一个对象))
CRecordset::Open
4.4 记录集中字段的数量
CRecordset::GetODBCFieldCount
4.5 记录集中字段的信息(包含了字段的名称)
CRecordset::GetODBCFieldInfo
4.6 获取记录集中字段的值
CRecordset::GetFieldValue
4.7 记录集的指针操作
CRecordset::MoveNext
CRecordset::MovePrevious
CRecordset::MoveFirst
CRecordset::MoveLast
CRecordset::IsBOF
CRecordset::IsEOF
4.8 执行Sql语句
CDatabase::ExecuteSQL
登录按钮的消息处理中的代码
select count(*) from admin where loginId=‘%s’ and pwd=‘%s’;

     set.GetFieldValue((short)0,count);
     int nCount = atoi(count);  
     if(nCount>0)
     {
        CDialog::OnOK();
     }
     else
     {
        AfxMessageBox(“error”);
     }  

二、案例场景:汽车租赁系统

1 管理员表
2 汽车 : ID、品牌、颜色、租赁价格 …、状态:
3 租赁记录(出租/还车的记录):租赁人、身份证、汽车ID、天数



三、使用Ado访问数据库

1 Ado介绍
Ado是一个独立于MFC的单独的COM组件。通过接口对外提供服务。

2 相关文件
文件:msado15.dll
路径: C:\Program Files\Common Files\System\ado\msado15.dll
3 在MFC中导入Ado组件
通常在stdafx.h文件中导入:
#import 文件路径 no_namespace rename(“EOF”,“adoEOF”)
生成项目,在项目的Debug目下,生成msado15.tlh和msado15.tli两个
文件。

4 使用COM
4.1 通常在App类的InitInstance函数中初始化COM库
HRESULT CoInitialize(LPVOID pvReserved );

 4.2 通常在App类的ExitInstance函数中卸载COM库   
     void CoUninitialize( );
  1. Ado组件的接口类
    5.1 _ConnectionPtr类-类似于ODBC类的CDatabase类。功能主要是
    连接和关闭数据库。
 5.2 _RecordsetPtr类-类似于ODBC类的CRecordset类。功能主要是
                     对记录集的操作。
                           
 组件接口类的函数的参数类型与C++的类型不同:
 例如 MFC的字符串类型是CString,COM的字符串类型是 _bstr_t。
      COM中还有一种类型叫可变类型 _variant_t。
 所以,为了避免类型转换带来的复杂性,我们会将Ado组件的接口类
 做一个封装,封装成c++的类,只在封装时,做一个类型转换。以后再
 使用时,直接使用封装类即可。
  1. _ConnectionPtr类的使用
    6.1 打开数据库
    HRESULT Open (
    _bstr_t ConnectionString,//连接字符串
    _bstr_t UserID,//登录ID,通常写""
    _bstr_t Password,//登录密码,通常写""
    long Options//选项,通常为 -1.
    );
    不同的数据库产品,连接字符串各不相同。即使是相同的数据库类型,
    由于版本不同,连接字符串也不一样。
    Provider=Microsoft.ACE.OLEDB.12.0;Data Source=D:\stuDB.accdb
    6.2 关闭数据库
    Close
    6.3 执行Sql语句

7 _RecordsetPtr类的使用
7.1 打开记录集
HRESULT Open (
const _variant_t & Source,//Sql语句\表名\存储过程
const _variant_t & ActiveConnection,//基于的数据库连接
enum CursorTypeEnum CursorType,//游标类型
enum LockTypeEnum LockType,//记录集的锁定类型
long Options//选项,标识第一个参数,adCmdText/adCmdTable/adCmdStoredProc
);
7.2 获取字段的数量
Fields->GetCount();
7.3 获取字段的名称
Fields->GetItem(nIndex)->GetName();//_bstr_t类型
7.4 获取字段的值
Fields->GetItem(nIndex)->GetValue();//_variant_t类型
7.5 记录集的指针操作
MoveFirst();
MoveLast();
MovePrevious();
MoveNext();
IsEOF();
IsBOF();



MFC的第三部分

一、Windows平台的网络通信编程(socket)

1 简单介绍
1.1 基本的socket函数
1.2 以WSA开头的socket函数-主要提供异步网络通信操作
1.3 MFC部分的封装了以WSA开头的socket函数
2 相关文件 (以2.2版本的库为例)
2.1 dll文件: ws2_32.dll
2.2 h文件: winsock2.h
2.3 lib文件:ws2_32.lib
3 使用步骤
3.1 加载socket库
int WSAStartup(
WORD wVersionRequested,//请求使用的库的版本
LPWSADATA lpWSAData//返回可用的库的信息
);

3.2 使用库函数
TCP通信或UDP通信

3.3 卸载socket库
WSACleanup
4 TCP通信
4.1 服务器
4.1.1 创建
4.1.2 绑定
4.1.3 监听
4.1.4 接收客户端连接 (阻塞函数)
4.1.5 通信
4.1.6 关闭
4.2 客户端
4.2.1 创建
4.2.2 连接
4.2.3 通信
4.2.4 关闭
5 UDP通信
5.1 服务器
5.1.1 创建
5.1.2 绑定
5.1.3 通信
5.1.4 关闭
5.2 客户端
5.2.1 创建
5.2.2 通信
5.2.3 关闭
6 MFC的socket类
6.1 相关类
6.1.1 CAsyncSocket类-异步socket类。
6.1.2 CSocket类-继承自CAsyncSocket类,同步socket类。
6.2 完成一个文件传输的例子

二、远程控制项目

你可能感兴趣的:(Linux,C,C++,mfc,c++,ux,后端)