`

SDI实现多视图并切换视图

 
阅读更多

首先在H文件有如下声明:

class CMultiViewApp : public CWinApp<?XML:NAMESPACE PREFIX = O />

{

public:

CView* m_pFirstView;

CView* m_pOtherView;

int m_currentView;

CView* m_pView2;

CView* m_pView1;

CMultiViewApp();

// Overrides

// ClassWizard generated virtual function overrides

//{{AFX_VIRTUAL(CMultiViewApp)

public:

virtual BOOL InitInstance();

//}}AFX_VIRTUAL

// Implementation

//{{AFX_MSG(CMultiViewApp)

afx_msg void OnAppAbout();

afx_msg void OnViewOtherview();

afx_msg void OnViewFirstview();

//}}AFX_MSG

afx_msg void OnViewChange(UINT nCmdID);

DECLARE_MESSAGE_MAP()

};

其次,在CPP文件有如下消息MAP

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

// CMultiViewApp

BEGIN_MESSAGE_MAP(CMultiViewApp, CWinApp)

//{{AFX_MSG_MAP(CMultiViewApp)

ON_COMMAND(ID_APP_ABOUT, OnAppAbout)

ON_COMMAND(ID_VIEW_OTHERVIEW, OnViewOtherview)

ON_COMMAND(ID_VIEW_FIRSTVIEW, OnViewFirstview)

//}}AFX_MSG_MAP

// Standard file based document commands

ON_COMMAND(ID_FILE_NEW, CWinApp::OnFileNew)

ON_COMMAND(ID_FILE_OPEN, CWinApp::OnFileOpen)

// Standard print setup command

ON_COMMAND(ID_FILE_PRINT_SETUP, CWinApp::OnFilePrintSetup)

ON_COMMAND_RANGE( ID_VIEW_VIEW1, ID_VIEW_VIEW2, OnViewChange)

END_MESSAGE_MAP()

说明:SDI程序在CMyApp::InitInstance()已经通过DocTemplate创建一个关联的视图/文档实例,切显示出来.具体实现如下:

BOOL CMultiViewApp::InitInstance()

{

AfxEnableControlContainer();

// Standard initialization

// If you are not using these features and wish to reduce the size

// of your final executable, you should remove from the following

// the specific initialization routines you do not need.

#ifdef _AFXDLL

Enable3dControls(); // Call this when using MFC in a shared DLL

#else

Enable3dControlsStatic(); // Call this when linking to MFC statically

#endif

// Change the registry key under which our settings are stored.

// TODO: You should modify this string to be something appropriate

// such as the name of your company or organization.

SetRegistryKey(_T("Local AppWizard-Generated Applications"));

LoadStdProfileSettings(); // Load standard INI file options (including MRU)

// Register the application's document templates. Document templates

// serve as the connection between documents, frame windows and views.

CSingleDocTemplate* pDocTemplate;

pDocTemplate = new CSingleDocTemplate(

IDR_MAINFRAME,

RUNTIME_CLASS(CMultiViewDoc),

RUNTIME_CLASS(CMainFrame), // main SDI frame window

RUNTIME_CLASS(CMultiViewView));

AddDocTemplate(pDocTemplate);

// Parse command line for standard shell commands, DDE, file open

CCommandLineInfo cmdInfo;

ParseCommandLine(cmdInfo);

// Dispatch commands specified on the command line

if (!ProcessShellCommand(cmdInfo))

return FALSE;

CView* pActiveView = ((CFrameWnd*) m_pMainWnd)->GetActiveView();

m_pFirstView = pActiveView;

m_pOtherView = (CView*) new COtherView;

CDocument* pDoc = ((CFrameWnd*)m_pMainWnd)->GetActiveDocument();

//通过CCreateContext实现第二视图和文档的关联

CCreateContext context;

context.m_pCurrentDoc = pDoc;

UINT m_ID = AFX_IDW_PANE_FIRST + 1;

CRect rect;

//为了演示第一种多视图是实现方法,Vew的实例创建放在了这里

m_pOtherView->Create(NULL, NULL, WS_CHILD, rect, m_pMainWnd, m_ID, &context);

// The one and only window has been initialized, so show and update it.

m_pMainWnd->ShowWindow(SW_SHOWMAXIMIZED);

m_pMainWnd->UpdateWindow();

m_currentView=1;

return TRUE;

}

1. SDI单文档多视图实现方法1

void CMultiViewApp::OnViewOtherview()

{

// TODO: Add your command handler code here

UINT temp = ::GetWindowLong(m_pOtherView->m_hWnd, GWL_ID);

::SetWindowLong(m_pOtherView->m_hWnd, GWL_ID, ::GetWindowLong(m_pFirstView->m_hWnd, GWL_ID));

::SetWindowLong(m_pFirstView->m_hWnd, GWL_ID, temp);

m_pFirstView->ShowWindow(SW_HIDE);

m_pOtherView->ShowWindow(SW_SHOW);

((CFrameWnd*)m_pMainWnd)->SetActiveView(m_pOtherView);

((CFrameWnd*) m_pMainWnd)->RecalcLayout();

m_pOtherView->Invalidate();

}

void CMultiViewApp::OnViewFirstview()

{

// TODO: Add your command handler code here

UINT temp = ::GetWindowLong(m_pOtherView->m_hWnd, GWL_ID); //GetWindowWord()

::SetWindowLong(m_pOtherView->m_hWnd, GWL_ID, ::GetWindowLong(m_pFirstView->m_hWnd, GWL_ID));//SetWindowWord()

::SetWindowLong(m_pFirstView->m_hWnd, GWL_ID, temp);//SetWindowWord()

m_pOtherView->ShowWindow(SW_HIDE);

m_pFirstView->ShowWindow(SW_SHOW);

((CFrameWnd*)m_pMainWnd)->SetActiveView(m_pFirstView);

((CFrameWnd*)m_pMainWnd)->RecalcLayout();

m_pFirstView->Invalidate();

}

2. SDI单文档多视图实现方法2

void CMultiViewApp::OnViewChange(UINT nCmdID)

{

//另外一种方法实现SDI的多视图切换

CView* pViewAdd;

CView* pViewRemove;

CMainFrame* pMainFrame=(CMainFrame*)AfxGetMainWnd();

CDocument* pDoc = pMainFrame->GetActiveDocument();

if((nCmdID == ID_VIEW_VIEW1) && (m_currentView == 1))

return;

if((nCmdID == ID_VIEW_VIEW2) && (m_currentView == 2))

return;

if (nCmdID == ID_VIEW_VIEW2)

{

if (m_pView2 == NULL)

{

m_pView1 = pMainFrame->GetActiveView();

m_pView2 = new COtherView();

//Note that if OnSize has been overridden in CMyView2

//and GetDocument() is used in this override it can

//cause assertions and, if the assertions are ignored,

//cause access violation.

//使用CCreateContext structure实现viewdocument的关联

CCreateContext context;

context.m_pCurrentDoc=pDoc;//m_pView1->GetDocument();

m_pView2->Create(NULL, NULL, AFX_WS_DEFAULT_VIEW,

CFrameWnd::rectDefault, AfxGetMainWnd(), AFX_IDW_PANE_FIRST + 1, &context/*NULL*/);

}

pViewAdd = m_pView2;

pViewRemove = m_pView1;

m_currentView= 2;

}

else

{

pViewAdd = m_pView1;

pViewRemove = m_pView2;

m_currentView= 1;

}

// Set the child i.d. of the active view to AFX_IDW_PANE_FIRST,

// so that CFrameWnd::RecalcLayout will allocate to this

// "first pane" that portion of the frame window's client area

// not allocated to control bars. Set the child i.d. of the

// other view to anything other than AFX_IDW_PANE_FIRST; this

// examples switches the child id's of the two views.

int nSwitchChildID = pViewAdd->GetDlgCtrlID();

pViewAdd->SetDlgCtrlID(AFX_IDW_PANE_FIRST);

pViewRemove->SetDlgCtrlID(nSwitchChildID);

// Show the newly active view and hide the inactive view.

pViewAdd->ShowWindow(SW_SHOW);

pViewRemove->ShowWindow(SW_HIDE);

// Connect the newly active view to the document, and

// disconnect the inactive view.

//通过CCreateContext实现视图View和文档Document的关联

//就没有必要手动AddView(),如果需要可以进行手动RemoveView()

//AddView()会在CView::OnCreate()MFC调用,RemoveView()会在CView::~CView()被调用

//当然可以根据需要手动调用它们,在本例当中,View都是被创建一次,没有被销毁,所以不会自动

//调用RemoveView()

//pDoc->AddView(pViewAdd);

//pDoc->RemoveView(pViewRemove);

pMainFrame->SetActiveView(pViewAdd);

pMainFrame->RecalcLayout();

return ;

}

The code needed to implement view switching depends on the frame window containing the view. There are three common cases: the view is contained within a CFrameWnd (SDI application), the view is contained within a CMDIChildWnd (MDI application) and the view is a pane of a splitter window, either in SDI or MDI applications. In all cases, what we need is a method in our document class to switch to the desired view. This method should receive the new view as a parameter and return the view that was replaced. This returned view is not contained in the document's list anymore. The advantage of having this method in the document class becomes obvious when there are several document types each of which can have different view types. Let's start with an SDI application that doesn't have splitters:

Collapse Copy Code
CView* CMyDocument::SwitchToView ( CView* pNewView )
{
   CFrameWnd* pMainWnd = (CFrameWnd*)AfxGetMainWnd();
   CView* pOldActiveView = pMainWnd->GetActiveView();
   ASSERT(pOldActiveView != NULL);
   ASSERT_VALID(pOldActiveView);
   ASSERT(pOldActiveView->GetDocument() == this); // must be attached to us

   /* Set the child window ID of the active view to AFX_IDW_PANE_FIRST.
      This is necessary so that CFrameWnd::RecalcLayout will allocate
      this "first pane" to that portion of the frame window's client
      area not allocated to control bars.  Set the child ID of
      the previously active view to some other ID.
   */

   ::SetWindowLong(pOldActiveView->m_hWnd, GWL_ID, 0);
   ::SetWindowLong(pNewView->m_hWnd, GWL_ID, AFX_IDW_PANE_FIRST);

   // Show the newly active view and hide the inactive view.
   pNewView->ShowWindow(SW_SHOW);
   pOldActiveView->ShowWindow(SW_HIDE);

   // Connect the newly active view to the document,
   // and disconnect the inactive view
   AddView(pNewView); 
   RemoveView(pOldActiveView);
   pMainWnd->SetActiveView(pNewView);
   pMainWnd->RecalcLayout();

   return pOldActiveView;
}

In the case of an MDI application (again without splitters):

Collapse Copy Code
CView* CMyDocument::SwitchToView ( CView* pNewView )
{
   CMDIFrameWnd* pMainWnd = (CMDIFrameWnd*)AfxGetMainWnd();

   // Get the active MDI child window.
   CMDIChildWnd* pChild = (CMDIChildWnd*)pMainWnd->MDIGetActive();

   // Get the active view attached to the active MDI child window.
   CView* pOldActiveView = pChild->GetActiveView();

   // Set flag so that document will not be deleted when view is dettached.
   BOOL bAutoDelete = m_bAutoDelete;
   m_bAutoDelete = FALSE;

   // Dettach existing view
   RemoveView(pOldActiveView);

   // restore flag
   m_bAutoDelete = bAutoDelete;

   // Show the newly active view and hide the inactive view.
   pNewView->ShowWindow(SW_SHOW);
   pOldActiveView->ShowWindow(SW_HIDE);

   // Attach new view
   AddView(pNewView);

   pChild->RecalcLayout();
   pNewView->UpdateWindow();
   pChild->SetActiveView(pNewView);
   return pOldActiveView;
}

When the view to replace is a pane of a splitter window, there is also a small difference between SDI and MDI applications, related to the retrieval of the current active view. In the method below, you must comment out what you don't need depending on your application type:

Collapse Copy Code
CView* CSDISplitDoc::SwitchToView ( CView* pNewView )
{
/* Uncomment this if this is a SDI application
   CFrameWnd* pMainWnd   = (CFrameWnd*)AfxGetMainWnd();
   CView* pOldActiveView = pMainWnd->GetActiveView();
*/

/* Uncomment this if this is a MDI application
   CMDIFrameWnd* pMainWnd = (CMDIFrameWnd*)AfxGetMainWnd();

   // Get the active MDI child window.
   CMDIChildWnd* pChild = (CMDIChildWnd*)pMainWnd->MDIGetActive();

   // Get the active view attached to the active MDI child window.
   CView* pOldActiveView = pChild->GetActiveView();
*/

   CSplitterWnd* pSplitter = (CSplitterWnd *)pOldActiveView->GetParent();
   int row, col;
   ASSERT(pSplitter->IsChildPane(pOldActiveView, row, col));

   // set flag so that document will not be deleted when view is destroyed
   m_bAutoDelete = FALSE;    

   // Dettach existing view
   RemoveView(pOldActiveView);

   // set flag back to default 
   m_bAutoDelete = TRUE;
 
   /* Set the child window ID of the active view to the ID of the corresponding
      pane. Set the child ID of the previously active view to some other ID.
   */
   ::SetWindowLong(pOldActiveView->m_hWnd, GWL_ID, 0);
   ::SetWindowLong(pNewView->m_hWnd, GWL_ID, pSplitter->IdFromRowCol(row, col));

   // Show the newly active view and hide the inactive view.
   pNewView->ShowWindow(SW_SHOW);
   pOldActiveView->ShowWindow(SW_HIDE);

   // Attach new view
   AddView(pNewView);

   // Set active 
   pSplitter->GetParentFrame()->SetActiveView(pNewView);
   
   pSplitter->RecalcLayout(); 
   pNewView->SendMessage(WM_PAINT); 

   return pOldActiveView;
}

The SwitchToView functions above receive a pointer to an existing view, so a view must have already been created without attaching it to a document. Note that this imposes restrictions on view creation code, which should not make use of the document in any way (for example, the OnInitialUpdate member function). Otherwise, exceptions might occur. The newly activated view is shown before it is attached to the document, so functions in the view that respond to Windows messages such as WM_SIZE or WM_GETMINMAXINFO should not make use of the document either.

The view must be created with correct parent window and window ID. Both parameters depend on the frame windows containing the view, just the same as the SwithToView function. The non-active views could be created the first time the menu to select one of them was selected or somewhere in the document initialization code. Supposing we have a m_pView1 member in the document class that is a pointer to a view, this is how it should be created in a SDI application:

Collapse Copy Code
if (!m_pView1)
{
   // create the new view
   m_pView1 = new CView1;
   m_pView1->Create(NULL, NULL, AFX_WS_DEFAULT_VIEW, CFrameWnd::rectDefault, 
   AfxGetMainWnd(), AFX_IDW_PANE_FIRST+1, NULL);
}

In a MDI application:

Collapse Copy Code
   CMDIFrameWnd* pMainWnd = (CMDIFrameWnd*)AfxGetMainWnd();
   // Get the active MDI child window.
   CMDIChildWnd* pChild = (CMDIChildWnd*)pMainWnd->MDIGetActive();

   if (!m_pView1)
   {
   // create the new view
   m_pView1 = new CView1;
   m_pView1->Create(NULL, NULL, AFX_WS_DEFAULT_VIEW, CRect(0, 0, 0, 0), 
                   pChild, AFX_IDW_PANE_FIRST, NULL);
}

And finally, if the view is a pane of a splitter window (read the comments to difference between SDI and MDI applications):

Collapse Copy Code
/* Uncomment this if this is a SDI application
   CFrameWnd* pMainWnd = (CFrameWnd*)AfxGetMainWnd();
   CView* pActiveView = pMainWnd->GetActiveView();
   CSplitterWnd* pSplitter = (CSplitterWnd *)pActiveView->GetParent();
*/

/* Uncomment this if this is a MDI application
   CMDIFrameWnd* pMainWnd = (CMDIFrameWnd*)AfxGetMainWnd();
   CMDIChildWnd* pChild = (CMDIChildWnd*)pMainWnd->MDIGetActive();
   CView* pActiveView = pChild->GetActiveView();
   CSplitterWnd* pSplitter = (CSplitterWnd *)pActiveView->GetParent();
*/

   if (!m_pView1)
   {
      // create the new view
      m_pView1 = new CView1;
      m_pView1->Create(NULL, NULL, AFX_WS_DEFAULT_VIEW, 
               CRect(0, 0, 0, 0),  pSplitter, 0, NULL);
   }

When we already have an existing view (m_pView1 in our example), we can make this view active as follows:

Collapse Copy Code
   CView* pOldActiveView = SwitchToView(m_pView1);
   if (!pOldActiveView)
      // there was not an active view
   else
      // pOldActiveView is a pointer to the now inactive view

Note that inactive views destroy themselves when their parent window is destroyed, so you don't have to worry about destroying them.

分享到:
评论

相关推荐

    数据库系统课程设计.txt

    数据库课程设计数据库课程设计数据库课程设计数据库课程设计

    外汇经纪CRM软件,全球前10强生产商排名及市场份额.docx

    外汇经纪CRM软件,全球前10强生产商排名及市场份额

    BS EN 60068-2-5-2011.pdf

    BS EN 60068-2-5-2011.pdf

    MS2磁化率系统操作手册

    MS2磁化率系统操作手册

    2016年美赛A~F题特等奖论文合集.pdf

    大学生,数学建模,美国大学生数学建模竞赛,MCM/ICM,历年美赛特等奖O奖论文

    自动化测试装置

    自动化测试装置

    大华网络硬盘录像机用户手册.pdf

    大华网络硬盘录像机用户手册

    大型民营企业数字化转型综合解决方案.pptx

    大型民营企业数字化转型综合解决方案.pptx

    2024年中国5G智能手机背光模组行业研究报告.docx

    2024年中国5G智能手机背光模组行业研究报告

    node-v8.15.0-sunos-x86.tar.xz

    Node.js,简称Node,是一个开源且跨平台的JavaScript运行时环境,它允许在浏览器外运行JavaScript代码。Node.js于2009年由Ryan Dahl创立,旨在创建高性能的Web服务器和网络应用程序。它基于Google Chrome的V8 JavaScript引擎,可以在Windows、Linux、Unix、Mac OS X等操作系统上运行。 Node.js的特点之一是事件驱动和非阻塞I/O模型,这使得它非常适合处理大量并发连接,从而在构建实时应用程序如在线游戏、聊天应用以及实时通讯服务时表现卓越。此外,Node.js使用了模块化的架构,通过npm(Node package manager,Node包管理器),社区成员可以共享和复用代码,极大地促进了Node.js生态系统的发展和扩张。 Node.js不仅用于服务器端开发。随着技术的发展,它也被用于构建工具链、开发桌面应用程序、物联网设备等。Node.js能够处理文件系统、操作数据库、处理网络请求等,因此,开发者可以用JavaScript编写全栈应用程序,这一点大大提高了开发效率和便捷性。 在实践中,许多大型企业和组织已经采用Node.js作为其Web应用程序的开发平台,如Netflix、PayPal和Walmart等。它们利用Node.js提高了应用性能,简化了开发流程,并且能更快地响应市场需求。

    海关商品编码/HS编码表

    用于海关申报商品编码/HS编码信息

    奥维互动地图软件安装包

    奥维互动地图软件安装包

    《统计与数据分析基础》02数据采集.pptx

    《统计与数据分析基础》02数据采集

    node-v9.11.2-linux-s390x.tar.xz

    Node.js,简称Node,是一个开源且跨平台的JavaScript运行时环境,它允许在浏览器外运行JavaScript代码。Node.js于2009年由Ryan Dahl创立,旨在创建高性能的Web服务器和网络应用程序。它基于Google Chrome的V8 JavaScript引擎,可以在Windows、Linux、Unix、Mac OS X等操作系统上运行。 Node.js的特点之一是事件驱动和非阻塞I/O模型,这使得它非常适合处理大量并发连接,从而在构建实时应用程序如在线游戏、聊天应用以及实时通讯服务时表现卓越。此外,Node.js使用了模块化的架构,通过npm(Node package manager,Node包管理器),社区成员可以共享和复用代码,极大地促进了Node.js生态系统的发展和扩张。 Node.js不仅用于服务器端开发。随着技术的发展,它也被用于构建工具链、开发桌面应用程序、物联网设备等。Node.js能够处理文件系统、操作数据库、处理网络请求等,因此,开发者可以用JavaScript编写全栈应用程序,这一点大大提高了开发效率和便捷性。 在实践中,许多大型企业和组织已经采用Node.js作为其Web应用程序的开发平台,如Netflix、PayPal和Walmart等。它们利用Node.js提高了应用性能,简化了开发流程,并且能更快地响应市场需求。

    BIM+ESE数字化:低碳园区智慧能源数字化管理解决方案.pptx

    BIM+ESE数字化:低碳园区智慧能源数字化管理解决方案.pptx

    node-v11.5.0-linux-armv6l.tar.xz

    Node.js,简称Node,是一个开源且跨平台的JavaScript运行时环境,它允许在浏览器外运行JavaScript代码。Node.js于2009年由Ryan Dahl创立,旨在创建高性能的Web服务器和网络应用程序。它基于Google Chrome的V8 JavaScript引擎,可以在Windows、Linux、Unix、Mac OS X等操作系统上运行。 Node.js的特点之一是事件驱动和非阻塞I/O模型,这使得它非常适合处理大量并发连接,从而在构建实时应用程序如在线游戏、聊天应用以及实时通讯服务时表现卓越。此外,Node.js使用了模块化的架构,通过npm(Node package manager,Node包管理器),社区成员可以共享和复用代码,极大地促进了Node.js生态系统的发展和扩张。 Node.js不仅用于服务器端开发。随着技术的发展,它也被用于构建工具链、开发桌面应用程序、物联网设备等。Node.js能够处理文件系统、操作数据库、处理网络请求等,因此,开发者可以用JavaScript编写全栈应用程序,这一点大大提高了开发效率和便捷性。 在实践中,许多大型企业和组织已经采用Node.js作为其Web应用程序的开发平台,如Netflix、PayPal和Walmart等。它们利用Node.js提高了应用性能,简化了开发流程,并且能更快地响应市场需求。

    各城市-人口就业和工资数据(1978-2022年).xlsx

    样例数据及详细介绍:https://blog.csdn.net/li514006030/article/details/138510754

    广东工业大学-2010计算机系统结构试题附答案考试试题回忆版以及答案解析.doc

    此试题是考试后回忆版本,你会发现是惊喜。恭喜你考个好成绩。

    德勤:2024年技术趋势报告.pdf

    德勤:2024年技术趋势报告.pdf

    node-v9.9.0-linux-x86.tar.xz

    Node.js,简称Node,是一个开源且跨平台的JavaScript运行时环境,它允许在浏览器外运行JavaScript代码。Node.js于2009年由Ryan Dahl创立,旨在创建高性能的Web服务器和网络应用程序。它基于Google Chrome的V8 JavaScript引擎,可以在Windows、Linux、Unix、Mac OS X等操作系统上运行。 Node.js的特点之一是事件驱动和非阻塞I/O模型,这使得它非常适合处理大量并发连接,从而在构建实时应用程序如在线游戏、聊天应用以及实时通讯服务时表现卓越。此外,Node.js使用了模块化的架构,通过npm(Node package manager,Node包管理器),社区成员可以共享和复用代码,极大地促进了Node.js生态系统的发展和扩张。 Node.js不仅用于服务器端开发。随着技术的发展,它也被用于构建工具链、开发桌面应用程序、物联网设备等。Node.js能够处理文件系统、操作数据库、处理网络请求等,因此,开发者可以用JavaScript编写全栈应用程序,这一点大大提高了开发效率和便捷性。 在实践中,许多大型企业和组织已经采用Node.js作为其Web应用程序的开发平台,如Netflix、PayPal和Walmart等。它们利用Node.js提高了应用性能,简化了开发流程,并且能更快地响应市场需求。

Global site tag (gtag.js) - Google Analytics