Dynamic toolbar has fixed size when docked






4.78/5 (9 votes)
Nov 3, 2000

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.