Objective Toolkit : Chapter 22 Docking Views : Using the Docking Views Architecture
Using the Docking Views Architecture
The topics that follow demonstrate how to utilize docking views in your applications.
To incorporate docking views into your application
1. Incorporate docking windows into your application. See “Using the Advanced Docking Windows Architecture” for more information.
2. In the InitInstance() method of your application object, modify your document template class to utilize SECMultiDocTemplate in place of CMultiDocTemplate.
SECMultiDocTemplate* pTemplate=new SECMultiDocTemplate(
IDR_RICHEDITTYPE,
RUNTIME_CLASS(CREditDoc),
pDefaultMdiChildFrameClass,
RUNTIME_CLASS(CRichEditView));
AddDocTemplate(pTemplate);
Docking views are not supported by SDI applications.
To set docking view styles
See “To set the style of a docking window.” In this chapter, see “Docking Views Options.”
To toggle the presence of the docking button on a dockable view frame
1. Create an SECMultiDocTemplate-derived class. Add the static data member, m_bDockingViewCaptionButton, to this class. Because it is static, this flag affects every docking view. For example:
 
// static docking view flags for easy access
static BOOL m_bDockingViewCaptionButton;
2. In the new class, override the OnEnableSysCommandEx() method to set the SCXOPT_NO_CAPTION_BUTTON style based conditionally on the state of m_bDockingviewCaptionButton, and then call the base class implementation. This override ensures that each new frame has the appropriate docking style.
 
// This virtual callback is called when a new
// frame is being created. Override to customize
// the docking view support. Note that changes
// set here do not take effect until the next
// frame is created (either a new document
// is opened, or an existing document is
// docked/undocked). Calling the EnableSysCommandEx
//frame window function is necessary for immediate
//update (must be used in conjunction with
// this override to maintain config through all
// docking states).
void CMyMultiDocTemplate::OnEnableSysCommandEx
(CFrameWnd* pFrame,
DWORD dwScxFlags)
{
// use the nsSysCommandEx namespace for
// easy typing
using namespace nsSysCommandEx;
 
// Flag that we are actively using the
// syscommandEx options:
dwScxFlags|=SCXOPT_ENABLED;
 
// do we want a caption button?
if(m_bDockingViewCaptionButton)
dwScxFlags&=~SCXOPT_NO_CAPTION_BUTTON;
else dwScxFlags|=SCXOPT_NO_CAPTION_BUTTON;
 
// Pass this info along to the base class
SECMultiDocTemplate::OnEnableSysCommandEx(
pFrame,
dwScxFlags);
}
3. In the InitInstance() method of your application object, modify your document template class to utilize the SECMultiDocTemplate-derived class.
 
CMyMultiDocTemplate* pTemplate = new CMyMultiDocTemplate(
IDR_MYRESTYPE,
RUNTIME_CLASS(CMyDoc),
RUNTIME_CLASS(SECWorksheetWnd),
RUNTIME_CLASS(CMyView)));
 
AddDocTemplate(pTemplate);
4. In the view class, add a new method, UpdateParentFrame(). This method updates the frame so they reflects the current state of the caption button.
 
void CMyView::UpdateParentFrame()
{
DWORD dwScxFlags=SCXOPT_ENABLED;
if(!CMyMultiDocTemplate::m_bDockingViewCaptionButton)
dwScxFlags|=SCXOPT_NO_CAPTION_BUTTON;
// If parent is a dockable frame, send flags
// as approp.
CFrameWnd* pFrame=GetParentFrame();
ASSERT(pFrame);
if( pFrame->IsKindOf(
RUNTIME_CLASS(SECMDIChildWnd)))
((SECMDIChildWnd*)pFrame)
->EnableSysCommandEx(dwScxFlags);
else if( pFrame->IsKindOf(
RUNTIME_CLASS(SECDockableFrame)))
((SECDockableFrame *)pFrame)
->EnableSysCommandEx(dwScxFlags);
 
// Signal a frame change to refresh
// caption button (if necessary)
pFrame->SetWindowPos(NULL,0,0,0,0,
SWP_NOZORDER|SWP_NOMOVE|
SWP_NOSIZE|SWP_FRAMECHANGED);
}
5. Add a toolbar button or a menu item handler that toggles the state of the caption button for the current view.
 
void CMyView::OnToggleDockingCaption()
{
CMyMultiDocTemplate::m_bDockingViewCaptionButton=
!CMyMultiDocTemplate::m_bDockingViewCaptionButton;
 
// The SECMultiDocTemplate::OnEnableSysCommandEx
// override will insure each new frame created
// will have the latest docking style. We
// still must explicitly update this
// current frame, though, for the changes to
// have an immediate effect.
UpdateParentFrame();
}
See the mdi sample in the <stingray-installdir>Samples\Toolkit\MFC\DockingViews\Bounce subdirectory for a demonstration of this technique.
To disable right mouse double-clicks on the docking view caption bar
See “To toggle the presence of the docking button on a dockable view frame” and replace SCXOPT_NO_CAPTION_BUTTON with SCXOPT_NO_HANDLE_RDBLCLK.
To create an initially docked view
When you call OpenDocumentFile(), which is typically in the InitInstance() method of your application object, specify the bInitiallyDocked parameter (the third parameter) to be TRUE. It defaults to FALSE if not specified. For example:
 
// Doc the cloud view initially
GetTemplate(CLOUD_DOCNAME)
->OpenDocumentFile(NULL, TRUE, TRUE);
To start an application with no initial view
Insert the following line immediately before the call to ProcessShellCommand() in the application object's InitInstance() method.
 
cmdInfo.m_nShellCommand = CCommandLineInfo::FileNothing;
To put a splitter in a docking view
1. Add a CSplitter object as a member variable in your view. You need to make the splitter a member of the view instead of the frame because the frame does not survive the docking process. For more information, see “Docking Views Containment Model.” For example:
 
CSplitterWnd m_wndSplitter;
2. In the OnCreate() method of the view, create the splitter window:
 
// Create a 1 x 2 splitter
BOOL bRC = m_wndSplitter.CreateStatic(
this, 1, 2);
3. Then, add additional windows or views.
 
// Embed view 1 in pane 0
m_wndSplitter.CreateView ( 0, 0,
RUNTIME_CLASS(CMyView),
size, pContext );
 
// Embed view 2 in pane 1
m_wndSplitter.CreateView ( 0, 1,
RUNTIME_CLASS(CMyView2),
size, pContext );
4. Add an OnSize() method to resize the splitter as needed.
//
// VERY IMPORTANT!!!
// You must size the contained window to the current size of
// the view otherwise you will see nothing!!!
void CMySplitterView::OnSize(UINT nType, int cx, int cy)
{
CView::OnSize(nType, cx, cy);
m_wndSplitter.SetWindowPos(&wndTop,0,0,cx,cy,
SWP_SHOWWINDOW);
}
The OnCreate() method of the view has the LPCREATESTRUCT lpCreateStruct parameter. One of the members of this structure contains the pointer to the CCreateContext:
 
CCreateContext* pContext =
(CCreateContext*)lpCreateStruct->lpCreateParams;
The source code for this section was taken from our SplitView sample application in <stingray-installdir>\Samples\Toolkit\MFC\DockingViews\DockTabs\SpltView.cpp.
To dock a view
Have your CView send a WM_SYSCOMMANDEX message to its current parent frame window. For example, the following code notifies the frame that the view is to be docked to the right.
 
using namespace nsSysCommandEx;
ScxInfo si(GetParentFrame()->m_hWnd);
si.m_dw[0]=SCXID_DOCKRIGHT;
GetParentFrame()->SendMessage(WM_SYSCOMMANDEX,
SCX_NEWFRAME,(LPARAM)si);
For a list of SCXID parameters, see “WM_SYSCOMMANDEX.”
To float a view as an MDI child
From your CView, send a WM_SYSCOMMANDEX message to its current parent frame window. For example:
 
using namespace nsSysCommandEx;
ScxInfo si(GetParentFrame()->m_hWnd);
si.m_dw[0]=SCXID_MDICHILD;
GetParentFrame()->SendMessage(WM_SYSCOMMANDEX,
SCX_NEWFRAME,(LPARAM)si);
For a list of SCXID parameters, see “WM_SYSCOMMANDEX.”
To obtain a pointer to the view
Within the context of your application’s main frame object (SECMDIFrameWnd-derived), call the SECMDIFrameWnd::GetActiveFrame() and CFrameWnd::GetActiveView() methods. For example:
 
// Retrieve a pointer to the currently active view,
// regardless of whether it is inside an MDI child,
// docked frame, or floating frame.
CFrameWnd* pActiveFrame=GetActiveFrame();
if(pActiveFrame)
CView* pActiveView=
pActiveFrame->GetActiveView();
CMDIFrameWnd::MDIGetActive() does not return the appropriate value for a docked view.
To control the initial size and position of a docking view as it is docked
1. Derive a class from SECMultiDockTemplate.
2. Override SECMultiDocTemplate::ToggleDocking(CFrameWnd* pFrame).
3. In the override, issue a call to the SECMultiDockTemplate::Dock() method instead of invoking the base class. Because this method is overloaded, you need to call the overload that accepts the SECDockPos() and SECDockSize() parameters. For example:
 
void CMyMultiDocTemplate::ToggleDocking(CFrameWnd* pFrame)
{
BOOL bDocked = IsDocked(pFrame);
 
if (bDocked)
// No change here
Undock(pFrame);
else
{
// IsToCustomDock is some function you
// write to determine if special
// handling needed...
if(IsToCustomDock(pFrame))
{
 
// Establish your custom docking config
// dockbar row 3, col 2
SECDockPos pos(3,2);
// 50% width, 100 height
SECDockSize size(0.50f,100);
// or whatever…
UINT nDockbarID=AFX_IDW_DOCKBAR_RIGHT;
 
// Call the overload
Dock(pFrame,nDockbarID,&pos,&size);
}
else // old way
Dock(pFrame);
}
}