Microsoft KB Archive/298126

= PRB: MFC Vertical Toolbars May Not Display All Buttons After Customization =

Article ID: 298126

Article Last Modified on 7/17/2001

-

APPLIES TO


 * Microsoft Visual C++ 6.0 Service Pack 5

-



This article was previously published under Q298126



SYMPTOMS
When a Microsoft Foundation Classes (MFC) toolbar is positioned vertically, customization of the toolbar may result in one or more of the buttons failing to appear. The customization may be the result of adding or removing buttons through the use of the Customize function of CToolBarCtrl or similar programmatic methods.



CAUSE
Originally, MFC provided all details of objects such as toolbars, but starting with version 4.0, MFC began wrapping the common control implementations of toolbars, status bars, and so forth. This can result in a need to compensate for minor differences in the implementation of MFC controlbar classes.



RESOLUTION
The following code can correctly resize and redraw an MFC vertical toolbar, whether docked or floating, after buttons have been added or removed. The OnToolBarChange handler below is called in response to the TBN_TOOLBARCHANGE notification. The code essentially takes three steps. First, CalcDynamicLayout is called with the proper parameters for docked/floating/vertical/horizontal states. Second, DockControlBar (or FloatControlBar) is called, primarily to leverage the calls these functions make to SetWindowPos. Finally, DrawBorders is called to complete the redraw.

Add the following entry to your CMainFrame's message map manually (AFX_IDW_TOOLBAR is the ID of the toolbar). ON_NOTIFY(TBN_TOOLBARCHANGE, AFX_IDW_TOOLBAR, OnToolBarChange)

Add the OnToolBarChange member function to CMainFrame class and add the following code: void CMainFrame::OnToolBarChange(NMHDR *notify, LRESULT *result) {      // Update the toolbar icons. CFrameWnd* pFrame; if (m_wndToolBar.IsFloating) pFrame = m_wndToolBar.GetParentFrame; else pFrame = m_wndToolBar.GetDockingFrame;

CRect rectActualSize; CRect rectActualFrameSize; CRect rect; CSize size;

// Get the ToolBar's rectangle m_wndToolBar.GetWindowRect(&rect); // Are we horizontal? BOOL bHorz = (m_wndToolBar.m_dwStyle & CBRS_ORIENT_HORZ) != 0; if ((m_wndToolBar.m_dwStyle & CBRS_FLOATING) &&        (m_wndToolBar.m_dwStyle & CBRS_SIZE_DYNAMIC)) size = m_wndToolBar.CalcDynamicLayout(0, LM_HORZ | LM_MRUWIDTH |                                           LM_COMMIT); else if (bHorz) size = m_wndToolBar.CalcDynamicLayout(0, LM_HORZ | LM_HORZDOCK |                                           LM_COMMIT); else size = m_wndToolBar.CalcDynamicLayout(0, LM_VERTDOCK | LM_COMMIT);

// Use the result to calculate a new size rectActualSize = CRect(rect.TopLeft, size); rectActualFrameSize = CRect(rect.TopLeft, size);

// Calculate frame rectangle CMiniFrameWnd::CalcBorders(rectActualFrameSize);

// Leave room for the window's border. The values used here // for m_cxBorder and m_cyBorder are 2 and 2 as a result of       // calling GetSystemMetrics for SM_CXBORDER and SM_CYBORDER // (these should return 1) and multiplying the result by 2 // to accommodate the modern shell's wider borders. rectActualFrameSize.InflateRect(-m_cxBorder, -m_cyBorder); if (m_wndToolBar.IsFloating) {        pFrame->FloatControlBar(&m_wndToolBar,                            rectActualFrameSize.TopLeft); }    else pFrame->DockControlBar(&m_wndToolBar);

// force the frame window to recalculate the size m_wndToolBar.GetParentFrame->RecalcLayout;

CDC* pDC = GetDC; rectActualFrameSize.OffsetRect(-rectActualFrameSize.left,                                      -rectActualFrameSize.top); m_wndToolBar.DrawBorders(pDC, rectActualFrameSize); ReleaseDC(pDC); }

Add the following data members to CMainFrame class and initialize them in CMainFrame's OnCreate member function: int m_cyBorder; int m_cxBorder;

int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct) {       m_cxBorder = GetSystemMetrics(SM_CXBORDER); m_cyBorder = GetSystemMetrics(SM_CYBORDER); ..... }



STATUS
This behavior is by design.



MORE INFORMATION
In order to access the toolbar's customize feature you must set the CCS_ADJUSTABLE style to the toolbar control, as shown here: m_wndToolBar.GetToolBarCtrl.ModifyStyle(0, CCS_ADJUSTABLE);

After this change, at least one ToolBar notification must be handled for the ToolBar customization dialog box to appear correctly. This notification is TBN_QUERYINSERT, and it can be handled in the CMainFrame class with a handler such as the following: void CMainFrame::OnQueryInsert( NMHDR * pNotifyStruct, LRESULT * result ) {   *result = TRUE; }

The NMHDR structure is actually a NMTOOLBAR notification structure. Another notification that should be handled is TBN_GETBUTTONINFO. This is important because the notification is sent to request button information for those buttons that are available to be added to the toolbar. To properly handle this notification, the NMTOOLBAR structure's iItem member should be compared to the index of the original TBBUTTON structure array, and the handler should fill the structure with button information and set the result to TRUE.

