The article describes how Prof-UIS implements the dockable
control bar mechanism. It also explains the most important operations
on the dockable control bar including how its position is set in
a frame window.
Important terms
There are several terms that may have different meanings to different
people. Brief descriptions of some important terms are given below.
- Frame window
- An overlapped/popup window with one child window in the center area
and a set of child windows (control bars) that can be fixed
to its borders.
- Docking site
- A popup frame window that contains a set of control bars in its
either docked or floating state.
- Floating container (floating palette, floating frame, mini frame)
- A special kind of the frame window that encloses only one child docking
bar window with the
AFX_IDW_DOCKBAR_FLOAT dialog control identifier.
The docking bar window encloses one or more control bars.
Floating containers are created and destroyed automatically with
the control bar’s drag-and-drop algorithm.
- Control bar
- The generalized MFC implementation of the window that can be either fixed
to any of the borders of its parent frame window or floated in
the floating container.
- Fixed-size control bar
- A fixed-size control bar (e.g. toolbars or menu bars). The size of
the fixed bar in its docked state could not be changed by dragging
its borders.
- Resizable control bar *
- A control bar that can be resized by dragging its borders and docked in
the dynamic control bar containers.
- Docking bar
- A kind of an MFC control bar which is used as a parent window for
all the control bars with the re-docking feature turned on
(
CControlBar::EnableDocking() is used for this).
Basically MFC provides two types of docking bars, which are implemented
as the internal class (CDockBar ): floating bar (with the dialog control
identifier set to AFX_IDW_DOCKBAR_FLOAT ) and docking bar fixed to
the sides of the docking site (with the dialog control identifiers
set to AFX_IDW_DOCKBAR_LEFT ,
AFX_IDW_DOCKBAR_RIGHT , AFX_IDW_DOCKBAR_TOP , or
AFX_IDW_DOCKBAR_BOTTOM ). MFC supports only four docking bars
for one docking site at the time (these bars are marked with red in
the below). In Prof-UIS these bars are called "circle 0" or
"outer docking bar circle". Both fixed and resizable bars
can be docked into "circle 0", but the drag-and-drop algorithm
for resizable bars docks them only into the Prof-UIS-specific
inner docking bar "circles" with numbers starting from 1.
In the figure below, "circle 1" is marked with blue,
"circle 2" - with green. Inner circles are created and
destroyed dynamically with the drag-and-drop algorithm for
the resizable bar. These inner circles "allow" resizable bars
to be docked to each other in a nested way. The fixed-size control bars
could be docked only into "circle 0" marked with red.
- Docking site’s client area
- The area that is free of any bars. It is marked with yellow in the figure
and used by MDI client windows in MDI applications and the view window
in SDI applications.
- Dynamic control bar container *
- A special kind of the resizable control bar, which is created dynamically
and used for docking other resizable bars to horizontal rows inside
vertical rows and vice versa. The dynamic control bar container like
any resizable control bar can take up part of the docking site or
part of the floating container.
- Status bar
- The MFC implementation of the status line. The status bar cannot be
re-docked by dragging any its area. It takes up part of the docking site
under the lowest docking bar (i.e. under the red "circle 0").
* Prof-UIS - specific term
How to dock fixed-size control bars relatively each other?
To set a certain fixed docking bar location, just call your
CMainFrame::DockControlBar() method with the appropriate
parameter values. The following example arranges two toolbars into
one horizontal image at the bottom of a frame window:
DockControlBar(
&m_wndToolBar1,
AFX_IDW_DOCKBAR_BOTTOM
);
CRect wrAlreadyDockedToolBar;
m_wndToolBar1.GetWindowRect( &wrAlreadyDockedToolBar );
wrAlreadyDockedToolBar.OffsetRect( 0, 1 );
DockControlBar(
&m_wndToolBar2,
AFX_IDW_DOCKBAR_BOTTOM,
&wrAlreadyDockedToolBar
);
How to dock resizable bars relatively each other?
Use the CExtControlBar::DockControlBar() methods
(two overloaded functions) to set the relative positions of the
control bars. In the sample below, the first method docks the
m_wndResourceViewBar resizable bar to the newly created
row in the left part of "docking circle 1". The second one is
applied to the already docked m_wndResourceViewBar bar,
with its parameters specifying the position of the
m_wndServerExplorerBar bar relatively to the
m_wndResourceViewBar one.
m_wndResourceViewBar.DockControlBar(
AFX_IDW_DOCKBAR_LEFT,
1,
this,
false
);
m_wndResourceViewBar.DockControlBar(
&m_wndServerExplorerBar,
true,
true,
this,
false
);
How to show or hide docked or floating control bars?
To make both fixed-size bars and resizable bars visible/invisible,
the CFrameWnd::ShowControlBar() method should be used.
The CControlBar::ShowWindow() cannot be used here,
because it does not affect the positions of other bars in the same
frame window (i.e. the method does not perform the frame layout
recalculation).
How to float fixed-size bar?
For this purpose, use either
CExtControlBar::FloatControlBar() , or
CFrameWnd::FloatControlBar() . Both methods produce
the same results.
How to float resizable bar?
The CExtControlBar::FloatControlBar() method should be used.
The CFrameWnd::FloatControlBar() method is not allowed.
How to enable control bars in the docking site to be re-dockable?
Usually all the control bars (but the status bar) in any docking site
are enabled to be re-dockable. This feature is turned on by performing
the following two steps. First, call the
static CExtControlBar::FrameEnableDocking( pDockSite )
method. Second, invoke the CExtControlBar::EnableDocking()
method of the bar.
If a bar is not re-dockable, its parent window is the docking site.
In case of a dockable bar, the parent window is always a docking bar
window (even for a floating palette).
IMPORTANT: CExtControlBar::FrameEnableDocking( pDockSite )
should be used instead of CFrameWnd::EnableDocking() .
How to activate resizable bar that is not visible?
The call of the static CExtControlBar::DoFrameBarCheckCmd(
pDockSite,
nReisizableBarDlgCtrlID,
false)
method activates the resizable bar being in any state.
How to set initial size for resizable control bar?
Use the three methods below to initialize the desired size of a bar
that is either in the docked state (vertical/horizontal) or
in the floating state:
SetInitDesiredSizeVertical( CSize )
SetInitDesiredSizeHorizontal( CSize )
SetInitDesiredSizeFloating( CSize )
The real sizes of docked bars are adjusted proportionally between all
the resizable bars in one row.
Please note that the bar can be in the floating state only when it itself
is the single bar in its floating container. In any other case,
the bar is in the docked state.
How to detect whether bar is in floating container or in docking site?
Call the CExtControlBar::GetParentFrame() method to get
the pointer to the parent CFrameWnd -based window.
If this returned object is kind of CMiniFrameWnd , the
bar is docked inside a floating container. Otherwise the bar is
docked in the docking site.
How to detect whether bar is visible or not?
Retrieve the bar window style flags by calling the GetStyle()
method. The bar window is visible if its window style flags have the
WS_VISIBLE flag. The CControlBar::IsVisible()
method can additionally detect whether the bar is temporarily
invisible.
How to handle control bar’s show/hide commands and update their associated command states in docking site?
These commands make each control bar visible/invisible. They are
usually marked with check marks, which indicates visibility of the bars.
Every docking bar has its own unique dialog control identifier and
the corresponding menu command in the docking site. In this case,
the context menu with the list of all the docking bars can be activated
on every frame point. So, to set the correct check mark for
the "Show/Hide" command of the bar, you should add
the following two lines to the frame’s message map:
ON_COMMAND_EX( ID_BAR_... , OnBarCheck )
ON_UPDATE_COMMAND_UI( ID_BAR_... , OnUpdateControlBarMenu )
How to handle control bar’s show/hide commands and update their associated command states in docking site like in Visual Studio .NET?
First, see the previous answer. The difference is in the command
handling/updating for the resizable bars. These commands have no check
marks and are only used to activate resizable control bars. They never
hide bars. Implement the new OnBarCheck() and
OnUpdateControlBarMenu() methods in the docking site:
BOOL CMainFrame::OnBarCheck( UINT nID )
{
return
CExtControlBar::DoFrameBarCheckCmd(
this,
nID,
false
);
}
void CMainFrame::OnUpdateControlBarMenu( CCmdUI * pCmdUI )
{
CExtControlBar::DoFrameBarCheckUpdate(
this,
pCmdUI,
false
);
}
How to load/save state of docking bars?
The state persistence is usually implemented in your
CMainFrame ’s OnCreate() and
DestroyWindow() methods.
To load bars’ state:
CExtControlBar::ProfileBarStateLoad(
this, // some kind of CFrameWnd
pApp->m_pszRegistryKey, // application registry key (usually company name)
pApp->m_pszProfileName, // application profile name (usually product name)
pApp->m_pszProfileName // Prof-UIS profile name
);
To save bars’ state:
CExtControlBar::ProfileBarStateSave(
this, // some kind of CFrameWnd
pApp->m_pszRegistryKey, // application registry key (usually company name)
pApp->m_pszProfileName, // application profile name (usually product name)
pApp->m_pszProfileName // Prof-UIS profile name
);
How to add Visual Studio .NET like resizable control bar to frame window?
You should add the CExtControlBar member in the frame
window class declaration. Creating a resizable control bar is similar
to that of toolbar.
How to insert window into resizable control bar?
When creating such a child window, pass a pointer to
CExtControlBar instance in the "parent window"
parameter to the child window Create() method. After
that, the control bar will automatically adjust the child window
to its client area. So far, the resizable control bar allows only
one child window
How to add docking menu bar to frame window?
The docking menu bar is implemented just as an ordinary toolbar.
Any needed initialization should be performed in your
CMainFrame ’s OnCreate() handler. Moreover,
you need to add a frame window class member of
CExtMenuControlBar class.
...
if( !m_wndMenuBar.Create(
_T( "Menubar name" ),
this,
ID_VIEW_MENUBAR
)
||
!m_wndMenuBar.LoadMenuBar( IDR_MAINFRAME )
)
{
TRACE0( _T( "Failed to create menubar\n" ) );
return -1;
}
...
m_wndMenuBar.EnableDocking( CBRS_ALIGN_ANY );
...
CExtControlBar::FrameEnableDocking( this );
...
DockControlBar( &m_wndMenuBar );
...
By default, CExtMenuControlBar does not activate menu
on pressing the ALT key. To enable this, you should
override the PreTranslateMessage() virtual function
in a frame window class and add the following lines before
the parent PreTranslateMessage() :
if( m_wndMenuBar.TranslateMainFrameMessage( pMsg ) )
return TRUE;
In the case of MDI, repeat the same in the child frame window class.
|