65.9K
CodeProject is changing. Read more.
Home

Dynamic toolbar has fixed size when docked

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.78/5 (9 votes)

Nov 3, 2000

viewsIcon

135695

How to ensure that your docking toolbars are of a particular size when docked

Introduction

When creating a toolbar in MFC, you can turn on either the CBRS_SIZE_FIXED style or the CBRS_SIZE_DYNAMIC style. With the fixed style, you define places where breaks should occur, and these cannot be changed by the user, either when the toolbar is docked or when it is floating (unless, of course, you have some property page somewhere to allow them to specify the size). With the dynamic style, the user can resize the toolbar when it is floating, but when it gets docked, it resets itself to a single row or single column.

For my application, I wanted to have toolbars that would act both as a fixed and a dynamic toolbar. When it is floating, the user should be able to resize the toolbar. Then, when the toolbar gets docked, it should maintain the size that was set by the user. MFC will not allow this, and it will assert if you try to create a toolbar with both the CBRS_SIZE_DYNAMIC and the CBRS_SIZE_FIXED styles.

However, I found an easy way to trick MFC. In fact, this only requires a few lines of code. You need to derive a class from CToolBar, in my case I called it CToolBarEMRL. You create a toolbar with the style CBRS_SIZE_DYNAMIC.

In your derived class, you need to override the virtual function CalcDynamicLayout(). This function is called by MFC when it needs to know the toolbar size. The flag nMode will contain LM_HORZDOCK when the toolbar size should reflect docking to the top or bottom of the main frame window. Similarly, nMode contains LM_VERTDOCK when docking to the left or right of the main frame. This is the flag that causes MFC to use a single row or single column of tools in the toolbar. To keep the floating size, we must turn off this flag from the nMode variable, and turn on the LM_MRUWIDTH flag. The latter flag tells MFC to use the "most recently used" dynamic width when calculating the toolbar size. After resetting the nMode flag, we just need to call the base class version and return the result.

Here is the code for the overridden CalcDynamicLayout() function:

//////////////////////////////////////////////////////////
// FUNCTION  CToolBarEMRL::CalcDynamicLayout
// PURPOSE   calculates the dynamic layout of the toolbar
//
CSize CToolBarEMRL::CalcDynamicLayout (int nLength, DWORD nMode)
{
   if (m_bKeepSizeWhenDocked && (nMode & LM_VERTDOCK)) {
      return CToolBar::CalcDynamicLayout(nLength,
                            (nMode & ~LM_VERTDOCK) | (LM_MRUWIDTH));
   }
   else
   {
      return CToolBar::CalcDynamicLayout(nLength, nMode);
   }
} // CToolBarEMRL::CalcDynamicLayout

As you can see, I have a flag in the CToolBarEMRL class that controls whether the toolbar should keep its size or not. This allows me to use my derived class for any toolbar, whether or not it will have this docking size capability. Furthermore, my toolbars only keep their "floating" size when they are docked to the left or right side of the main frame window. The toolbar becomes a single row if it is docked to the top or bottom. If you want a toolbar to keep its size on any side, you just need to change the above 'if' statement with this:

if (m_bKeepSizeWhenDocked && ((nMode & LM_VERTDOCK) ||
                              (nMode & LM_HORZDOCK))) 
{
    return CToolBar::CalcDynamicLayout(nLength,
                            (nMode & ~(LM_VERTDOCK | LM_HORZDOCK)) |
                            (LM_MRUWIDTH));
}

The images below demonstrate how the toolbar behaves.