Switching to other view in a doc-view application

In a previous article we discussed how to replace views in a document-view application. The views to replace were destroyed, and new views were created to replace them. Sometimes it's better to preserve the views and use them later rather than to destroy and recreate them. In this article we show how to switch to other views without destroying the old ones, so we could use them later.

In the code below, the inactive views are disconnected from the document (so they don't receive OnUpdate messages) using CDocument::RemoveView. When needed they are reconnected to the document and resynchronized using CDocument::AddView. In order to keep the inactive views synchronized with the document we should have to implement custom hints (using the pHint parameter in the CView::OnUpdate member function). The views are hidden and shown using the CWnd::ShowWindow member function.

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. Lets start with an SDI application that doesn't have splitters:


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):

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:


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:


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:


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 windows (read the comments to difference between SDI and MDI applications):


/* 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:


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.

Date Last Updated: March 3, 1999



Comments

  • http://www.oakleysunglassesoutc.com/ mqsegt

    Posted by http://www.oakleysunglassesoutc.com/ Mandyvkm on 03/31/2013 05:08am

    ghd hair straightener,The old man may not be afraid of the two generations of Emperors, but multi-less attitude, be able to conceal how long how long is the old man now anxious as the Royal Party collar Weng suddenly singled out to challenge the authority of the old lady's home repair meal pension it! WANG Cun good to follow the old man more than a decade, and is closely related to the natural Needless to say, otherwise we would not recommend him to Guangzhou when the alternate channel member, but precisely because of this distance, the old man did not dare just the right WANG Cun-shan also loyal to himself. To the character of the old man, the king kept good so he ran errands use the service, or you can use, but if you want to go back to this inner core of the Group, is almost unlikely Tan Yankai has long been the old man's confidential briefings on this issue. Sub Exhibition brother, you follow my father for many years, you cry 't-ghd straightener according to age, said the said' ... but recently Xu Zhixiang large parameter case is a manifestation of the situation is not very peaceful, you K Tan Yankai waved his hand and said: the same as my father act Fenyou must not order some little things for his old upset ...... my father before the Pro to told cheap ghd,hairstraighteneraul.ghd australia,com/" title="ghd sale"ghd sale confidential briefings, you leave my father's side for so many years, and also respect him so elderly, the elderly are very pleased.

    Reply
  • Effortless Products Of ugg - An A-Z

    Posted by Geneviveytd on 11/10/2012 01:45am

    Considering that the 60's surfers as well as competitive swimmers also have identified ugg boots like a popular means for keeping warm although out from the drinking water. Additionally they dressed in all of them in to the ocean since these unique Hawaiian [url=http://www.bootsos.com/]ugg boots sale[/url] ended up excellent with regard to raising the motorboats drift on the sea.http://www.bootsalso.com/

    Reply
  • thanks

    Posted by Legacy on 03/30/2003 12:00am

    Originally posted by: doyd

    thanks, It help me finish some projects

    Reply
  • Can CMultiDocTemplate pointers be used to switch views?

    Posted by Legacy on 01/03/2003 12:00am

    Originally posted by: Geroge Scarborough

    In the APP I created two templates to represent the views I have, one is a view with a control list, the other is a view to plot the values in the list. I do not want to destroy the view because the data set is huge and performance would suffer. What you have documented is what I want to do but I would like to do it with template pointers instead. Is that possible/advisable? If so, what do I need to change in your example to code it? Do you already have an example of the coding?

    Thanks,
    George

    Reply
  • Help.....

    Posted by Legacy on 05/31/2002 12:00am

    Originally posted by: Pratap Reddy

    Hi

    iam new to this vc++ programming.
    i created an SDI app using MFC App Wizard(exe). in wizard at step 6 i Chosed default CView as base class.
    in my application i added CFormViews.

    i have a menu. by using menu how can i switch to different forms. and also where can i find SwitchToForm()method?

    how can i call forms using menus.

    pratap

    Reply
  • Help !!!

    Posted by Legacy on 09/24/2001 12:00am

    Originally posted by: Jens Fredriksson

    Help this is exactly what I want but I can't get it work. I have tested several times but always ending up struggling whit MFC.

    I am using VC 5.0 to create a SDI app. Then I try to make a new class with class wizard but don't seem to be able to make a descendent of my viewclass so I did a decendant from Cview and replased all Cview in the files with my viewclass.
    Is this right? Is there anyone who can tell me step by step how to implement this or send me a simple demo project.

    Regards Jens.

    Reply
  • Switching to other view in a doc-view application.

    Posted by Legacy on 06/28/2001 12:00am

    Originally posted by: shiva

    Hi,
    What if we have many view associated and I want to switch between all the opened view just like control tab functionality. How do I go about it, put some light on the same

    Reply
  • Crashing on if statement...

    Posted by Legacy on 06/12/2001 12:00am

    Originally posted by: Ryan

    The following line:
    if (!m_pView1) { ...
    is crashing on me.
    The strange thing is, it only crashes in Debug mode. I'm assuming it has something to do with how memory is setup, and I missed a step in initializing the view.
    Can anyone help?

    Reply
  • Switching to other view in a doc-view application

    Posted by Legacy on 05/05/2001 12:00am

    Originally posted by: J.Padmalatha

    I have created an MDI application based on Cform view.  I have inserted a new form with class name "cfrm1".  I want to switch to that new form by selecting some menu item in the main frame (or) child frame.  When I am accessing that, it is giving the error "cannot access protected members declaed in cfrm1".  Please give an example to swtich to other form without using any splitters in MDI application.
    

    Reply
  • Tip to initialization of the new view

    Posted by Legacy on 01/28/2001 12:00am

    Originally posted by: Svatos

    My new created view was not correct initialized. I have called the OnInitialUpdate Function of the view and it works better.

    This Function should be called after attaching to the document.

    Here an example

    AddView(pNewView); // original code

    if ( bIsNewView ) // flag if it was a new view
    pNewView->OnInitialUpdate(); // call the function

    pChild->RecalcLayout(); // original code

    Maybe it hepls somebody.

    Reply
  • Loading, Please Wait ...

Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • A modern mobile IT strategy is no longer an option, it is an absolute business necessity. Today's most productive employees are not tied to a desk, an office, or a location. They are mobile. And your company's IT strategy has to be ready to support them with easy, reliable, 24/7 access to the business information they need, from anywhere in the world, across a broad range of communication devices. Here's how some of the nation's most progressive corporations are meeting the many needs of their mobile workers …

  • IBM Worklight is a mobile application development platform that lets you extend your business to mobile devices. It is designed to provide an open, comprehensive platform to build, run and manage HTML5, hybrid and native mobile apps.

Most Popular Programming Stories

More for Developers

Latest Developer Headlines

RSS Feeds