zoukankan      html  css  js  c++  java
  • 5.MFC基础(五)视图、运行时类信息、动态创建

    一、MFC的视图窗口

     1.相关问题

       视图窗口:提供了一个用于显示数据的窗口,并和用户进行交互操作

     2.相关的类

       CView及其子类 - 父类CWnd,封装了关于视图窗口的操作

     3.视图窗口的使用

      (1)从CView类派生一个自己的视图类(CMyView),并必须重写父类的纯虚函数OnDraw

         当CView类帮我们处理WM_PAINT消息时将调用OnDraw

      (2)在框架窗口的WM_CREATE消息处理中:new一个CMyVIew类对象(pView),并调用Create函数,完成视图窗口的创建

     4.命令消息(WM_COMMAND)处理顺序

       View  -->  Frame  -->  App

       CFrameWnd::OnCmdMsg函数内部代码执行的先后顺序决定的

     5.对象的关系图

       m_pMainWnd = pFrame;

       m_pViewActive = pView;

       theApp

          |------->m_pMainWnd(框架类对象地址pFrame)

                                         |------->m_pViewActive(视图类对象地址pView)

      相关代码:

    #include "stdafx.h"
    
    
    class CMyView :public CView
    {
        DECLARE_MESSAGE_MAP()
    public:
        virtual void OnDraw(CDC* pDC);
    public:
        afx_msg void OnPaint();
        afx_msg void OnNew();
    };
    BEGIN_MESSAGE_MAP(CMyView, CView)
        ON_COMMAND(ID_NEW, OnNew)
        //ON_WM_PAINT()
    END_MESSAGE_MAP()
    
    void CMyView::OnNew()
    {
        AfxMessageBox(L"视图类处理了新建被点击");
    }
    void CMyView::OnPaint()
    {
        PAINTSTRUCT ps = { 0 };
        HDC hdc = ::BeginPaint(this->m_hWnd, &ps);
        ::TextOut(hdc, 200, 200, L"CMyView::OnPaint", 16);
        ::EndPaint(this->m_hWnd, &ps);
    }
    
    void CMyView::OnDraw(CDC* pDC)
    {
        pDC->TextOutW(100, 100, "CMyView::OnDraw");
    }
    
    class CMyFrameWnd :public CFrameWnd
    {
        DECLARE_MESSAGE_MAP()
    public:
        afx_msg void OnPaint();
        afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
    
    };
    BEGIN_MESSAGE_MAP(CMyFrameWnd, CFrameWnd)
        ON_WM_CREATE()
        ON_WM_PAINT()
    END_MESSAGE_MAP()
    
    int CMyFrameWnd::OnCreate(LPCREATESTRUCT lpCreateStruct)
    {
        CMyView *pView = new CMyView;
        this->m_pViewActive = pView;
        pView->Create(NULL, L"", WS_VISIBLE|WS_CHILD|WS_BORDER, CRect(0, 0, 100, 100), 
            this, AFX_IDW_PANE_FIRST);
        return CFrameWnd::OnCreate(lpCreateStruct);
    }
    
    void CMyFrameWnd::OnPaint()
    {
        PAINTSTRUCT ps = { 0 };
        HDC hdc = ::BeginPaint(this->m_hWnd, &ps);
        ::TextOut(hdc, 100, 100, L"我是框架窗口客户区", 9);
        ::EndPaint(this->m_hWnd, &ps);
    }
    
    class CMyWinApp :public CWinApp
    {
    public:
        virtual BOOL InitInstance();
    };
    
    CMyWinApp theApp;
    
    BOOL CMyWinApp::InitInstance()
    {
        CMyFrameWnd *pFrame = new CMyFrameWnd;
        m_pMainWnd = pFrame;
        pFrame->Create(NULL, L"MFC View", WS_OVERLAPPEDWINDOW, 
            CFrameWnd::rectDefault, NULL, MAKEINTRESOURCE(IDR_MENU1));
        pFrame->ShowWindow(SW_SHOW);
        pFrame->UpdateWindow();
        return TRUE;
    }
    View Code

      运行结果:

      

    二、运行时类信息机制(MFC第四大机制)

     1.运行时类信息机制的作用

       在程序执行过程中,可以通过这个机制获知对象相关类的信息(获知一个对象是不是某个类的对象)

     2.运行时类信息机制的使用

      (1)类必须派生自CObject

      (2)类内必须添加声明宏 DECLARE_DYNAMIC

      (3)类外必须添加实现宏 IMPLEMENT_DYNAMIC

         CObject::IsKindOf( ) - 可以判断对象是不是属于某个类

     3.运行时类信息实现

      (1)数据结构

        struct  CRuntimeClass(宏展开静态变量的类型)
        {
          LPCSTR    m_lpszClassName;                       //类名称

          int           m_nObjectSize;                           //类的大小sizeof

          UINT        m_wSchema;                               //类的版本0xFFF

          CObject* (PASCAL* m_pfnCreateObject)( );  //用于动态创建机制,此处没用,为NULL

          CRuntimeClass*  m_pBaseClass;                  //父类静态变量地址(负责连接链表)

          CRuntimeClass*  m_pNextClass;                   //运行时类信息为NULL

        };

      (2)宏展开代码

         见代码

      (3)宏展开各部分的作用

         classCDog - 静态变量,保存了关于类的相关信息(类名、大小、版本...)

         GetRuntimeClass( ) - 虚函数,获取本类静态变量地址(获取链表头结点地址)

      (4)关系图

         GetRuntimeClass( )

                          |->类名/大小/版本

               |->&classCDog

                                   |->类名/大小/版本

               |->&classCAnimal

                                             |->类名/大小/版本

                                             |->&classCObject

                                                         |->类名/大小/版本

                                                         |->NULL   

      (5)IsKindOf的实现

         利用类对象(yellowDog)调用宏展开的虚函数GetRumtimeClass获取本类静态变量地址(&classCDog链表头结点)

         利用&classCDog和目标(IsKindOf的参数)进行比对,如果相等,证明yellowDog属于该类;如果不相等,利用&classCDog

         第五个成员获取父类静态变量,和目标进行循环比对,只要又一次比对成功,也能证明yellowDog属于该类

         如果循环结束一次比对都不成功才证明yellowDog不属于这个类

        伪代码: 

        yellowDog.IsKindOf( RUNTIME_CLASS( CObject ) )

        {

          CRuntimeClass*  pClassThis  =  GetRuntimeClass( );  //获得链表头结点地址

          return  pClassThis->IsDerivedFrom( RUNTIME_CLASS( CObject ) )  //函数内部this为链表头结点,参数为链表尾节点

          {

            const CRuntimeClass*  pClassThis  =  this;  //获取链表头结点

            while ( pClassThis  !=  NULL )

            {        

              if  ( pClassThis  ==  RUNTIME_CLASS( CObject ) )
                return  TRUE;

              pClassThis  =  pClassThis->m_pBaseClass;

            }

            return  FALSE;

          }

        }   

      附:RUNTIME_CLASS( theClass )  ==>  &theClass::classtheClass

        括号中指明的类的静态变量地址

      相关代码: 

    #include "stdafx.h"
    
    class CAnimal : public CObject
    {
        DECLARE_DYNAMIC(CAnimal)
    
    };
    IMPLEMENT_DYNAMIC(CAnimal, CObject)
    
    class CDog : public CAnimal
    {
    public:
        static const CRuntimeClass classCDog;
        virtual CRuntimeClass* GetRuntimeClass() const;
    };
    
    AFX_COMDAT const CRuntimeClass CDog::classCDog = {
        "CDog", 
        sizeof(class CDog), 
        0xFFFF, 
        NULL,
        ((CRuntimeClass*)(&CAnimal::classCAnimal)),
        NULL
    }; 
    CRuntimeClass* CDog::GetRuntimeClass() const
    { 
        return ((CRuntimeClass*)(&CDog::classCDog));
    }
    
    int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])
    {
        CDog yellowDog;
        if (yellowDog.IsKindOf(RUNTIME_CLASS(CObject)))
        {
            printf("yellowDog is CObject
    ");
        }
        else
        {
            printf("yellowDog is not CObject
    ");
        }
        return 0;
    }
    View Code

      运行结果:

      

     三、动态创建机制(MFC第五大机制)

      1.动态创建机制的作用

        在不知道类名的情况下,将类的对象创建出来

      2.动态创建机制的使用

       (1)类必须派生自CObject

       (2)类内必须添加声明宏 DECLARE_DYNCREATE

       (3)类外必须添加实现宏 IPLEMENT_DYNCREATE

          CRuntimeClass::CreateObject - 负责动态创建类的对象

      3.动态创建机制的实现

       (1)宏展开代码

          见代码

       (2)宏展开各部分的作用(和运行时类信息机制的区别)

          多了一个静态函数CDog::CreateObject(new了一个CDog类对象)

          静态变量的第四个成员不在为NULL,保存了新增加静态函数的地址(函数名称)

       (3)CRuntimeClass::CreateObject执行过程

          利用CDog类静态变量(&CDog::classCDog)的第四个成员获取新增加静态函数(CDog::CreateObject)

          调用这个静态函数(CDog::CreateObject),在这个静态函数内部new了一个CDog对象,并将对象地址返回

           伪代码:

          CObject *pObj = RUNTIME_CLASS(CDog)->CreateObject( )  //this为&classCDog,链表头结点

          {

            CObject*  pObject  =  ( *m_pfnCreateObject )( )  //CDog::CreateObject,pObject就是CDog

            {

              return  new  CDog;

            }

            return  pObject;  //把CDog返回

          }

      相关代码:

    #include "stdafx.h"
    
    
    class CAnimal :public CObject
    {
        DECLARE_DYNCREATE(CAnimal)
    };
    IMPLEMENT_DYNCREATE(CAnimal, CObject)
    
    class CDog :public CAnimal
    {
    public: 
        static const CRuntimeClass classCDog; 
        virtual CRuntimeClass* GetRuntimeClass() const; 
        static CObject* PASCAL CreateObject();
    };
    
    CObject* PASCAL CDog::CreateObject()
    {
        return new CDog;
    }
    
    AFX_COMDAT const CRuntimeClass CDog::classCDog = { 
        "CDog",
        sizeof(class CDog),
        0xFFFF,
        CDog::CreateObject,
        ((CRuntimeClass*)(&CAnimal::classCAnimal)),
        NULL
    }; 
    
    CRuntimeClass* CDog::GetRuntimeClass() const 
    {
        return ((CRuntimeClass*)(&CDog::classCDog));
    }
    
    int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])
    {
        CObject *pObj = RUNTIME_CLASS(CDog)->CreateObject();
        if (pObj->IsKindOf(RUNTIME_CLASS(CDog)))
        {
            printf("pObj is CDog
    ");
        }
        else
        {
            printf("pObj is not CDog
    ");
        }
        return 0;
    }
    View Code

      运行结果:

      

      

  • 相关阅读:
    java 多线程 继承Thread和实现Runnable的区别
    TCP和UDP的区别
    重载与覆盖(java)
    感悟
    ant design + react带有二级导航菜单自动生成
    自己搭建ant design框架
    ant design框架学习
    radio美化
    nodejs-微信公众号 ----答疑机器人
    微信小程序----开发小技巧(二)
  • 原文地址:https://www.cnblogs.com/csqtech/p/5689175.html
Copyright © 2011-2022 走看看