VS2010 MFC中制作Visual Studio風格的停靠側欄窗口(CDockablePane里嵌套FormView表單視圖)
1. 在資源窗口里新建一個FormView的Dialog,修改ID為IDD_FORMVIEW。在此Dialog上點擊右鍵添加類,建立一個基類為CFormView的類,這里取名為CMfcFormView。則生成了MfcFormView.h和MfcFormView.cpp文件。
2. 建立一個CDockablePane的派生類,予以容納FormView,建立派生出的CDockablePane類為CSolutionWnd
即利用類向導,添加類名為CSolutionWnd,基類為CDockablePane,生成文件為SolutionWnd.h和SolutionWnd.cpp。
3. 在SolutionWnd.h中添加:
頭文件:#include "MfcFormView.h"
代碼:
protected:
CMfcFormView* m_pformView;
在SolutionWnd.cpp中的構造函數中創建CMfcFormView對象,即添加代碼:
m_pformView = (CMfcFormView*) (RUNTIME_CLASS(CMfcFormView)->CreateObject());
4. 既然創建了CDockablePane,那必然需要改寫OnCreate函數和OnSize函數。因為通過CDockablePane的創建必然會調用OnCreate函數,在OnCreate函數里創建
FormView,在OnSize里面調整FormView的大小,覆蓋整個CDockablePane。
利用類向導在CSolution聲明里添加消息映射函數:
DECLARE_MESSAGE_MAP()
afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
afx_msg void OnSize(UINT nType, int cx, int cy);
在OnCreate函數里創建FormView
int CSolutionWnd::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CDockablePane::OnCreate(lpCreateStruct) == -1)
return -1;
// TODO: 在此添加您專用的創建代碼
RECT rect;
GetClientRect(&rect);
m_pformView->Create(NULL, NULL, WS_CHILD|WS_VISIBLE, rect, this, 123, NULL);
return 0;
}
在CSolution的OnSize函數里調整FormView填充整個DockablePane區域
void CSolutionWnd::OnSize(UINT nType, int cx, int cy)
{
CDockablePane::OnSize(nType, cx, cy);
// TODO: 在此處添加消息處理程序代碼
if (GetSafeHwnd() == NULL)
{
return;
}
if(m_pformView->GetSafeHwnd()!=NULL)
{
CRect rect;
GetClientRect(rect);
m_pformView->SetWindowPos(NULL, rect.left, rect.top, rect.Width(), rect.Height(), SWP_NOACTIVATE | SWP_NOZORDER);
}
}
4. 在MainFrm.h里添加頭文件:#include "SolutionWnd.h",添加m_wndSolution變量(類型為CSolutionWnd)
在MainFrm.cpp里的CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)函數里找到代碼:
m_wndProperties.EnableDocking(CBRS_ALIGN_ANY);
DockPane(&m_wndProperties);
在其后添加:
m_wndSolution.EnableDocking(CBRS_ALIGN_ANY);
m_wndSolution.AttachToTabWnd(&m_wndProperties, DM_SHOW, TRUE, &pTabbedBar);
在MainFrm.cpp里的CMainFrame::CreateDockingWindows()中添加代碼:
CString strSolutionWnd;
bNameValid = strSolutionWnd.LoadString(IDS_SOLUTION_WND);
ASSERT(bNameValid);
if(!m_wndSolution.Create(strSolutionWnd,this,CRect(0,0,200,200),TRUE,1234,WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS
| WS_CLIPCHILDREN | CBRS_RIGHT | CBRS_FLOAT_MULTI))
{
TRACE0("未能創建“解決方案窗口\n");
return FALSE;
}
5. 利用類向導在CMfcFormView里添加消息映射函數OnCreate以及改寫虛函數Create:
afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
virtual BOOL Create(LPCTSTR lpszClassName, LPCTSTR lpszWindowName, DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID, CCreateContext* pContext = NULL);
// CMfcFormView 消息處理程序
int CMfcFormView::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CFormView::OnCreate(lpCreateStruct) == -1)
return -1;
// TODO: 在此添加您專用的創建代碼
return 0;
}
BOOL CMfcFormView::Create(LPCTSTR lpszClassName, LPCTSTR lpszWindowName, DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID, CCreateContext* pContext)
{
// TODO: 在此添加專用代碼和/或調用基類
return CFormView::Create(lpszClassName, lpszWindowName, dwStyle, rect, pParentWnd, nID, pContext);
}
Bingo~
注意幾點:
1. FormView的Create函數是protected類型的,通過改寫FormView::Create函數為Public類型,才能調用到FormView::Create函數。盡管我們在Create函數里什么也沒有做,但是如果不重寫Create函數的話,就會出現編譯錯誤。
2. 報錯:error C2065: “IDD_FORMVIEW”: 未聲明的標識符
解決辦法:在MfcFormView.h中添加頭文件:#include "Resource.h"
3. 編譯通過了,但運行出錯。通過調試發現
每次運行到:
BOOL CFormView::Create(LPCTSTR /*lpszClassName*/, LPCTSTR /*lpszWindowName*/,
DWORD dwRequestedStyle, const RECT& rect, CWnd* pParentWnd, UINT nID,
CCreateContext* pContext)
{
ASSERT(pParentWnd != NULL);
ASSERT(m_lpszTemplateName != NULL);
m_pCreateContext = pContext; // save state for later OnCreate
#ifdef _DEBUG
// dialog template must exist and be invisible with WS_CHILD set <——請注意此處
if (!_AfxCheckDialogTemplate(m_lpszTemplateName, TRUE))
{
ASSERT(FALSE); // invalid dialog template name
PostNcDestroy(); // cleanup if Create fails too soon
return FALSE;
}
#endif //_DEBUG
中的ASSERT時就報錯。
解決辦法:檢查Dialog的屬性:Visible屬性應設置為FALSE
Style屬性應設置為Child
SystemMenu和TitleBar屬性最好都設為False
因為 根據上面代碼的要求是:對話框模板必須存在,屬性要設置成不可見和子窗口風格。