This development of this source code was partially sponsored by Dundas Software, and is also used to implement stacked docking dialog bars in these Dundas Software’s MFC components – Ultimate Diagram and the HyperView scriptable forms environment.
Resizable control bar, that can be resized both when docked and when floating.
Multiple sizing control bars can be docked on the same row/column.
Dynamic resizing when docked.
State persistence support (SaveState/LoadState).
Gripper with “hide bar” flat button.
No custom resources were used (bitmaps, cursors, strings, etc.), so the integration is easier and you have full control over the resources you eventually use in derived classes.
Easy to use: just derive your own control bar(s) from CSizingControlBar then add your child controls.
Environment: VC++ 5.0, 6.0; Win95/98 and NT 4.0; UNICODE enabled.
The functionality is somewhat like DevStudio’s control bars. However, the look is not the same, as the main goal was to get an easy to use class. Personally, I like it how it is now, but feel free to send me your suggestions.
Derive a class from CSizingControlBar (you have an example in mybar.h and mybar.cpp).
Add a member variable to CMainFrame (in mainfrm.h).
Create the bar in CMainFrame::OnCreate(). Then set bar styles, enable it to dock… like any control bar.
if (!m_wndMyBar.Create(_T(“My Bar”), this, CSize(200, 100),
TRUE /*bHasGripper*/, AFX_IDW_CONTROLBAR_FIRST + 32))
TRACE0(“Failed to create mybarn”);
return -1; // fail to create
CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC);
This class is intended to be used as a base class. Do not simply add your code to the sizecbar.* files – instead create a new class derived from CSizingControlBar and put there what you need.
Window IDs: You can see above that the control bar is created with the ID AFX_IDW_CONTROLBAR_FIRST + 32. The usage of IDs in the range of AFX_IDW_CONTROLBAR_FIRST + 32 .. AFX_IDW_CONTROLBAR_LAST is required only if the bar will not be enabled for docking (that’s is – it will stay fixed right under the frame’s menu). But in this situation you won’t be able to fully use the features of this class, so if you will enable it to dock (a reasonable guess 🙂 then you can use any valid window ID.
Another place where the IDs are important is the saving/loading of the bar’s state. You must use different IDs for each control bar that is enabled to dock, and this includes the other bars too. For example, if you have two toolbars, you can create the first one with the default ID (which is AFX_IDW_TOOLBAR = AFX_IDW_CONTROLBAR_FIRST), but the second one must have a different ID.
OnUpdateCmdUI: This member function is pure virtual in CControlBar (the base class of CSizingControlBar). Its purpose is to allow updating of controls at idle time (from here CCmdUI::DoUpdate() is called for the toolbars’ buttons, dialogbars’ controls, the panes of status bar, etc.).
However, I found it very useful to update the look of the “x” flat button (no timers needed). So, if you will use this function, don’t forget to call the base class’ member (see mybar.cpp).
Dynamic resizing: This feature allows redrawing of the bar during resizing. Also all the bars are repositioned and redrawn if necessary.
The SPI_GETDRAGFULLWINDOWS system parameter is queried for this (it is enabled by the “Show window contents while dragging” checkbox in Display Properties).
State persistence: The common MFC control bars’ docking state is saved using CMainFrame::SaveBarState(). In addition to the info saved by this function, the CSizingControlBar class needs to save 3 sizes. This is done in CSizingControlBar::SaveState() function, so a m_wndMyBar.SaveState() call is required. Please note that the state storing code must be placed in CMainFrame::DestroyWindow(), not in OnDestroy(), because at the time WM_DESTROY message is received, the floating bars are already destroyed.
In CMainFrame::OnCreate(), the m_wndMyBar.LoadState() call must be placed before LoadBarState().
Alternatively, if you have multiple CSizingControlBar derived bars, you can call once the static member CSizingControlBar::GlobalSaveState() instead of calling each bar’s SaveState(). The same for LoadState() – there is a CSizingControlBar::GlobalLoadState() function. See both samples here for more details.
Updates since the first release:
- The control bar color will change automatically if the user changes the system colors.
- It is no longer necessary to override the RecalcLayout() member function of CMainFrame. The control bar will handle this internally.
- Simplified the child controls size updating (see mybar.cpp).
- Replaced IsHorz() member function with IsHorzDocked(). Also added IsVertDocked().
- Restructured background and non-client painting so you can use memory DC painting in client area.
- Made public the size member variables. In this way, the size of the control bar can be saved and/or changed anytime you want (see mainfrm.cpp).
- Added a gripper. It can be disabled if you don’t like it.
- Added a string parameter for the control bar title in Create().
- Modified Create() to avoid an ASSERT that prevented the code to run under Visual C++ 6.0 .
- Added the dynamic resizing feature.
- Another Create() fix for VC 6.0.
- Moved OnUpdateCmdUI() to CMyBar sample derived class.
- Enforced a maximum size for resizing.
- Added multiple bars/row docking support.
- Added the “x” – like button for hiding the bar.
- Added state persistence support.
- Made the client area smaller – now you can use GetClientRect() to get the new rectangle for child(ren) position in OnSize().
- OnUpdateCmdUI() is back in CSizingControlBar. If you use it for updating controls, call the base class’ member too.
- Major rewrite, a few bugs fixed, etc.
Date Posted: 25 Jan 1998
Last Updated: 1 Mar 1999