0
votes

I try to create an area onto a CDialog, where I can put some CDockablePanes in. Those shall be perfectly dockable to a fixed dialog content.

The Codejock Dialog Panes Sample is exactly what I want, but realized with the MFC feature pack classes: http://codejock.com/downloads/samples/dockingpane.asp

At the moment I got a class inherited from CFrameWndEx, which is embedded in the CDialog. I also got a working CDockablePane in it. I can undock it and move it, but when I want to dock it the program crashes.

This is because the dockable pane class tries to generate a dummy pane for previewing where the real pane would go. It calls GetTopLevelFrame() which returns NULL. This produces the crash in afxpane.cpp @CreateEx().

Does someone has any help or ideas for me? :(

Greets,


Edit:
Okay, some code:
I wrote a little class inherited from CFrameWndEx (because its constructor is protected):

class CMyFrame: public CFrameWndEx  
{  
    public:  
    DECLARE_MESSAGE_MAP()  
    afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);  
    CDockablePane m_DockWnd; // Will use an own class inherited from CDockablePane later on
};

Now I embedded this class in my CDialog and change its size to the dialogs size:

BOOL CMyDlg::OnInitDialog()  
{      
    CRect wndRect;  
    GetWindowRect(wndRect);    
    m_pFrame = new CMyFrame();  
    m_pFrame->Create(NULL, NULL, WS_CHILD | WS_VISIBLE | WS_BORDER, wndRect, this);  
    m_pFrame->MoveWindow(wndRect);

    CDialog::OnInitDialog();
    ...
}

In the OnCreate() of the CMyFrame class I set up the CDockablePane and dock it:

int CMyFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
    if (CFrameWndEx::OnCreate(lpCreateStruct) == -1)
        return -1;

    CMFCVisualManager::SetDefaultManager(RUNTIME_CLASS(CMFCVisualManagerWindows));

    EnableDocking(CBRS_ALIGN_ANY);
    // DT_SMART creates dummy dockable panes for previewing the possible position of  
    // the currently floating pane, this leads to a crash at call to GetTopLevelFrame()
    CDockingManager::SetDockingMode(DT_SMART);
    EnableAutoHidePanes(CBRS_ALIGN_ANY);

    // m_DockWnd is a CDockablePane
    if (!m_DockWnd.Create(_T("Test"), this, CRect(0, 0, 200, 200), TRUE, IDC_DOCK_WND, 
        WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | CBRS_LEFT | CBRS_FLOAT_MULTI))
    {
    TRACE0("Failed to create Properties window\n");
    return 1; // failed to create
    }

    m_DockWnd.EnableDocking(CBRS_ALIGN_ANY);
    DockPane(&m_DockWnd);

    return 0;
}
2
You should post some code to help describe what you are doing ... are you using a dock pane manager? Also note cleaning up CDockablePane requires some extra hooks to avoid memory leaks.AJG85
Okay, I added some code.slaindevil
DockablePanes were not designed to be used on CDialog.sergiol

2 Answers

2
votes

Okay, I finally got it.

Instead of letting the MFC create the dummywnd, I created it by myself. So the MFC skips the creation and the call to GetTopLevelFrame().

Now the problem was, that the dummywnd member variable was protected and had no public set method. So I inherited a class and built myself a public set method.

0
votes

Another simple method is to set your docking mode to DT_IMMEDIATE if you are in a Dlg implementing Docking Frames. Call CDockingManager::SetDockingMode(DT_IMMEDIATE);

in you CFrameWndEx object's OnCreate (or someplace appropriate).