2016-08-16 66 views
1

我想作爲本文介紹在這裏做完全一樣的: 「C++ MFC Feature Pack --> Create multiple CDockablePanes onto an CDialog創建多個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作爲子窗口,然後添加CFrameWndEx中的子CDockablePane。

基本上我有一個MFC dialogA和一些控件,並且在這個對話框中我需要一些可撕開的tabsXYZ,並且我需要在每個tear-off tabsXYZ中添加一些控件。所以這意味着每個可撕掉的選項卡XYZ實際上都是一個子對話框B.所以這就是我嘗試在dialogA中使用CDockablePanes(實際上是CPaneDialog)的地方。

+0

我對此沒有太多經驗,但是您發佈的鏈接看起來像是黑客。那裏沒有「虛擬窗口」。它似乎創建一個'CFrameWndEx'作爲對話框的子窗口。我不認爲這是可取的。你有基於對話框的應用程序嗎?如果是這樣,你是否試圖在主對話框中添加窗格?請注意,您可以創建一個「CFrameWndEx」並向其添加子對話框,或者將子對話框添加到可docable窗格中。您可以跳過文檔/視圖部分。 –

+0

感謝您的回覆巴馬克。這不是黑客,我已經改變了鏈接顯示的方式。並在「編輯」部分下方的頂部添加更多詳情。對於如何在對話框中使用兒童拆解/可停靠對話框,您有任何建議嗎?最好。 – Zeng

+0

你沒有回答我的問題。沒有理由創建一個框架窗口作爲對話框的子窗口,沒有什麼可以獲得的。 'CFrameWndEx'可以完成'CDialog'所能做的一切,等等。您可以將子對話框添加到框架窗口。在其他鏈接中提到的方法對初學者來說似乎更爲方便,但它需要非常糟糕的黑客行爲,導致更多的問題。 –

回答

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

+0

非常感謝Barmak,這是一個非常詳細的答案。我還沒有機會嘗試它,但它看起來可以很好地工作。最好。 – Zeng