3

I want to change the presented View by clicking a button inside the Window like this. My Project settings:

  1. I made an MFC Project (SDI) without Doc/View support.
  2. I made two more Views in the Designer and added Classes to them. The new View Classes are derived from CFormView. I changed the Constructor and Destructor of the new View Classes to public.

  3. Added them as pointers to MainFrm.h:

CMainView*        m_pMainView;
CSecondView*      m_pSecondView; 
  1. I changed the OnCreate(),OnSetFocus() and OnCmdMsg() Method of MainFrm.cpp like this: (That allows to present the FormView I made with the Designer)
int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
    if (CFrameWnd::OnCreate(lpCreateStruct) == -1)
        return -1;

    // First, build the view context structure
    CCreateContext ccx;

    // Designate the class from which to build the view
    ccx.m_pNewViewClass = RUNTIME_CLASS(CMainView);

    // Using the structure, create a view
    m_pMainView = DYNAMIC_DOWNCAST(CMainView, this->CreateView(&ccx));


    if (!m_pMainView)
    {
        TRACE0("creation of view failed");
    }

    // Do layout recalc
    RecalcLayout();

    // Show the view and do an initial update

    m_pMainView->ShowWindow(SW_SHOW);
    m_pMainView->OnInitialUpdate();

    // Set this view active
    SetActiveView(m_pMainView);

    // Order it to resize the parent window to fit
    m_pMainView->ResizeParentToFit(FALSE);


    return 0;
}

...

void CMainFrame::OnSetFocus(CWnd* /*pOldWnd*/)
{

    m_pMainView->SetFocus();
}

BOOL CMainFrame::OnCmdMsg(UINT nID, int nCode, void* pExtra, AFX_CMDHANDLERINFO* pHandlerInfo)
{

    if (m_pMainView->OnCmdMsg(nID, nCode, pExtra, pHandlerInfo))
        return TRUE;

    return CFrameWnd::OnCmdMsg(nID, nCode, pExtra, pHandlerInfo);
}

Now here comes my problem! I have a button on the First presented View and if you click on it, the view should change. I made the following function with the event handler in the Designer:

void CMainView::OnBnClickedButton1()
{
// What to do here? I want to change the current view to another View by clicking the button
}

If i handle it in the MainFrm.cpp class for example with menue buttons it is no problem... that works fine:

void CMainFrame::OnViewNextview()
{
    CCreateContext ccx2;
    ccx2.m_pNewViewClass = RUNTIME_CLASS(CSecondView);
    m_pSecondView = DYNAMIC_DOWNCAST(CSecondView, this->CreateView(&ccx2));

    RecalcLayout();

    m_pMainView->ShowWindow(SW_SHOW);
    m_pMainView->OnInitialUpdate();

    SetActiveView(m_pMainView);

    m_pMainView->ResizeParentToFit(FALSE);

}

I tried to write a function in CMainFrame and call this function in CMainView::OnBnClickedButton1() but I don't know how to get the current MainFrm Object. A pointer on MainFrm or a member of it in CMainView did not work.

I searched and red tutorials for days to solve my problem. I also tried it with Doc/View support like shown here: https://learn.microsoft.com/en-us/cpp/mfc/adding-multiple-views-to-a-single-document?view=vs-2019 but i dont know where to call switchView() correctly.

Maybe anyone can help...

Andrew Truckle
  • 17,769
  • 16
  • 66
  • 164
Xe Li
  • 41
  • 6

2 Answers2

3

First, you shouldn't really be overriding OnCmdMsg - instead, use DECLARE_MESSAGE_MAP in your header file and BEGIN_MESSAGE_MAP/END_MESSAGE_MAP in your implementation file, and insert handler messages between those two macros.

I see that you already have a handler in your CMainView class for the button click! From here, you should call the CMainFrame function to change to the next view - just as you do when the menu command is given (which you say works). Make that function public and give the MainView class access to a pointer to the main frame (or use AfxGetMainWnd() and cast it to a pointer of your class). Something like this:

void CMainView::OnBnClickedButton1()
{
    AfxGetMainWnd()->PostMessage(WM_COMMAND, menuID); // ID of menu command that works!
}
Andrew Truckle
  • 17,769
  • 16
  • 66
  • 164
Adrian Mole
  • 49,934
  • 160
  • 51
  • 83
1

Big hugs for Adrian, i got it to work! I also added a third view successfully :)

It is very IMPORTANT , to HIDE the last shown Window if you want to implement more views. you can do it like:

void CMainFrame::OnView3()
{
    CCreateContext ccx3;
    ccx3.m_pNewViewClass = RUNTIME_CLASS(CThirdView);
    m_pThirdView = DYNAMIC_DOWNCAST(CThirdView, this->CreateView(&ccx3));

    RecalcLayout();

    m_pSecondView->ShowWindow(SW_HIDE); // Hide the last Window
    m_pThirdView->ShowWindow(SW_SHOW);  // Show the new Window

    m_pThirdView->OnInitialUpdate();
    SetActiveView(m_pThirdView);
    //m_pThirdView->ResizeParentToFit(FALSE); //if you call this, the size of the window is the same like in the Designer
}
Xe Li
  • 41
  • 6
  • 1
    Glad it worked! But I would re-emphasize that you should do away with your override of OnCmdMsg! As far as I can see, it does nothing useful but potentially could cause many, many problems! Messages that are intended for the MainView window will be sent there by the framework; message sent to (and received by) the MainFrame are for it, and it alone! – Adrian Mole Aug 18 '19 at 16:15
  • I did, i have a problem with the void CMainFrame::OnSetFocus() Method. I tried to switch from view2 to View3 but the focus does not change correctly. Maybe you can give me a tipp here. – Xe Li Aug 18 '19 at 18:11
  • Test GetActiveView() and, if that's non-NULL, then use GetActiveView()->SetFocus() – Adrian Mole Aug 18 '19 at 18:19
  • if (GetActiveView() != NULL) { GetActiveView()->SetFocus(); } i tried this in the OnSetFocus() but that doesnt seem to have an effect – Xe Li Aug 18 '19 at 18:33
  • Maybe put a "CFormView *current" member in your frame window class, set this to NULL or whatever is actually the one you want (when you make and show each form) and use that: current->SetFocus(). Not sure about SDI, but MDI apps return the 'frame' of the active window with MDIGetActive(). – Adrian Mole Aug 18 '19 at 18:59
  • Ok i got it now! I had to HIDE the last shown Window when i show another one. I did it with m_pMainView->ShowWindow(SW_HIDE) and m_pSecondView->ShowWindow(SW_SHOW); – Xe Li Aug 19 '19 at 09:02