Создать несколько CDockablePanes на CDialog

Я пытаюсь сделать то же самое, что и статья, описанная здесь: " C++ MFC Feature Pack -> Создание нескольких CDockablePanes на 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 как дочернее окно в моем диалоговом окне, а затем добавить дочерний CDockablePane в этот CFrameWndEx.

По сути, у меня есть диалоговое окно MFCA с некоторыми элементами управления, и в этом диалоговом окне A мне нужны отрывные вкладки XYZ, и мне нужно добавить несколько элементов управления в каждую отрывную вкладку XYZ. Таким образом, это означает, что каждая отрывная вкладка XYZ на самом деле является одним дочерним диалогом B. Так что это приходит к тому, что я пытаюсь использовать CDockablePanes (на самом деле CPaneDialog) в диалоге A.

1 ответ

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

Другие вопросы по тегам