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();
}
}
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.
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)
:
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.