Switching Toolbars in MDI
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;
}
}
int CDocTemplateEx::GetResourceID ()
{
return (m_nIDResource);
}
CArraym_aToolbars; CArray m_idrLoaded; CMainClient m_wndClient;
int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CMDIFrameWnd::OnCreate(lpCreateStruct) == -1)
return -1;
m_wndClient.SubclassWindow (m_hWndMDIClient); // this is what YOU add
...
}
#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.

Comments
Another Solution
Posted by Legacy on 06/07/2002 12:00amOriginally posted by: Amit Gefen
-
ReplyAn improvement for Visual C++ .Net
Posted by Jim McCreary on 06/30/2005 03:03pmWith the code above the toolbar did not show up properly for me using Visual C++ .Net (version 7) Basically I had to sub CreateEx for Create as: bool CMainFrame::SelectToolBar(UINT unIDR) { if ( m_pToolBar ) { delete m_pToolBar; } m_pToolBar = new CToolBar(); if (!m_pToolBar->CreateEx(this, TBSTYLE_FLAT, WS_CHILD | WS_VISIBLE | CBRS_TOP | CBRS_GRIPPER | CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC) || !m_pToolBar->LoadToolBar(unIDR)) { TRACE("Failed to create toolbar %d\n", unIDR); return false; } // delete the 3 lines below if toolbar is not to be dockable m_pToolBar->EnableDocking(CBRS_ALIGN_ANY); EnableDocking(CBRS_ALIGN_ANY); DockControlBar(m_pToolBar); return true; }ReplyDrag and drop between views in a splitter window
Posted by Legacy on 05/22/1999 12:00amOriginally posted by: Gene Rodrigues
Doesn't MFC handle this automatically based on the individual document templates you create using their assocaited IDR_DOCTYPE? If the menu name uses the same IDR_DOCTYPE defined for the template, the switch to the appropriate menu associated with the document template should be handled automatically.
Replycomments
Posted by Legacy on 03/26/1999 12:00amOriginally posted by: subrosa
You could also just stick the toolbar on the the client frame so you wouldn't have to switch all the time
ReplyDemo project aborts after selecting "switch" or "switch1"
Posted by Legacy on 03/23/1999 12:00amOriginally posted by: Steve Quick
Reply