1
votes

I need help with switching between CFormViews in my MFC SDI C++ project. I have been digging for a long time, and can't figure out why my code isn't working. Through searching the internet (and this site included) I came across several tutorials for switching forms by adding two functions to MainFrm.cpp (a CMainFrame object that inherits from CFrameWnd). One of them is passed an id of the form I want to switch to, then gets a pointer to the active view, and runs some other code from there. However, GetActiveView() always returns a NULL pointer value. I know there's an active view because I'm clicking a button from an active form. My code is below. This is just the function I'm referring to. It resides in MainFrm.cpp (the default window file created when you start a new MFC project).

So far I've tried the code from the Microsoft Knowledge Base that talks about How to Get Current CDocument or CView from Anywhere, I tried to get the active frame first, then called GetActiveView from CFrameWnd, and I tried the code below. All to no avail. I clearly do not know enough about MFC to figure anything out. If you need more information from me, please ask. I probably didn't mention everything I should have. I chose to do MFC for a school project, and can't proceed to create a UML or writing any other code until I know that I can get these forms to work.

void CMainFrame::SelectView(UINT ViewID)
{
    // If the view the user selected is already displaying, do nothing
    if (ViewID == m_CurrentView)
        return;

    // Get a pointer to the current view
    CView* pCurrentView = GetActiveView();

    // We are about to change the view, so we need a pointer to the runtime class
    CRuntimeClass* pNewView = NULL; // Added = NULL because it wouldn't allow program to be run without initialization of pNewView

    // We will process a form
    // First, let's change the identifier of the current view to our integer
    ::SetWindowLong(pCurrentView->m_hWnd, GWL_ID, m_CurrentView);

    // Now we will identify what form the user selected
    switch (ViewID)
    {
    case IDD_CHOOSE_ITEM:
        pNewView = RUNTIME_CLASS(CChooseItemView);
        break;

    case IDD_ITEM_INFORMATION:
        pNewView = RUNTIME_CLASS(CItemInformationView);
        break;
    }

    // We will deal with the frame
    CCreateContext crtContext;

    // We have a new view now. So we initialize the context
    crtContext.m_pNewViewClass = pNewView;
    // No need to change the document. We keep the current document
    crtContext.m_pCurrentDoc = GetActiveDocument();

    CView* pNewViewer = STATIC_DOWNCAST(CView, CreateView(&crtContext));

    // Now we can create a new view and get rid of the previous one
    if (pNewViewer != NULL)
    {
        pNewViewer->ShowWindow(SW_SHOW);
        pNewViewer->OnInitialUpdate();
        SetActiveView(pNewViewer);
        RecalcLayout();
        m_CurrentView = ViewID;
        pCurrentView->DestroyWindow();
    }
}
2
MFC Doc/View: How to obtain a pointer to various objects?link. A very good overview, one from this table should help..!Tom Tom
If returns NULL, then other Panes, Splitters etc may be active. But you can still get the associated CView(s) from the existing CDocument.Tom Tom
Thanks you, but I already tried the link you gave. I tried the, from the CMainFrame get the CView (which is part of the code above). How would other panes and splitters be active? I am using the default SDI code that only opens one window and one form (whatever the default form is the wizard sets up). If I need to access the CView from within MainFrame, how would I get the views from the CDocument file? Would I create a CDocument object, then call a function from within it? Thanks for your help!Just Me
No active View, but you are sure there is a working view? Try first set SetActiveView(.. myView..) from your working Button form.Tom Tom

2 Answers

0
votes

The following code is working for me:

virtual CView* SwitchToView(CView* pNewView);

and in cpp:

CView* CMyDoc::SwitchToView(CView* pNewView)
{
	CMDIFrameWndEx* pMainWnd = (CMDIFrameWndEx*)AfxGetMainWnd();
	// Get the active MDI child window
	CMDIChildWndEx* pChild = (CMDIChildWndEx*)pMainWnd->MDIGetActive();
	// Get the active view attached to the active MDI child window.
	CView* pOldActiveView = pChild->GetActiveView();
	// Exchange control ID of old view
	// note: if you have more than two view you have to remember which view you switched to
	// so you can set it's old control ID correctly
	if(pNewView == m_pMyView)
		pOldActiveView->SetDlgCtrlID(CTRLID_MYVIEW2);
	if(pNewView == m_pMyView2)
		pOldActiveView->SetDlgCtrlID(CTRLID_MYVIEW);
	// Exchange control ID of new new
	// note: the control ID of the active view must always be AFX_IDW_PANE_FIRST
	pNewView->SetDlgCtrlID(AFX_IDW_PANE_FIRST);
	// 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;
}

I hope it help you.

0
votes

To get the a non active View but associated CView from CDocument, you can implement this schema in Doc

// ----- GetCChooseItemView() -- -Search the first associated CView in  INACTIVE Views too ! ------ 
CView* CMyDoc::GetCChooseItemView(void)
{
  CRuntimeClass* prt = RUNTIME_CLASS(CChooseItemView);
  CView* pView = NULL;

  // Continue search in inactive View by T(o)m

  POSITION pos = GetFirstViewPosition();
  while (pos != NULL)
  {
    pView = GetNextView(pos);
    if (pView->GetRuntimeClass() == prt)
    {
        if (pView->IsKindOf(RUNTIME_CLASS(CChooseItemView)))
            break;
    }
    pView = NULL;       // not valid vie
  }

  return static_cast<CChooseItemView*>(pView);
}

then add in your SelectView Code

void CMainFrame::SelectView(UINT ViewID)
{
  : (code as before)
  :      
  // Get a pointer to the current view
  CView* pCurrentView = GetActiveView();

  // Get a pointer to the current view
  CView* pCurrentView = GetActiveView();
  if (pCurrentView == NULL
  { 
    CMyDoc* pDoc = static_cast<CMyDoc*>(GetActiveDocument());
    if (pDoc)
    {
      pCurrentView = pDoc->GetChhoseItemView(); 
      if (pCurrentView == NULL)
         mpCurrentView = pDoc->GetCItemInformationView()  // let as exercise for the OP

      if (pCurrentView == NULL
      {
          DebugBreak();     // Errror No View found..
      }
    } 

  :  (code as befeore)
  :   
}