• 6.MFC基础(六)窗口切分、文档类


    一、切分窗口

      1.切分窗口分类

       静态切分 - 在窗口创建出来的时候就已经完成切分

       动态切分 - 在程序执行过程中根据用户的需要实时完成切分,最多只能切出2*2个(最多2行2列)

      2.相关类

       CSplitterWnd - 父类CFrameWnd(只有一个客户区的窗口叫规则框架窗口),封装了关于不规则窗口的操作

      3.静态切分

       (1)定义CSplitterWnd类对象

       (2)重写CFrameWnd::OnCreateClient函数

          创建不规则框架窗口

            BOOL  CSplitterWnd::CreateStatic( CWnd*    pParentWnd,                                    //父窗口对象地址

                                                                             int           nRows,                                            //行数

                                                                             int           nCols,                                              //列数

                                                                             DWORD   dwStyle = WS_CHILD | WS_VISIBLE,  //窗口风格

                                                                             UINT        nID = AFX_IDW_PANE_FIRST );         //ID

          给不规则框架窗口的各个客户区创建视图窗口

            virtual  BOOL  CSplitterWnd::CreateView( int                       row,             //行

                                                                                      int                       col,              //列

                                                                                      CRuntimeClass*    pViewClass,  //视图类对象地址

                                                                                      SIZE                    sizeInt,        //大小

                                                                                      CCreateContext*  pContext );   //上下文

      相关代码:

    #include "stdafx.h"
    
    
    class CMyView : public CView
    {
        DECLARE_DYNCREATE(CMyView)
    public:
        virtual void OnDraw(CDC *pDC);
    };
    IMPLEMENT_DYNCREATE(CMyView, CView)
    
    void CMyView::OnDraw(CDC* pDC)
    {
        pDC->TextOutW(100, 100, L"自己的视图");
    }
    
    class CMyFrameWnd : public CFrameWnd
    {
    public:
        virtual BOOL OnCreateClient(LPCREATESTRUCT lpcs, CCreateContext* pContext);
    private:
        //定义切分窗口对象
        CSplitterWnd m_split1;  //日字形
        CSplitterWnd m_split2;  //倒日字形
    };
    //重写虚函数
    BOOL CMyFrameWnd::OnCreateClient(LPCREATESTRUCT lpcs, CCreateContext* pContext)
    {
        //创建日字形不规则窗口,2行1列
        m_split1.CreateStatic(this, 2, 1); 
        //创建倒日字形不规则窗口,1行2列
        m_split2.CreateStatic(&m_split1, 1, 2, WS_CHILD|WS_VISIBLE, m_split1.IdFromRowCol(0, 0));//将倒日字放到日字的0行0列  
        
        //给倒日字创建视图窗口
        m_split2.CreateView(0, 0, RUNTIME_CLASS(CMyView), CSize(100, 100), pContext);
        m_split2.CreateView(0, 1, RUNTIME_CLASS(CEditView), CSize(100, 100), pContext);
        m_split1.CreateView(1, 0, RUNTIME_CLASS(CHtmlView), CSize(100, 100), pContext);
    
        CHtmlView *pView = (CHtmlView*)m_split1.GetPane(1, 0);
        pView->Navigate(L"www.baidu.com");
    
        //设置行列信息
        m_split1.SetRowInfo(0, 200, 100);  //高200,最小100
        m_split2.SetColumnInfo(0, 400, 200); //宽400,最小200
    
        return TRUE;
    }
    
    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 Split");
        pFrame->ShowWindow(SW_SHOW);
        pFrame->UpdateWindow();
        return TRUE;
    }
    View Code

      运行结果:

      

     4.动态切分

      (1)定义CSplitterWnd类对象

      (2)重写CFrameWnd::OnCreateClient虚函数

         CSplitterWnd::Create创建切分

      先关代码: 

    #include "stdafx.h"
    
    
    class CMyView : public CView
    {
        DECLARE_DYNCREATE(CMyView)
    public:
        virtual void OnDraw(CDC *pDC);
    };
    IMPLEMENT_DYNCREATE(CMyView, CView)
    
    void CMyView::OnDraw(CDC* pDC)
    {
        pDC->TextOutW(100, 100, L"自己的视图");
    }
    
    class CMyFrameWnd : public CFrameWnd
    {
    public:
        virtual BOOL OnCreateClient(LPCREATESTRUCT lpcs, CCreateContext* pContext);
    private:
        CSplitterWnd m_split;
    };
    
    BOOL CMyFrameWnd::OnCreateClient(LPCREATESTRUCT lpcs, CCreateContext* pContext)
    {
        CCreateContext cct;
        cct.m_pNewViewClass = RUNTIME_CLASS(CMyView);
        m_split.Create(this, 2, 2, CSize(100, 100), &cct);
        return TRUE;
    }
    
    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 Split");
        pFrame->ShowWindow(SW_SHOW);
        pFrame->UpdateWindow();
        return TRUE;
    }
    View Code

      运行结果:

      

    二、MFC的文档

      1.相关问题

        文档主要提供了对数据的管理,以及和视图窗口的交互  

        CDocument - 父类CCmdTarget

      2.相关类     

       (1)利用pFrame调用LoadFrame函数创建主框架窗口(之前是用的Create函数) 

       (2)在框架窗口的WM_CREATE消息处理中创建视图窗口

       (3)在视图窗口的WM_CREATE消息处理中将视图类对象和文档类对象建立绑定关系  

          m_viewList.AddTail( pView );  

          pView->m_pDocument  =  this; 

          经过分析可知:文档类对象用一个链表成员和它关联的视图类对象,说明一个文档类对象可以对应多个视图类对象

                          视图类对象用一个普通成员变量保存和它关联的文档类对象,说明一个视图类对象只能对应一个文档类对象

      3.对象关系图

        theApp

          |->m_pMainWnd(框架类对象)

               |->m_pViewActive(视图类对象)

                     |->m_pDocument(文档类对象)

                             |->m_viewList(视图类对象)

      4.文档类和视图类的关系

        CDocument::UpdateAllViews - 刷新和文档类对象关联的所有视图类对象(视图窗口)

        CView::OnUpdate - 虚函数,当视图窗口刷新时被调用

      相关代码:

    #include "stdafx.h"
    
    /*************************************************
    CMyDoc
    *************************************************/
    class CMyDoc : public CDocument
    {
        DECLARE_MESSAGE_MAP()
    public:
        afx_msg void OnNew();
    public:
        CString m_strDoc;
    
    };
    BEGIN_MESSAGE_MAP(CMyDoc, CDocument)
        ON_COMMAND(ID_NEW, OnNew)
    END_MESSAGE_MAP()
    
    void CMyDoc::OnNew()
    {
        m_strDoc = "hello doc, 这叫老夫如何是好";
        UpdateAllViews(NULL);
    }
    /************************************************
    CMyView
    ************************************************/
    class CMyView : public CEditView
    {
        DECLARE_MESSAGE_MAP()
        DECLARE_DYNCREATE(CMyView)
    public:
        afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
    public:
        virtual void OnUpdate(CView* pSender, LPARAM lHint, CObject* pHint);
    };
    BEGIN_MESSAGE_MAP(CMyView, CEditView)
        ON_WM_CREATE()
    END_MESSAGE_MAP()
    IMPLEMENT_DYNCREATE(CMyView, CEditView)
    
    void CMyView::OnUpdate(CView* pSender, LPARAM lHint, CObject* pHint)
    {
        CMyDoc*pDoc = (CMyDoc*)m_pDocument;
        SetWindowText(pDoc->m_strDoc);
    }
    
    int CMyView::OnCreate(LPCREATESTRUCT lpCreateStruct)
    {
        return CEditView::OnCreate(lpCreateStruct);//将视图类对象和文档类对象建立绑定关系
    }
    
    /********************************************************
    CMyFrameWnd
    *********************************************************/
    class CMyFrameWnd :public CFrameWnd
    {
        DECLARE_MESSAGE_MAP()
    public:
        afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
    public:
        virtual BOOL OnCreateClient(LPCREATESTRUCT lpcs, CCreateContext* pContext);
    private:
        CSplitterWnd m_split;
    };
    BEGIN_MESSAGE_MAP(CMyFrameWnd, CFrameWnd)
        ON_WM_CREATE()
    END_MESSAGE_MAP()
    
    BOOL CMyFrameWnd::OnCreateClient(LPCREATESTRUCT lpcs, CCreateContext* pContext)
    {
        m_split.CreateStatic(this, 1, 2);
        m_split.CreateView(0, 0, RUNTIME_CLASS(CMyView), CSize(100, 100), pContext);
        m_split.CreateView(0, 1, RUNTIME_CLASS(CMyView), CSize(100, 100), pContext);
        return TRUE;
    }
    
    int CMyFrameWnd::OnCreate(LPCREATESTRUCT lpCreateStruct)
    {
        return CFrameWnd::OnCreate(lpCreateStruct);//创建视图窗口
    }
    
    /*****************************************************************
    CMyWinAPP
    *****************************************************************/
    class CMyWinApp : public CWinApp
    {
    public:
        virtual BOOL InitInstance();
    };
    
    CMyWinApp theApp;
    
    BOOL CMyWinApp::InitInstance()
    {
        CMyFrameWnd *pFrame = new CMyFrameWnd;
        m_pMainWnd = pFrame;
    
        CCreateContext cct;
        cct.m_pCurrentDoc = new CMyDoc;
        cct.m_pNewViewClass = RUNTIME_CLASS(CMyView);
    
        pFrame->LoadFrame(IDR_MENU1, WS_OVERLAPPEDWINDOW, NULL, &cct);
        pFrame->ShowWindow(SW_SHOW);
        pFrame->UpdateWindow();
        return TRUE;
    }
    View Code

      运行结果:

      

      5.命令消息(WM_COMMAND)的处理顺序(★★★)

        View --> Document --> Frame --> App (默认顺序)

        CFrameWnd::OnCmdMsg虚函数内部执行顺决定,故我们可以重写该函数,改变消息处理的顺序

      相关代码:

    #include "stdafx.h"
    
    /*************************************************
    CMyDoc
    *************************************************/
    class CMyDoc : public CDocument
    {
        DECLARE_MESSAGE_MAP()
    public:
        afx_msg void OnNew();
    public:
        CString m_strDoc;
    
    };
    BEGIN_MESSAGE_MAP(CMyDoc, CDocument)
        //ON_COMMAND(ID_NEW, OnNew)
    END_MESSAGE_MAP()
    
    void CMyDoc::OnNew()
    {
        m_strDoc = "hello doc, 这叫老夫如何是好";
        UpdateAllViews(NULL);
    }
    /************************************************
    CMyView
    ************************************************/
    class CMyView : public CEditView
    {
        DECLARE_MESSAGE_MAP()
        DECLARE_DYNCREATE(CMyView)
    public:
        afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
    public:
        virtual void OnUpdate(CView* pSender, LPARAM lHint, CObject* pHint);
    };
    BEGIN_MESSAGE_MAP(CMyView, CEditView)
        ON_WM_CREATE()
    END_MESSAGE_MAP()
    IMPLEMENT_DYNCREATE(CMyView, CEditView)
    
    void CMyView::OnUpdate(CView* pSender, LPARAM lHint, CObject* pHint)
    {
        CMyDoc*pDoc = (CMyDoc*)m_pDocument;
        SetWindowText(pDoc->m_strDoc);
    }
    
    int CMyView::OnCreate(LPCREATESTRUCT lpCreateStruct)
    {
        return CEditView::OnCreate(lpCreateStruct);//将视图类对象和文档类对象建立绑定关系
    }
    
    /********************************************************
    CMyFrameWnd
    *********************************************************/
    class CMyFrameWnd :public CFrameWnd
    {
        DECLARE_MESSAGE_MAP()
    public:
        afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
    public:
        virtual BOOL OnCreateClient(LPCREATESTRUCT lpcs, CCreateContext* pContext);
    private:
        CSplitterWnd m_split;
    };
    BEGIN_MESSAGE_MAP(CMyFrameWnd, CFrameWnd)
        ON_WM_CREATE()
    END_MESSAGE_MAP()
    
    BOOL CMyFrameWnd::OnCreateClient(LPCREATESTRUCT lpcs, CCreateContext* pContext)
    {
        m_split.CreateStatic(this, 1, 2);
        m_split.CreateView(0, 0, RUNTIME_CLASS(CMyView), CSize(100, 100), pContext);
        m_split.CreateView(0, 1, RUNTIME_CLASS(CMyView), CSize(100, 100), pContext);
        return TRUE;
    }
    
    int CMyFrameWnd::OnCreate(LPCREATESTRUCT lpCreateStruct)
    {
        return CFrameWnd::OnCreate(lpCreateStruct);//创建视图窗口
    }
    
    /*****************************************************************
    CMyWinAPP
    *****************************************************************/
    class CMyWinApp : public CWinApp
    {
        DECLARE_MESSAGE_MAP()
    public:
        virtual BOOL InitInstance();
    public:
        afx_msg void OnNew();
    };
    BEGIN_MESSAGE_MAP(CMyWinApp, CWinApp)
        ON_COMMAND(ID_NEW, OnNew)
    END_MESSAGE_MAP()
    
    CMyWinApp theApp;
    
    void CMyWinApp::OnNew()
    {
        AfxMessageBox(L"应用程序类处理新建消息");
    }
    
    BOOL CMyWinApp::InitInstance()
    {
        CMyFrameWnd *pFrame = new CMyFrameWnd;
        m_pMainWnd = pFrame;
    
        CCreateContext cct;
        cct.m_pCurrentDoc = new CMyDoc;
        cct.m_pNewViewClass = RUNTIME_CLASS(CMyView);
    
        pFrame->LoadFrame(IDR_MENU1, WS_OVERLAPPEDWINDOW, NULL, &cct);
        pFrame->ShowWindow(SW_SHOW);
        pFrame->UpdateWindow();
        return TRUE;
    }
    View Code

      运行结果:

      

      伪代码:

        CMyFrameWnd  *pFrame  =  new  CMyFrameWnd;

        CCreateContext  cct;

        cct.m_pCurrentDoc  =  new  CMyDoc;

        cct.m_pNewViewClass  =  RUNTIME_CLASS( CMyView );

        pFrame->LoadFrame( IDR_MENU1, WS_OVERLAPPEDWINDOW, NULL, &cct )

        {

          //this为pFrame,pContext为&cct

          Create( lpszClass, strTitle, dwDefaultStyle, rectDefault, pParentWnd, ATL_MAKEINTRESOURCE(nIDResource), 0L, pContext ) )

          {

            1.加载菜单

            //this为pFrame,pContext为&cct       

            CreateEx( ......, ( LPVOID )pContext ) )

            {

              CREATESTRUCT  cs;
              ......
              cs.lpCreateParams  =  lpParam;  //lpParam为&cct     

              //创建主框架窗口,一旦执行成功,触发WM_CREATE消息,会回到我们的WM_CREATE消息处理函数中    

              HWND  hWnd  =  CreateWindowEx( ......, cs.lpCreateParams );  

            }

          }

        }

        ***********************************************************************************************************

        //处理框架窗口WM_CREATE消息,this为pFrame,lpcs为CreateWindowEx的全部参数

        CFrameWnd::OnCreate( lpcs)

        {

          CCreateContext*  pContext  =  ( CCreateContext* ) lpcs->lpCreateParams;  //取出&cct

          return  OnCreateHelper( lpcs, pContext )  //this为pFrame,pContext为&cct

          {

            OnCreateClient( lpcs, pContext )  //this为pFrame,pContext为&cct

            {      

              if  ( pContext  !=  NULL  &&  pContext->m_pNewViewClass  !=  NULL )
              {
                CWnd  *pWnd  =  CreateView( pContext, AFX_IDW_PANE_FIRST ) 
                {

                  //动态创建视图类对象并返回对象地址

                  CWnd*  pView  =  ( CWnd* )pContext->m_pNewViewClass->CreateObject( );

                  //用视图类对象创建视图窗口,this为视图类对象地址pView      

                  pView->Create( NULL, NULL, AFX_WS_DEFAULT_VIEW, CRect(0,0,0,0), this, nID, pContext )  

                  {            

                    return  CreateEx( ......, ( LPVOID )pContext )

                    {

                      CREATESTRUCT cs;

                      .......

                      cs.lpCreateParams = lpParam;   

                       //创建视图窗口,执行成功,触发WM_CREATE消息,会回到我们的WM_CREATE消息处理函数中

                      HWND  hWnd  =  CreateWindowEx( ......, cs.lpCreateParams );  

                    }

                  }

                  return  pView;

                }

                if  ( pWnd  == NULL )

                  return  FALSE;
              }

              return  TRUE;

            }

          }

        }

      *********************************************************************************************************

      //处理视图类的WM_CREATE消息,this为pView,lpcs为CreateWindowEx的全部参数

      CEditView::OnCreate( lpcs ) 

      {

         CCtrlView::OnCreate( lpcs )  //this为pView

        {

          CCreateContext*  pContext  =  ( CCreateContext* )lpcs->lpCreateParams;  //拿到&cct

           //this为pView,m_pCurrentDoc为文档类对象(CMyDoc)的对象地址,参数是视图类对象地址(CMyView)

          pContext->m_pCurrentDoc->AddView( this )

          {

            m_viewList.AddTail( pView );  //文档类对象用一个链表成员和它关联的视图类对象

            pView->m_pDocument  =  this;  //视图类对象用一个普通成员变量保存和它关联的文档类对象

          }

        }

      }

       ************************************************************************************************************

      //文档类更新所有视图,其中会调用视图类的更新函数

      UpdateAllViews( )

      {

        POSITION pos = GetFirstViewPosition( );//得到文档类对象中视图链表的迭代器

        while  ( pos  !=  NULL )

        {

          CView*  pView  =  GetNextView( pos );     

          if ( pView  !=  pSender )

            pView->OnUpdate( pSender, lHint, pHint );  //调用我们写的虚函数

        }

      }

      *****************************************************************************************

      //WM_COMMAND消息的处理顺序

      OnCommand( wParam, lParam )  //this为pFrame

      {

        return CWnd::OnCommand( wParam, lParam )  //this为pFrame

        {

          return  OnCmdMsg( nID, nCode, NULL, NULL )  //this为pFrame(起点)

          {

            ////////////////////////////////////////////////////////////////////////////////////////////////

            //视图类的WM_COMMAND处理(里面会找Document的消息处理),故View->Document

            /////////////////////////////////////////////////////////////////////////////////////////////////   

            CView*  pView  =  GetActiveView( );

            pView->OnCmdMsg( nID, nCode, pExtra, pHandlerInfo )  //this为pView

            {

              CWnd::OnCmdMsg( nID, nCode, pExtra, pHandlerInfo )  //this为pView

              {

                //this为视图类对象地址

                CCmdTarget::OnCmdMsg( ... )  //★消息处理最终目的地

                {              

                  for ( pMessageMap  =  GetMessageMap( );  pMessageMap->pfnGetBaseMap  !=  NULL;
                     pMessageMap  =  (*pMessageMap->pfnGetBaseMap)( ) )  {  ......  } 

                }

              }      

              if  ( m_pDocument  !=  NULL )
              {
                return  m_pDocument->CDocument::OnCmdMsg( nID,  nCode,  pExtra,  pHandlerInfo )  //this为文档对象地址

                {

                   //this为文档类对象地址

                  CCmdTarget::OnCmdMsg( ...... );  //★消息处理最终目的地

                }
              }

            }
            ////////////////////////////////////////////////////////////////////////////////////////////////

            //框架类的WM_COMMAND消息处理

            ////////////////////////////////////////////////////////////////////////////////////////////////

            CWnd::OnCmdMsg( nID, nCode, pExtra, pHandlerInfo )  //this为pFrame

            {

              //this为框架类对象地址

              CCmdTarget::OnCmdMsg( ... );  //★消息处理最终目的地

            }

            ////////////////////////////////////////////////////////////////////////////////////////////////

            //应用程序类的WM_COMMAND的消息处理

            ////////////////////////////////////////////////////////////////////////////////////////////////

            CWinApp*  pApp  =  AfxGetApp( );

            pApp->OnCmdMsg( nID, nCode, pExtra, pHandlerInfo )

            {

              //this为应用程序对象地址

              CCmdTarget::OnCmdMsg( ... );  //★消息处理最终目的地

            }

          }

        }

      }

  • 相关阅读:
    一百零二、SAP中ALV事件之十五,让ALV表格自动求和
    一百零一、SAP中ALV事件之十四,让ALV表格自动排序
    一百、SAP中ALV事件之十三,给ALV的自定义按钮添加事件
    九十九、SAP中ALV事件之十二,给ALV的标题栏添加图片
    九十八、SAP中ALV事件之十一,查看图片
    九十七、SAP中ALV事件之十,通过REUSE_ALV_COMMENTARY_WRITE函数来显示ALV的标题
    九十六、SAP中ALV事件之九,显示功能按钮栏中显示ALV加强工具栏
    九十五、SAP中查看自定义包的所有模块,对象,函数主,事务等
    二十、JavaScript之对象
    十九、JavaScript之数组
  • 原文地址:https://www.cnblogs.com/csqtech/p/5693306.html
Copyright © 2020-2023  润新知