1

我正在尝试与此处描述的文章完全相同:“ C++ MFC Feature Pack --> Create multiple CDockablePanes to an CDialog

我按照他的程序进行操作,现在可以取消停靠并移动 CDockablePane,但在将其停靠回来时也会发生同样的崩溃。在他自己的回答中,他说他自己创建了 dummywnd,因此 MFC 跳过了创建和对 GetTopLevelFrame() 的调用。这就是我感到困惑的地方,我该如何准确地创建 dummywnd?

我的第二个问题是如何在 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 对话框 A,在这个对话框 A 中我需要一些可撕下的标签 XYZ,并且我需要在每个可撕下的标签 XYZ 中添加一些控件。所以这意味着每个可撕下的 tabsXYZ 实际上是一个子 dialogB。所以这就是我尝试在dialogA中使用CDockablePanes(实际上是CPaneDialog)的地方。

4

1 回答 1

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

于 2016-08-18T02:46:15.597 回答