Click here to Skip to main content
Click here to Skip to main content
Go to top

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

, 23 Jul 2013
Rate this:
Please Sign up or sign in to vote.
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.

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.

Figure 1 Default Docking
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.

Figure 2 Docking top and bottom
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.

Figure 3 Side by side docking
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.)

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.

// 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:

#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:

// 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.

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)

Share

About the Author

snavece
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.
Follow on   Google+   LinkedIn

Comments and Discussions

 
GeneralDropDown SubMenu [modified] PinmemberITISAG23-Jul-14 15:47 
GeneralRe: DropDown SubMenu Pinmembersnavece25-Jul-14 3:25 
GeneralMy vote of 5 PinmemberMember 780004013-May-14 14:06 
QuestionMissing the code download link PinmemberTheo Buys9-Apr-14 22:39 
AnswerRe: Missing the code download link Pinmembersnavece10-Apr-14 17:30 
QuestionGood stuff (My 5) PinmemberH.Brydon6-Aug-13 12:02 
AnswerRe: Good stuff (My 5) Pinmembersnavece6-Aug-13 13:12 
QuestionReplace image Pinmemberstevehoang5-Jul-13 6:52 
AnswerRe: Replace image Pinmembersnavece6-Jul-13 1:24 
GeneralRe: Replace image Pinmemberskyformat99@gmail.com7-Jul-13 19:33 
GeneralRe: Replace image Pinmemberstevehoang3-Aug-14 10:58 
GeneralMy vote of 5 [modified] Pinmemberskyformat99@gmail.com4-Jul-13 15:19 
GeneralRe: My vote of 5 Pinmembersnavece10-Apr-14 17:30 

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

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

| Advertise | Privacy | Mobile
Web04 | 2.8.140905.1 | Last Updated 23 Jul 2013
Article Copyright 2013 by snavece
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid