Switching Toolbars in MDI

The following method displays specific toolbar for each MDI child
window CView type, identified by an ID related to that doc/view, while
the mainframe toolbar is always displayed.

The idea is to retrieve the toolbar ID from the view class. This
is done by identifying the active MDI child, retrieving its document class,
and from that document class retrieving the template class which holds
the ID. This is done each time a new window is set, by detecting WM_MDISETMENU
message in the client window (CMainClient).

The main frame window holds two additional arrays: one of the toolbar
pointers and one of the IDs of the already loaded toolbar. When a new menu
is set, the main frame searches for the toolbar ID loaded IDs array. If
found, the toolbar from the loaded toolbar array, from index if the required
ID, is displayed. Otherwise, a new toolbar created, and the toolbar pointer
and the ID are stored in the appropriate arrays and that toolbar is displayed.

This code was developed and tested using VC6.0 on NT 4.

The following 3 pictures show the demo application with toolbar
1 (figure 1), toolbar 2 (figure 1) and without toolbar (figure 3). The
differences are in the buttons background



Figure 1: Mainframe toolbar and Tolbar 1 are shown.



Figure 2: Mainframe toolbar and Tolbar 2 are shown.



Figure 3: Only mainframe toolbar is shown.

Integration

In order to integrate this method into your code you should do
the following:


  • Create a toolbar for each one of your doc/view classes. Give
    that toolbar the same ID as the menu ID that assigned for that doc/view.

  • Create a new class, say CMainClient, derived from CWnd (generic
    CWnd), to be used as the MDI client

  • Add the following two handlers to your MDI client class (CMainClient):

  • LRESULT CMainClient::DefWindowProc(UINT message, WPARAM wParam, LPARAM lParam)
    {
    /***************************************************************\
    | This function calls the main frame window to switch toolbars |
    | when a new MDI menu is set. |
    \***************************************************************/
    LRESULT lRet = CWnd::DefWindowProc(message, wParam, lParam);
    if (message == WM_MDISETMENU) {
    CMainFrame *pFrame;

    pFrame = (CMainFrame *) AfxGetMainWnd ();
    if (::IsWindow (pFrame))
    pFrame->SwitchToolbar ();
    }
    return (lRet);
    }

    void CMainClient::OnParentNotify(UINT message, LPARAM lParam)
    {
    /***************************************************************\
    | This function calls the main frame window to switch toolbars |
    | when a all the MDI child windows are closed. |
    \***************************************************************/
    CWnd::OnParentNotify(message, lParam);
    CMainFrame *pFrame;
    CWnd *pWnd;

    pWnd = AfxGetMainWnd ();
    if (pWnd->IsKindOf (RUNTIME_CLASS (CMainFrame)))
    pFrame = (CMainFrame *) AfxGetMainWnd ();
    else
    return; // don’t crash the application, just leave
    switch (LOWORD (message)) {
    case WM_CREATE:
    m_nChilds++;
    break;
    case WM_DESTROY:
    m_nChilds–;
    if (m_nChilds == 0)
    pFrame->SwitchToolbar ();
    break;
    default:
    break;
    }
    }

  • Create a new class, say CDocTemplateEx, derived from CDocTemplate. Add the
    following public method to this class:

  • int CDocTemplateEx::GetResourceID ()
    {
    return (m_nIDResource);
    }

  • Add the following member variables to CMainFrame class:

  • CArray m_aToolbars;
    CArray m_idrLoaded;
    CMainClient m_wndClient;

  • Add the following line in CMainFrame::OnCreate function, immediately
    after the call to CMDIFrameWnd::OnCreate:

  • int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
    {
    if (CMDIFrameWnd::OnCreate(lpCreateStruct) == -1)
    return -1;

    m_wndClient.SubclassWindow (m_hWndMDIClient); // this is what YOU add

    }

  • Add the following method to CMainFrame class:

  • #include “DocTemplateEx.h”

    void CMainFrame::SwitchToolbar ()
    {
    /***************************************************************\
    | This function retrive the resource ID from the current view. |
    | Then it calls ‘SetToolbar’ to activate the specified toolbar |
    | and to disactivets all the others. |
    | If no view is open the resource ID, ‘idResource’, is set to 0 |
    | and all toolbars are disactivated. |
    | External functions used: |
    | IsWindow (CWnd *pWnd) |
    \***************************************************************/

    CView *pView;
    CDocTemplateEx *pTmpl;
    CMDIChildWnd *pKid;
    int idResource = 0; // initialize incase no resource is found

    pKid = MDIGetActive ();
    if (::IsWindow (pKid)) {
    pView = pKid->GetActiveView ();
    if (::IsWindow (pView)) {
    pTmpl = (CDocTemplateEx *) pView->GetDocument ()->GetDocTemplate ();
    idResource = pTmpl->GetResourceID ();
    }
    }
    SetToolbar (idResource);
    }

    void CMainFrame::SetToolbar (int nIdr)
    /***************************************************************\
    | This function gets the toolbar index to the toolbars array, |
    | ‘m_vToolbars’. The it loops over all the toolbars. If the |
    | toolbar the one to be displayed it is closed. |
    | External functions used: |
    | ShowControlBar |
    | RecalcLayout |
    \***************************************************************/
    {
    static int nToolbars;
    int n, nIdx;
    CString str;
    CToolBar *pTB;

    str.Format (“Toolbar #%d”, ++nToolbars);
    nIdx = AddToolbar (nIdr, str);
    for (n=0 ; n < m_vToolbars.GetSize () ; n++) { pTB = m_vToolbars.GetAt (n); if (n != nIdx) { ShowControlBar (pTB, 0, 0); } else ShowControlBar (pTB, 1, 1); } m_wndToolBar.GetParentFrame()->RecalcLayout();
    }

    int CMainFrame::AddToolbar (int nIDR, CString strWndTxt)
    /***************************************************************\
    | This function returns the index of the toolbar, that have the |
    | ID of ‘nIDR’, in the toolbar array, ‘m_vToolbars’. |
    | If the ID does not exist in the loaded ID array, ‘m_idrLoaded’|
    | the function creates a new toolbar, ads the toolbar pointer |
    | to the toolbar array and the ID to the loaded toolbar IDs |
    | array. |
    | The function also docks the toolbar left to the mainframe |
    | toolbar. |
    | External functions used: |
    | ShowControlBar |
    | FindInArray |
    \***************************************************************/
    {
    CToolBar *pTB;
    BOOL f;
    CRect rc;
    int nIdx;

    if (nIDR == 0)
    return (-1);
    if ((nIdx = ::FindInArray (m_idrLoaded, nIDR)) < 0) { pTB = new CToolBar; pTB->Create (this);
    f = pTB->LoadToolBar (nIDR);
    if (f == 0) {
    pTB->DestroyWindow ();
    delete pTB;
    return (-1);
    }
    pTB->SetBarStyle(m_wndToolBar.GetBarStyle() |
    CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC);
    pTB->EnableDocking(CBRS_ALIGN_TOP);
    m_wndToolBar.GetWindowRect (&rc);
    rc.OffsetRect(1,0);
    DockControlBar(pTB, AFX_IDW_DOCKBAR_TOP, &rc);
    pTB->SetWindowText (strWndTxt);
    pTB->ShowWindow (SW_RESTORE);
    ShowControlBar (pTB, 1, 1);
    nIdx = m_vToolbars.Add (pTB);
    m_idrLoaded.Add (nIDR);
    }
    return (nIdx);
    }

I hope someone out there find this helpful.
I’ll be thankful for any comment and/or correction.

Download demo project – 47 KB

More by Author

Get the Free Newsletter!

Subscribe to Developer Insider for top news, trends & analysis

Must Read