Click here to Skip to main content
15,887,746 members
Articles / Desktop Programming / WTL
Article

WTL Docking Windows

Rate me:
Please Sign up or sign in to vote.
4.89/5 (73 votes)
21 Nov 20077 min read 843.1K   14.1K   215   276
This is an implementation of docking windows for the WTL library

Sample Image - WTLDockingWindows1.png

Introduction.

This is an implementation of docking windows for the WTL library. The following topics describe how to use docking window classes.

Pre-Build Set-Up.

  • Make sure all header files are placed in the appropriate location and compiler can reach it.
  • Add DockImpl.cpp to the project. Probably the best way to do it is to add #include<DockImpl.cpp> to the stdafx.cpp.
  • Docking Windows use STL so it's requires to enable exception handling (/GX or /EH compiler options) and remove _ATL_MIN_CRT from the list the preprocessor defines in release configuration. If you use standard HP's STL you can leave default project setting intact, but I don't think it is a good idea.
  • If you use boost library define USE_BOOST.
  • I use some private message in range WM_USER to WM_USER + 2
    WMDF_FIRST = WM_USER
    WMDF_LAST = WM_USER + 2
    So if you define your own private messages please use WMDF_LAST+1 or if it is impossible redefine WMDF_FIRST.

Add to Main Frame Support for Docking Window Features

  • Create a new project with ATL/WTL AppWizard (MDI or SDI as you like)
  • Add #include <DockingFrame.h> to CMainFrame header.
  • Change the base of your CMainFrame class to dockwins::CDockingFrameImpl<CMainFrame> for SDI applications or to dockwins::CMDIDockingFrameImpl<CMainFrame> for MDI applications. All references to previous base class should be replaced by new one.
  • Add to the OnCreate method of your CMainFrame class InitializeDockingFrame(); it's the best place to change windows behavior of docking window. By default it is depend on system setting (Show window contents while dragging) if you for some reason need to change it you should use the following flags:
    CDockingBarStyle::sUseSysSettings — depend on system setting, default.
    CDockingBarStyle::sIgnoreSysSettings | CDockingBarStyle::sFullDrag — full drag
    CDockingBarStyle::sIgnoreSysSettings | CDockingBarStyle::sGhostDrag — ghost drag.
    If you use auto-hiding features you also can use the following flags:
    CDockingBarStyle::sAnimation — animate auto-hiding windows.
    CDockingBarStyle::sNoAnimation — do not animate auto-hiding windows.

Implement a Docking Window

  • Add #include <ExtDockingWindow.h> to header file of your docking window.
  • Create new class CSampleDockingWindow for example. Derive it from dockwins::CTitleDockingWindowImpl.
  • Add message map and DECLARE_WND_CLASS macro The CSampleDockingWindow class should look like this:
    C++
    class CSampleDockingWindow :
             public dockwins::CTitleDockingWindowImpl< SampleDockingWindow,
                    CWindow, dockwins::COutlookLikeTitleDockingWindowTraits >
    {
            typedef CSampleDockingWindow    thisClass;
            typedef dockwins::CTitleDockingWindowImpl<CSAMPLEDOCKINGWINDOW,
             CWINDOW,
             dockwins::COutlookLikeTitleDockingWindowTraits>  baseClass;
    public:
            DECLARE_WND_CLASS(_T("CSampleDockingWindow"))
            BEGIN_MSG_MAP(thisClass)
                    CHAIN_MSG_MAP(baseClass)
            END_MSG_MAP()
    };
  • Instantiate an object of the CSampleDockingWindow class as a member of the CMainFrame
  • In the CMainFrame::OnCreate(...) method, call the Create(...) method of the instantiated docking window class.
    C++
    LRESULT OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, 
                     BOOL& /*bHandled*/)
    {
            ...
            InitializeDockingFrame();
            ...
            CRect rcBar(0,0,100,100);
            m_sampleDockWnd.Create(m_hWnd,rcBar,_T("Sample docking window"));
            ...
    }

    Do not use empty rect even if you dock the window. When window start dragging it use previously stored floating rect size.

Add to Generic Window Support for Docking Window Features

To implement a window with docking window features, derive a class from dockwins::CDockingSiteImpl. In derived class chain default message map to the base class.

C++
class CDockSiteSampleWnd : public dockwins::CDockingSiteImpl < 
        CDockSiteSampleWnd >
{
        typedef dockwins::CDockingSiteImpl < CDockSiteSampleWnd > baseClass;
public:
        DECLARE_WND_CLASS(_T("CDockSiteSampleWnd"))
        BEGIN_MSG_MAP(CDockSiteSampleWnd)
                CHAIN_MSG_MAP(baseClass)
        END_MSG_MAP()
};

Add Support for Tabbed Docking Window

  • The tabbed docking window depend on Daniel Bowen's The Codeproject article "Custom Tab Controls,Tabbed Frame and Tabbed MDI", Please download the source code for this article.
  • Change the base class of your docking window from dockwins::CTitleDockingWindowImpl to dockwins::CBoxedDockingWindowImpl.
  • Use the following classes as traits for the dockwins::CBoxedDockingWindowImpl: COutlookLikeBoxedDockingWindowTraits, COutlookLikeExBoxedDockingWindowTraits or CVC6LikeBoxedDockingWindowTraits.
  • To add tabbed docking features support to the previous CSampleDockingWindow class, the code should look like this:
    C++
    class CSampleTabDockingWindow :
             public dockwins::CBoxedDockingWindowImpl< SampleDockingWindow,
                    CWindow, dockwins::COutlookLikeBoxedDockingWindowTraits >
    {
            typedef CSampleTabDockingWindow    thisClass;
            typedef dockwins::CBoxedDockingWindowImpl<CSAMPLEDOCKINGWINDOW,
             CWINDOW,
             dockwins::COutlookLikeBoxedDockingWindowTraits>  baseClass;
    public:
            DECLARE_WND_CLASS(_T("CSampleTabDockingWindow"))
            BEGIN_MSG_MAP(thisClass)
                    CHAIN_MSG_MAP(baseClass)
            END_MSG_MAP()
    };

Add Support for Auto-Hiding Features

To add auto-hiding features to your project just include a DWAutoHide.h header before any other docking windows headers.

Dock a Docking Window

Call the DockWindow methods from your frame window class.

C++
template<class T>
bool DockWindow(T& dockWnd,CDockingSide side,
                unsigned long nBar,float fPctPos,
                unsigned long nWidth, unsigned long nHeight);
dockWnd
Docking window.
side
Sides of the frame window to dock to
CDockingSide::sSingle force docking window to occupy the fulll width of the docking bar, combine this style with one of the following:
CDockingSide::sRight Dock to the right side of the frame window.
CDockingSide::sLeft Dock to the left side of the frame window.
CDockingSide::sTop Dock to the top side of the frame window.
CDockingSide::sBottom Dock to the bottom side of the frame window.
nBar
Index of dockbar to dock to, it's zero-based.
fPctPos
The percent of the dock bar's width that the docking window should use as top point.
nWidth
The requested width (in pixels) of the docking window. If the docking window is vertical, this parameter actually represents the control bar height.
nHeight
The requested height (in pixels) of the docking window. If the docking window is vertical, this parameter actually represents the control bar width.

Dock One Tabbed Docking Window to Another

Call the DockTo method of the tabbed docking window.

C++
bool DockTo(HWND hWnd,int index=0);
hWnd
Tabbed docking window to dock to.
index
Zero-based index.

Float a Docking Window that is Docked

Call the Float methods from your docking window class.

bool Float() - restore previous floating position
bool Float(LPCRECT pRc, <br />UINT flags=SWP_SHOWWINDOW | SWP_NOACTIVATE,<br />HWND hWndInsertAfter=HWND_TOP) - float docking window and move to a specified location.

Pin-up Docking Window

Call the one of the PinUp methods of the tabbed docking window.

C++
bool PinUp(const CDockingSide& side);
bool PinUp(const CDockingSide& side, unsigned long width, 
    bool bVisualize=false);
side
Sides of the frame window to pin-up to:
CDockingSide::sRight Pin-up to the right side of the frame window.
CDockingSide::sLeft Pin-up to the left side of the frame window.
CDockingSide::sTop Pin-up to the top side of the frame window.
CDockingSide::sBottom Pin-up to the bottom side of the frame window.
width
The requested width (in pixels) of the docking window.
bVisualize
Specifies the show state of the docking window after pinning.

Unpin Pinned Docking Window

Call Hide then Show methods of the pinned window to emulate the pin button press,
or call Float method to float a pinned docking window,
or call Hide method then call any functions that set docking window position.

Receive Notifications when the Docked State of a Docking Window Changes

Override the following member functions of your docking window class

void OnDocked(HDOCKBAR hBar,bool bHorizontal)
void OnUndocked(HDOCKBAR hBar)
hBar
Handle to the dockbar to docking to.
bHorizontal
Docking window orientation.

Hide/Show a Docking Window

To hide/show a docking window simply call Hide()/ Show() or Togle() methods of the CTitleDockingWindowImpl class.

Specify Minimum Docking Window Size

You can specify minimum docking window size by overriding GetMinMaxInfo method of your docking window, like this:

C++
void GetMinMaxInfo(LPMINMAXINFO pMinMaxInfo) const
{
   pMinMaxInfo->ptMinTrackSize.y=100;
   pMinMaxInfo->ptMinTrackSize.x=100;
}

Preserve Docking Window Position

You can use following member functions of the CDockingWindowBaseImpl class:

bool GetDockingWindowPlacement(DFDOCKPOSEX* pHdr) const
bool SetDockingWindowPlacement(DFDOCKPOSEX* pHdr)

Replace Splitter Bar

If you do not like splitter bar you can make your own. If you just want to change it's appearance probably the best way to derive it from CSimpleSplitterBar. And override Draw(),DrawGhostBar() etc. Then define your traits

C++
typedef CDockingFrameTraitsT <CMySplitterBar,
                WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN | WS_CLIPSIBLINGS,
                WS_EX_APPWINDOW | WS_EX_WINDOWEDGE>  CMyDockingFrameTraits;
and apply it to base class of CMainFrame.

Make Custom Caption

Create a new caption class. You can derive it from CCaptionBase or from other available Caption classes. Then define DockingWindowTraits

C++
typedef CDockingWindowTraits<CMyCaption,
                       WS_OVERLAPPEDWINDOW | WS_POPUP | WS_VISIBLE |
                       WS_CLIPCHILDREN | WS_CLIPSIBLINGS,
                       WS_EX_TOOLWINDOW> CMyTitleDockingWindowTraits;

and apply it to CTitleDockingWindowImpl.

Docking Window Classes

Docking Windows Frame Classes

CDockingFrameImplBase[DockingFrame.h] — this class provides basic docking window features.
CDockingFrameImpl [DockingFrame.h] — base class for a single document interface (SDI) frame window.
CMDIDockingFrameImpl [DockingFrame.h] — base class for a multiple document interface (MDI) frame window.
CDockingSiteImpl [DockingFrame.h] — base class for a generic window with docking window features.
CDockingFrameTraitsT [DockMisc.h] — traits of docking frame it's derived from CWinTraits class and add TSplitterBar parameter.

Docking Windows Classes

CDockingWindowBaseImpl [DockingWindow.h] — base class for docking windows. The CDockingWindowBaseImpl class derives from CWindowImpl and has the same parameters except TWinTraits. Instead, it is uses CDockingWindowTraits.
CTitleDockingWindowImpl [DockingWindow.h] — titled docking window.
CBoxedDockingWindowImpl [DockingBox.h] — titled docking window which support tabbed docking.
CDockingWindowTraits [DockingWindow.h] — traits of docking window it's derived from CWinTraits class and add TCaption parameter. If you need to customize the docking window caption, make new caption class and use CDockingWindowTraits with new class as TCaption parameter.

Docking Windows Captions Classes

CCaptionBase[DockingWindow.h] — base class for other caption class
COutlookLikeExCaption and COutlookLikeCaption [ExtDockingWindow.h] — Microsoft Outlook™ likes caption.
COutlookLikeCaption — always horizontal caption.
COutlookLikeExCaption — orientation of the caption depends on docking position.
CVC6LikeCaption [ExtDockingWindow.h] — Microsoft Visual C++ 6™ IDE like caption.

Docking Windows Traits Classes

COutlookLikeTitleDockingWindowTraits [ExtDockingWindow.h] traits for COutlookLikeCaption, use this class with CTitleDockingWindowImpl
COutlookLikeExTitleDockingWindowTraits [ExtDockingWindow.h] traits for COutlookLikeExCaption, use this class with CTitleDockingWindowImpl
CVC6LikeTitleDockingWindowTraits [ExtDockingWindow.h] traits forCVC6LikeCaption, use this class with CTitleDockingWindowImpl
COutlookLikeBoxedDockingWindowTraits [TabDockingBox.h] traits for COutlookLikeCaption, use this class with CBoxedDockingWindowImpl
COutlookLikeExBoxedDockingWindowTraits [TabDockingBox.h] traits for COutlookLikeExCaption, use this class with CBoxedDockingWindowImpl
CVC6LikeBoxedDockingWindowTraits[TabDockingBox.h] traits for CVC6LikeCaption, use this class with CBoxedDockingWindowImpl

Docking Windows Splitter Bar Classes

CSimpleSplitterBar[SimpleSplitterBar.h] - Very simple splitter bar.
CSimpleSplitterBarEx[SimpleSplitterBar.h] - another simple splitter bar.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Software Developer
Ireland Ireland
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
GeneralRe: Compiling under Unicode Pin
Jörgen Sigvardsson14-May-02 9:05
Jörgen Sigvardsson14-May-02 9:05 
GeneralRe: Compiling under Unicode Pin
Rob Caldecott15-May-02 6:55
Rob Caldecott15-May-02 6:55 
GeneralCompile cost Pin
19-Apr-02 22:30
suss19-Apr-02 22:30 
GeneralRe: Compile cost Pin
Xalon14-May-02 23:43
Xalon14-May-02 23:43 
GeneralSuggestions Pin
Rob Caldecott11-Apr-02 22:21
Rob Caldecott11-Apr-02 22:21 
GeneralSuggestion about user-defined messages Pin
Daniel Bowen9-Apr-02 12:45
Daniel Bowen9-Apr-02 12:45 
GeneralRe: Suggestion about user-defined messages Pin
9-Apr-02 19:07
suss9-Apr-02 19:07 
GeneralRe: Suggestion about user-defined messages Pin
Daniel Bowen10-Apr-02 6:40
Daniel Bowen10-Apr-02 6:40 
I realized I left out an important part in my first message Smile | :) . I should have started out "when you're doing base templatized windowing classes ...". I do agree that WM_USER + x is fine as long as you're aware of all the possible messages for a window before hand. When you're making a templatized base class that helps implement a window (ala WTL or ATL), its not always the case that you know all the messages that the window expects (unless no one but you uses the class of course Smile | :) )

This is really just my opinion from my own experience, but when you have a base templatized class for helping implement a window - either to be used as a pure base class, or as one of several "mix-in" classes, there have been occasions when you can unknowingly have conflicting message IDs if you base them off of WM_USER if you're not careful.

Example 1
Let's say that somebody else wants to have a window based off of your dockwins::CTitleDockingWindowImpl<> for a docking pane window, but they also want some other functionality. Let's say this other functionality is wrapped up in a separate Impl style classs, and takes a template parameter for the base (which they give as dockwins::CTitleDockingWindowImpl<>) and the message map is chained to the base.

Well, CTitleDockingWindowImpl derives from CDockingWindowBaseImpl, which uses the message WMDF_NDOCKSTATECHANGED - that really is WM_USER + 1. But let's say this other "Impl" class that uses CTitleDockingWindowImpl also uses a custom WM_USER + 1 message. There's a conflict, and in this case, if the "Impl" style class doesn't say "bHandled = FALSE;" when handling WM_USER+1, then CDockingWindowBaseImpl will never see the message.

Now, whoever it was using both CTitleDockingWindowImpl and the other "Impl" class could have caught this problem by tracing through all the class hierarchy, and seeing what messages are being used. This is what I personally do, but it's easy to let it slip when you're just using someone elses cool templatized windowing class, or you run into a problem (like "hey, the window doesn't dock").

Example 2
Another example is that you're writing a quick Impl style class that is meant to super/subclass a common control (i.e., list view) or window control (i.e., combo box). Well, these guys have special message based off of WM_USER already. See MSDN on WM_APP, and note that the "extended" common control message (i.e., LVM_SETITEM), are in the WM_USER range. If you were to introduce a special message based off of WM_USER that conflicted with one of these, you might introduce a subtle bug that doesn't get caught for a while. Now in this particular case, you can base your special message off of WM_APP and be OK.

Example 3
One last example of why WM_USER based messages are problematic is because of what I've see sometimes when reflecting notifications or commands, and using someone elses class that might not do DEFAULT_REFLECTION_HANDLER(). In ATL/WTL, when notifications are reflected, you are essentially having the parent window send back certain window messages "translated" to the WM_USER range - specifically, the "original" message ID is added to OCM__BASE (which is WM_USER + 0x1c00). Well, if by some chance the window receiving this message is expecting its own private message to have one of these message IDs, bad things can happen (try reflecting notifications to a generic tree view, and you'll see what I mean).


The reason I suggest RegisterWindowMessage is that it helps prevent such scenarios for the user of your templates when you're distributing them to others. It helps "encapsulate" your functionality just a little more.

You can take or leave the suggestion Smile | :) , but there it is.

-Daniel
General2 bugs (one annoying, second rare, but still annoying) Pin
limax23-Mar-02 4:43
limax23-Mar-02 4:43 
GeneralRe: 2 bugs (one annoying, second rare, but still annoying) Pin
25-Mar-02 20:15
suss25-Mar-02 20:15 
GeneralRebar postion bugs and fixes Pin
Rob Caldecott21-Mar-02 4:48
Rob Caldecott21-Mar-02 4:48 
GeneralRe: Rebar postion bugs and fixes Pin
21-Mar-02 20:37
suss21-Mar-02 20:37 
GeneralRe: Rebar postion bugs and fixes Pin
Hydra5-Jul-02 13:17
Hydra5-Jul-02 13:17 
GeneralRe: Rebar postion bugs and fixes Pin
Hydra5-Jul-02 14:41
Hydra5-Jul-02 14:41 
GeneralRe: Rebar postion bugs and fixes Pin
Ralph Shnelvar11-Feb-03 8:59
Ralph Shnelvar11-Feb-03 8:59 
GeneralHandling dialog messages Pin
Rob Caldecott20-Mar-02 23:12
Rob Caldecott20-Mar-02 23:12 
GeneralMinor bug Pin
Rob Caldecott6-Mar-02 9:06
Rob Caldecott6-Mar-02 9:06 
GeneralRe: Minor bug Pin
6-Mar-02 19:09
suss6-Mar-02 19:09 
GeneralTabbed Windows Pin
Marcello4-Mar-02 7:49
Marcello4-Mar-02 7:49 
GeneralRe: Tabbed Windows Pin
Daniel Bowen5-Mar-02 8:35
Daniel Bowen5-Mar-02 8:35 
GeneralRe: Tabbed Windows Pin
Rob Caldecott28-Mar-02 6:47
Rob Caldecott28-Mar-02 6:47 
GeneralTake a look! :) Pin
limax27-Feb-02 7:49
limax27-Feb-02 7:49 
GeneralRe: Take a look! :) Pin
Hydra5-Jul-02 13:38
Hydra5-Jul-02 13:38 
GeneralA small bug in the SDI Sample Pin
PaulW17-Feb-02 2:55
PaulW17-Feb-02 2:55 
GeneralRe: A small bug in the SDI Sample Pin
17-Feb-02 20:25
suss17-Feb-02 20:25 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.