Click here to Skip to main content
15,881,687 members
Articles / Desktop Programming / MFC

Some Notes on CMFCToolBar – Docking Large Buttons and Use of the MDIClientArea

Rate me:
Please Sign up or sign in to vote.
4.58/5 (12 votes)
23 Jul 2013CPOL4 min read 141.5K   2K   36   20
Updating CToolBar to MFC Feature Pack (2008)

Introduction

This article deals with the CMFCToolBar class, and documents a number of details that changed from CToolBar and how to get CMFCToolBar to behave.

Background

CMFCToolBar is part of the MFC Feature Pack added in 2008, it replaces CToolBar. Visual Studio 2012 Update 2 was used in this article.

The code to create toolbars generally goes in the CMainFrame::OnCreate method. The creation of two toolbars is shown below to handle a toolbar with large buttons and another toolbar with standard size buttons. If only standard size buttons are used, one can skip the code that deals with szImage and szButton. This code is necessary to correctly display large buttons. First, declare m_nToolBar and m_nAnalysisTool to be CMFCToolBar.

C++
DWORD dwCtrlStyle = TBSTYLE_FLAT | TBSTYLE_TOOLTIPS | CBRS_SIZE_DYNAMIC;
DWORD dwStyle = AFX_DEFAULT_TOOLBAR_STYLE;
CMFCToolBarInfo tbi, tbiA;
const CRect r1(1, 1, 1, 1); 
if (!m_nToolBar.CreateEx(this, dwCtrlStyle, dwStyle, r1, IDR_MAINFRAME) ||
        !m_nToolBar.LoadToolBarEx(IDR_MAINFRAME, tbi, TRUE)
{
    return -1;      // fail to create
} 
// this permits large buttons (>16x15) to display correctly
CSize szImage, szButton;
szImage = m_nToolBar.GetImageSize();
szButton.cx = szImage.cx + 6; // button size must be at least image size + 6
szButton.cy = szImage.cy + 6;
m_nToolBar.SetMenuSizes(szButton, szImage);

if (!m_wndStatusBar.Create(this) || 
        !m_wndStatusBar.SetIndicators(indicators, sizeof(indicators)/sizeof(UINT)))
{
    return -1;      // fail to create
}

// Adding Extra ToolBar
if (!m_nAnalysisTool.CreateEx( this, dwCtrlStyle, dwStyle, r1, IDR_ANALYSIS_TOOL) ||
        !m_nAnalysisTool.LoadToolBarEx(IDR_ANALYSIS_TOOL, tbiA, TRUE))
{
    return -1;      // fail to create
} 
szImage = m_nAnalysisTool.GetImageSize();
szButton.cx = szImage.cx + 6;
szButton.cy = szImage.cy + 6;
m_nAnalysisTool.SetMenuSizes(szButton, szImage);

dwStyle = CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC;
m_nToolBar.SetPaneStyle(m_nToolBar.GetPaneStyle() | dwStyle);
m_nAnalysisTool.SetPaneStyle(m_nToolBar.GetPaneStyle() | dwStyle); 
EnableDocking(CBRS_ALIGN_ANY);

Note that LoadToolBarEx fills CMFCToolBarInfo if it is empty, so use a new one for each toolbar.

CMFCToolBar Placement Examples

Be sure to remove registry entries HKCU\Software\CompanyName\ProgramName\Workspace before testing the code, otherwise the last toolbar placement will be used, if you are loading the registry with your WindowPlacement.

Toolbars default to align at the top if CBRS_ALIGN_ANY is used.

Now for three examples illustrating placement of tool bars:

Example 1

The default behavior is for tool bars to stack on the top. This look is not always desired.

Image 1

Figure 1 Default Docking
C++
m_nToolBar.EnableDocking(CBRS_ALIGN_ANY);
DockPane(&m_nToolBar);

m_nAnalysisTool.EnableDocking(CBRS_ALIGN_ANY);
DockPane(&m_nAnalysisTool);

Example 2

For a CMFCToolBar to initially dock on a side but then have freedom to dock on any side, first force the desired side by EnableDocking only to the side you wish, then call DockPane. This correctly places the toolbar. Then can call EnableDocking again and permit more sides to be valid. The three lines below the figure show this.

Image 2

Figure 2 Docking top and bottom
C++
m_nToolBar.EnableDocking(CBRS_ALIGN_ANY); 
DockPane(&m_nToolBar); 
m_nAnalysisTool.EnableDocking(CBRS_ALIGN_BOTTOM); 
DockPane(&m_nAnalysisTool);
m_nAnalysisTool.EnableDocking(CBRS_ALIGN_ANY);

Example 3

To force docking side by side on the same bar at the top, first dock the rightmost pane and then add the additional pane to the left of it.

Image 3

Figure 3 Side by side docking
C++
m_nToolBar.EnableDocking(CBRS_ALIGN_ANY); 
m_nAnalysisTool.EnableDocking(CBRS_ALIGN_ANY);
DockPane(&m_nAnalysisTool);  
m_dockManager.DockPaneLeftOf(&m_nToolBar, &m_nAnalysisTool);

Notes on the Coding

Do not attempt to use DockToFrameWindow(), this method only works with the CDockablePane class, and CMFCToolBar does not have CDockablePane in its hierarchy. The DockToFrameWindow() method does nothing but return false when called from the CMFCTooBar class. One would think that the CMFCToolBar class would inherit from the CDockablePane class, but it does not.

CMFCToolBar does not take care of toggling itself on or off. CToolBar previously did take care of toggling if you used ID_VIEW_TOOLBAR. To handle toggling now, one needs to make the following additions to the message map. (This is generally done in the CMainFrame class.)

C++
ON_COMMAND(ID_VIEW_TOOLBAR, OnViewControls)
ON_UPDATE_COMMAND_UI(ID_VIEW_TOOLBAR, OnUpdateViewControls) 
ON_COMMAND(ID_VIEW_PLOTCONTROLS, OnViewAnalysisControls) 
ON_UPDATE_COMMAND_UI(ID_VIEW_PLOTCONTROLS, OnUpdateViewAnalysisControls)

Then add the methods.

C++
// Toggle the ToolBar on and off.
void CMainFrame::OnViewControls() // Called when View->ToolBar menuitem is pressed.
{
  m_nToolOpen = !m_nToolOpen;
  ShowPane(&m_nToolBar, m_nToolOpen, FALSE, TRUE);
  // Force resize of toolbar when the larger toolbar is removed
  // (a problem if both toolbars are on the same line)   
  if (!m_nToolOpen) RecalcLayout();
  m_wndClientArea.Invalidate();  // force redraw to correct for image shifting
}

void CMainFrame::OnUpdateViewControls(CCmdUI* pCmdUI)
// Called when View is pressed or when View->ToolBar menuitem is displayed
{
    pCmdUI->SetCheck(m_nToolOpen);
}

// Toggle the Analysis ToolBar on and off. void CMainFrame::OnViewAnalysisControls()
// Called when View->Analysis ToolBar menuitem is pressed.
{
  m_nAnalysisToolOpen = !m_nAnalysisToolOpen;
  ShowPane(&m_nAnalysisTool, m_nAnalysisToolOpen , FALSE, TRUE);
  m_wndClientArea.Invalidate();  // force redraw to correct for image shifting
}

void CMainFrame::OnUpdateViewAnalysisControls(CCmdUI* pCmdUI)
// Called when View is pressed or when View->ToolBar menuitem is displayed
{
    pCmdUI->SetCheck(m_nAnalysisToolOpen);
}

CMFCToolBar and Drawing on the MDIClientArea

There are issues with CMFCToolBar and drawing on the MDIClientArea. Toggling tool bars on and off or moving the docking location may cause the image on the MDIClientArea to be corrupted. The CToolBar class always triggers an OnDraw message to the

MDIClient
. With the MFC 2008 Feature pack, it is not possible to subclass, so one cannot override the OnDraw routine.

The methods OnView… shown above do not need the m_wndClientArea.Invalidate() lines, unless drawing on the MDIClientArea. When drawing in the client area, these lines are needed when toolbar manipulation causes the client area to change size as the resizing will corrupt your image.

The RecalcLayout() call was included to handle the situation where the toolbar with a larger button size was turned off and both toolbars were on the same line; the area with the toolbars did not resize for smaller buttons without being forced. These situations were handled automatically with the older CToolBar class.

The moving of toolbars may also corrupt your drawing on the client area. I wrote a small class CMFCToolBarEx to extend CMFCToolBar and override OnAfterChangeParent(). The code in CMFCToolBarEx.h is:

C++
#pragma once
 
// CMFCToolBarEx.h
 
class CMFCToolBarEx : public CMFCToolBar
{
    DECLARE_DYNAMIC(CMFCToolBarEx)
 
public:
    CMFCToolBarEx();
    virtual ~CMFCToolBarEx();
 
protected:
    DECLARE_MESSAGE_MAP()
public:
    virtual void OnAfterChangeParent(CWnd* pWndOldParent);
};

The code in CMFCToolBarEx.cpp is:

C++
// MFCToolBarEx.cpp : implementation file
//
 
#include "stdafx.h"
#include "MainFrm.h"
#include "MFCToolBarEx.h"
 
// CMFCToolBarEx
 
IMPLEMENT_DYNAMIC(CMFCToolBarEx, CMFCToolBar)
 
CMFCToolBarEx::CMFCToolBarEx()
{
}
 
CMFCToolBarEx::~CMFCToolBarEx()
{
}
 
BEGIN_MESSAGE_MAP(CMFCToolBarEx, CMFCToolBar)
END_MESSAGE_MAP()
 
// CMFCToolBarEx message handlers
 
 
// Overrides
 
void CMFCToolBarEx::OnAfterChangeParent(CWnd* pWndOldParent)
{
    CMainFrame* pFrame = (CMainFrame*) AfxGetMainWnd();
    if (pFrame)
    {
        CRect rect;
        pFrame->GetClientRect(rect);
        pFrame->InvalidateRect(rect);
    }
    CMFCToolBar::OnAfterChangeParent(pWndOldParent);
}

If you have two sets of images that you wish to display on a toolbar without changing the ID of the buttons, the following code will change out the images on the buttons. IDR_ANANLYSIS_TOOL and IDR_ANALYSIS_TOOL_RATE are toolbars that have the same size. The toolbars only differ by the images on the buttons.

Swapping Images on CMFCToolBar

If you have two sets of images that you wish to display on a toolbar without changing the ID of the buttons, the following code will change out the images on the buttons. IDR_ANANLYSIS_TOOL and IDR_ANALYSIS_TOOL_RATE are toolbars that have the same size. The toolbars only differ by the images on the buttons.

C++
void CMainFrame::SetAnalysisBar(void)
{
    BOOL b;
 
    m_nAnalysisTool.ResetAllImages();
    if (m_productionDataSet.m_PRODUCTION_MODE == 1)
        b = m_nAnalysisTool.LoadBitmap(IDR_ANALYSIS_TOOL);
    else
        b = m_nAnalysisTool.LoadBitmap(IDR_ANALYSIS_TOOL_RATE);
 
    if (b) m_nAnalysisTool.Invalidate();
}

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Engineer self-employed
United States United States
I started programming in High School in 1968/9 using Basic and a teletype machine with an acoustic coupler communicating with a computer in a distant city, such was the state of the art. Most of my career has been developing numerically intensive programs for Petroleum Engineers.

Comments and Discussions

 
GeneralMy vote of 5 Pin
Member 1154959213-Oct-15 22:19
Member 1154959213-Oct-15 22:19 
QuestionCMFCToolbar image disappears through remote desktop or when connected to projector Pin
ashish.02220-May-15 4:26
ashish.02220-May-15 4:26 
AnswerRe: CMFCToolbar image disappears through remote desktop or when connected to projector Pin
snavece21-May-15 5:39
snavece21-May-15 5:39 
GeneralRe: CMFCToolbar image disappears through remote desktop or when connected to projector Pin
ashish.02221-May-15 7:58
ashish.02221-May-15 7:58 
QuestionDocking to a child window Pin
RobertM20-Apr-15 22:11
RobertM20-Apr-15 22:11 
AnswerRe: Docking to a child window Pin
snavece21-Apr-15 3:14
snavece21-Apr-15 3:14 
GeneralDropDown SubMenu Pin
ITISAG23-Jul-14 15:47
ITISAG23-Jul-14 15:47 
GeneralRe: DropDown SubMenu Pin
snavece25-Jul-14 3:25
snavece25-Jul-14 3:25 
GeneralMy vote of 5 Pin
VinhTran_13-May-14 14:06
VinhTran_13-May-14 14:06 
QuestionMissing the code download link Pin
Theo Buys9-Apr-14 22:39
Theo Buys9-Apr-14 22:39 
AnswerRe: Missing the code download link Pin
snavece10-Apr-14 17:30
snavece10-Apr-14 17:30 
QuestionGood stuff (My 5) Pin
H.Brydon6-Aug-13 12:02
professionalH.Brydon6-Aug-13 12:02 
AnswerRe: Good stuff (My 5) Pin
snavece6-Aug-13 13:12
snavece6-Aug-13 13:12 
QuestionReplace image Pin
stevehoang5-Jul-13 6:52
stevehoang5-Jul-13 6:52 
AnswerRe: Replace image Pin
snavece6-Jul-13 1:24
snavece6-Jul-13 1:24 
GeneralRe: Replace image Pin
skyformat99@gmail.com7-Jul-13 19:33
skyformat99@gmail.com7-Jul-13 19:33 
GeneralRe: Replace image Pin
stevehoang3-Aug-14 10:58
stevehoang3-Aug-14 10:58 
GeneralMy vote of 5 Pin
skyformat99@gmail.com4-Jul-13 15:19
skyformat99@gmail.com4-Jul-13 15:19 
GeneralRe: My vote of 5 Pin
snavece10-Apr-14 17:30
snavece10-Apr-14 17:30 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.