Reputation: 11
I'm trying to do exactly the same as the article describes here: "C++ MFC Feature Pack --> Create multiple CDockablePanes onto an CDialog"
I followed his procedure and now am able to undock and move the CDockablePane, but get the same crash when dock it back. In his own answer, he said he created the dummywnd by himself so MFC skipped the creation and the call to GetTopLevelFrame(). And this is where I got confused, how do I create the dummywnd exactly?
My second question is how do I exchange data between the CMyFrame and CDialog?
The person who asked and answered the question seems to be inactive for years and unreachable. Could anyone please help or have any ideas?
Thanks,
Edit:
I break the program and traced back exactly as the other author described. The dummy window mentioned above is actually in afxdragframeimpl.cpp:
void CMFCDragFrameImpl::MoveDragFrame(BOOL bForceMove)
where it creates:
m_pWndDummy = new CDummyDockablePane;
and calls:
m_pWndDummy->CreateEx(0, _T(""), AFXGetTopLevelFrame(m_pDraggedWnd), CRect(0, 0, 0, 0), FALSE, AFX_DUMMY_WND_ID, WS_CHILD);
And yes, I'm trying to create a CFrameWndEx as child window in my dialog, and then add child CDockablePane in that CFrameWndEx.
Basically I have a MFC dialogA with some controls, and within this dialogA I need some tear-off tabsXYZ, and I need to add some controls within each of the tear-off tabsXYZ. So this means each tear-off tabsXYZ is actually one child dialogB. So this comes to where I try to use CDockablePanes (CPaneDialog actually) within the dialogA.
Upvotes: 1
Views: 1233
Reputation: 31599
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();
...
}
I don't recommend the above code where frame window is placed in a dialog, because CFrameWndEx
does all sorts of strange things, it's easy to break this code. Surprisingly, it works fine on VS2015, I couldn't duplicate any crash. But the window's behavior is still odd.
It's better to make a new frame window, and place a child dialog in frame. For example:
class CMyFrame : public CFrameWndEx
{
CDialog m_dialog;
int OnCreate(LPCREATESTRUCT lpCreateStruct)
{
CFrameWndEx::OnCreate(lpCreateStruct);
m_dialog.Create(IDD_CHILD1, this);
CRect rc;
m_dialog.GetClientRect(&rc);
m_dialog.SetWindowPos(NULL, 0, 0, rc.right, rc.bottom, SWP_SHOWWINDOW);
return 1;
}
DECLARE_MESSAGE_MAP()
};
You open the window as follows:
void CMyMainFrame::OnButton()
{
CMyFrame *frame = new CMyFrame;
frame->LoadFrame(IDR_MAINFRAME,
WS_POPUPWINDOW | WS_THICKFRAME | WS_CAPTION | WS_SYSMENU, this);
frame->SetMenu(0);
frame->ShowWindow(SW_SHOW);
}
You can also create a child dialog and put that inside a docking pane. For example:
class CMyFrame : public CFrameWndEx
{
CDockablePane m_DockWnd;
CDialog m_dialog;
int OnCreate(LPCREATESTRUCT lpCreateStruct)
{
CFrameWndEx::OnCreate(lpCreateStruct);
CMFCVisualManager::SetDefaultManager(RUNTIME_CLASS(CMFCVisualManagerWindows));
CDockingManager::SetDockingMode(DT_SMART);
EnableAutoHidePanes(CBRS_ALIGN_ANY);
m_DockWnd.Create(_T("Test"), this, CRect(0, 0, 200, 200), TRUE, 0,
WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN |
CBRS_LEFT | CBRS_FLOAT_MULTI);
m_dialog.Create(IDD_PAGE1, &m_DockWnd);
CRect rdialog;
m_dialog.GetClientRect(&rdialog);
m_dialog.SetWindowPos(NULL, 0, 0, rdialog.Width(), rdialog.Height(), SWP_SHOWWINDOW);
m_DockWnd.SetMinSize(rdialog.Size());
m_DockWnd.EnableDocking(CBRS_ALIGN_ANY);
EnableDocking(CBRS_ALIGN_ANY);
DockPane(&m_DockWnd);
return 0;
}
...
};
Also remember, if your main window is also CFrameWndEx
then you make something like the following calls in InitInstance
:
SetRegistryKey(_T("MyCompany\\MyApp"));
SetRegistryBase(_T("MainFrame"));
When you open a new frame window you must change the registry base with
SetRegistryBase(_T("CMyFrame"));
Then change it back to SetRegistryBase(_T("MainFrame"))
when you exit CMyFrame
Upvotes: 0