在CDialog上创建多个CDockablePanes

时间:2016-08-16 21:07:54

标签: mfc cdialog dockable

我正在尝试完全按照文章中描述的那样做: “C++ MFC Feature Pack --> Create multiple CDockablePanes onto an CDialog

我遵循他的程序,现在可以取消停靠并移动CDockablePane,但在停靠时会遇到同样的崩溃。在他自己的回答中,他说他自己创建了虚拟符号,因此MFC跳过了创建和对GetTopLevelFrame()的调用。这就是我困惑的地方,我该如何准确地创建虚拟符号?

我的第二个问题是如何在CMyFrame和CDialog之间交换数据?

提出问题并回答问题的人似乎多年来一直处于非活动状态且无法访问。有人可以帮忙或有任何想法吗?

谢谢,

编辑:

我打破了程序并完全按照其他作者的描述追溯。上面提到的虚拟窗口实际上是afxdragframeimpl.cpp:

void CMFCDragFrameImpl::MoveDragFrame(BOOL bForceMove)

它创建的地方:

m_pWndDummy = new CDummyDockablePane;

并致电:

m_pWndDummy->CreateEx(0, _T(""), AFXGetTopLevelFrame(m_pDraggedWnd), CRect(0, 0, 0, 0), FALSE, AFX_DUMMY_WND_ID, WS_CHILD);

是的,我正在尝试在对话框中创建一个CFrameWndEx作为子窗口,然后在CFrameWndEx中添加子CDockablePane。

基本上我有一个带有一些控件的MFC对话框,在这个对话框中我需要一些撕下标签XYZ,我需要在每个撕下标签XYZ中添加一些控件。所以这意味着每个撕下标签XYZ实际上是一个子对话框B.所以这就到了我尝试在dialogA中使用CDockablePanes(实际上是CPaneDialog)的地方。

1 个答案:

答案 0 :(得分:0)

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();
    ...
}

我不推荐上面的代码,其中框架窗口放在对话框中,因为CFrameWndEx做了各种奇怪的事情,很容易打破这段代码。令人惊讶的是,它在VS2015上工作正常,我无法复制任何崩溃。但窗口的行为仍然很奇怪。

最好制作一个新的框架窗口,并在框架中放置一个子对话框。例如:

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()
};

按如下方式打开窗口:

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);
}

您还可以创建子对话框并将其放在停靠窗格中。例如:

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;
    }
    ...
};

另请注意,如果您的主窗口也是CFrameWndEx,那么您可以在InitInstance中进行以下调用:

SetRegistryKey(_T("MyCompany\\MyApp"));
SetRegistryBase(_T("MainFrame"));

当您打开新的框架窗口时,必须使用

更改注册表基础
SetRegistryBase(_T("CMyFrame"));

当您退出SetRegistryBase(_T("MainFrame"))

时,请将其更改回CMyFrame