[cpp] view plaincopyprint?關鍵字:CDockablePane, Visual Studio風格的Gui界面,,CDoackable裡嵌套FormView表單視圖步驟 www.2cto.com 關鍵字:CDockablePane, Visual Studio風格的Gui界面,,CDoackable裡嵌套FormView表單視圖步驟[cpp] view plaincopyprint?轉載注意作者原創:K_Linux_Man 轉載注意作者原創:K_Linux_Man 一直比較喜歡Visual Studio兩側的窗口,可以來回滑動,並且和點擊圖釘,釘住懸浮的窗口。那就嘗試著如何去做出來。 VC++6.0如果要去實現的話,不是不可以,但是得借助第三方的類庫,比如說,ToolKit,但是非常的麻煩。。。 Visual Studio裡面的新建Demo就可以實現這一功能,何樂而不為呢!!! 那停靠窗口裡面用什麼填充呢? 樹形控件??新建的Demo裡有了。更直觀一點的話,還是用FormView吧。。。好的。。。開始 要不先來個最終的效果圖..... 自己添加的解決方案停靠窗口,裡面嵌套FormView視圖窗口.而文件視圖,類視圖,還有屬性,Demo裡面默認生成的。只有解決方案那個是自己添加的。 新建兩個文件,SolutionWnd.h SolutionWnd.cpp 在資源窗口裡新建一個FormView的Dialog,修改ID為IDD_FORMVIEW,建立一個與FormView相關聯的的類, 利用類向導,添加一個名為CMfcFormView,選擇基類為CFormView. 生成在SolutionWnd.h和SolutionWnd.cpp文件裡。 SoulutionWnd.h [cpp] #pragma once #include "Resource.h" // CMfcFormView 窗體視圖 class CMfcFormView : public CFormView { <SPAN style="COLOR: rgb(255,0,0)">DECLARE_DYNCREATE</SPAN>(CMfcFormView)//<SPAN style="BACKGROUND-COLOR: rgb(255,0,0)">具有動態創建對象的能力</SPAN> public: CMfcFormView(): CFormView(CMfcFormView::IDD) {}// 動態創建所使用的受保護的構造函數 ~CMfcFormView() {} public: public: enum { IDD = IDD_FORMVIEW }; #ifdef _DEBUG virtual void AssertValid() const; #ifndef _WIN32_WCE virtual void Dump(CDumpContext& dc) const; #endif #endif protected: virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持 DECLARE_MESSAGE_MAP() #pragma once #include "Resource.h" // CMfcFormView 窗體視圖 class CMfcFormView : public CFormView { DECLARE_DYNCREATE(CMfcFormView)//具有動態創建對象的能力 public: CMfcFormView(): CFormView(CMfcFormView::IDD) {}// 動態創建所使用的受保護的構造函數 ~CMfcFormView() {} public: public: enum { IDD = IDD_FORMVIEW }; #ifdef _DEBUG virtual void AssertValid() const; #ifndef _WIN32_WCE virtual void Dump(CDumpContext& dc) const; #endif #endif protected: virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持 DECLARE_MESSAGE_MAP()[cpp] view plaincopyprint?}; }; SolutionWnd.cpp [cpp] #include "stdafx.h" #include "SolutionWnd.h" // CMfcFormView <SPAN style="COLOR: #ff0000">IMPLEMENT_DYNCREATE</SPAN>(CMfcFormView, CFormView) void CMfcFormView::DoDataExchange(CDataExchange* pDX) { CFormView::DoDataExchange(pDX); } BEGIN_MESSAGE_MAP(CMfcFormView, CFormView) END_MESSAGE_MAP() // CMfcFormView 診斷 #ifdef _DEBUG void CMfcFormView::AssertValid() const { CFormView::AssertValid(); } #ifndef _WIN32_WCE void CMfcFormView::Dump(CDumpContext& dc) const { CFormView::Dump(dc); } #endif #endif //_DEBUG // CMfcFormView 消息處理程序 #include "stdafx.h" #include "SolutionWnd.h" // CMfcFormView IMPLEMENT_DYNCREATE(CMfcFormView, CFormView) void CMfcFormView::DoDataExchange(CDataExchange* pDX) { CFormView::DoDataExchange(pDX); } BEGIN_MESSAGE_MAP(CMfcFormView, CFormView) END_MESSAGE_MAP() // CMfcFormView 診斷 #ifdef _DEBUG void CMfcFormView::AssertValid() const { CFormView::AssertValid(); } #ifndef _WIN32_WCE void CMfcFormView::Dump(CDumpContext& dc) const { CFormView::Dump(dc); } #endif #endif //_DEBUG // CMfcFormView 消息處理程序 至此我們已經把FormView派生出的CMfcFormView類建好了。 我們需要建立一個CDockablePane的派生類,予以容納FormView,建立派生出的CDockablePane類為CSolutionWnd 利用類向導,添加名為CSolutionWnd,基類為CDockablePane...生成文件SolutionWnd.h和SolutionWnd.cpp SolutionWnd.h裡又添加了如下代碼 [cpp] class CSolutionWnd : public CDockablePane { DECLARE_DYNAMIC(CSolutionWnd) //構造函數 public: CSolutionWnd(); //析構函數 ~CSolutionWnd(); //特性 public: protected: CMfcFormView* m_pformView; public: DECLARE_MESSAGE_MAP() }; class CSolutionWnd : public CDockablePane { DECLARE_DYNAMIC(CSolutionWnd) //構造函數 public: CSolutionWnd(); //析構函數 ~CSolutionWnd(); //特性 public: protected: CMfcFormView* m_pformView; public: DECLARE_MESSAGE_MAP() }; SolutionWnd.cpp 新添加的代碼 [cpp] BEGIN_MESSAGE_MAP(CSolutionWnd, CDockablePane) END_MESSAGE_MAP() IMPLEMENT_DYNAMIC(CSolutionWnd, CDockablePane) CSolutionWnd::CSolutionWnd() { m_pformView = (CMfcFormView*) (RUNTIME_CLASS(CMfcFormView)->CreateObject()); } CSolutionWnd::~CSolutionWnd() { } BEGIN_MESSAGE_MAP(CSolutionWnd, CDockablePane) END_MESSAGE_MAP() IMPLEMENT_DYNAMIC(CSolutionWnd, CDockablePane) CSolutionWnd::CSolutionWnd() { m_pformView = (CMfcFormView*) (RUNTIME_CLASS(CMfcFormView)->CreateObject()); } CSolutionWnd::~CSolutionWnd() { } 接著 1.在MainFrm.cpp裡添加m_wndSolution變量,類型為CSolutionWnd 2.在MainFrm.cpp裡的CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)函數裡添加代碼 [cpp] // 創建停靠窗口 if (!CreateDockingWindows()) _ { TRACE0("未能創建停靠窗口\n"); return -1; } m_wndFileView.EnableDocking(CBRS_ALIGN_ANY); m_wndClassView.EnableDocking(CBRS_ALIGN_ANY); DockPane(&m_wndFileView); | CDockablePane* pTabbedBar = NULL; | m_wndClassView.AttachToTabWnd(&m_wndFileView, DM_SHOW, TRUE, &pTabbedBar); m_wndOutput.EnableDocking(CBRS_ALIGN_ANY); DockPane(&m_wndOutput); m_wndProperties.EnableDocking(CBRS_ALIGN_ANY); DockPane(&m_wndProperties);_ <SPAN style="COLOR: #ff0000">m_wndSolution.EnableDocking(CBRS_ALIGN_ANY); m_wndSolution.AttachToTabWnd(&m_wndProperties, DM_SHOW, TRUE, &pTabbedBar);</SPAN><PRE class=cpp name="code"> // 紅色為自己添加</PRE><P></P> <PRE></PRE> <BR> <BR> <P></P> <P>3.在MainFrm.cpp裡的CMainFrame::CreateDockingWindows()中添加代碼</P> <P></P> <PRE class=cpp name="code"><SPAN style="COLOR: #ff0000">//創建解決方案窗口 CString strSolutionWnd; bNameValid = strSolutionWnd.LoadString(IDS_SOLUTION_WND); ASSERT(bNameValid); if(!</SPAN><SPAN style="COLOR: #3333ff">m_wndSolution.Create</SPAN><SPAN style="COLOR: #ff0000">(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; }</SPAN></PRE>既然我們要創建CDockablePane那必然需要改寫OnCreate函數和OnSize函數,原因是,通過CDockablePane的創建必然會調用OnCreate函數,在OnCreate函數裡創建FormView,在OnSize裡面調整FormView的大小,覆蓋整個CDockablePane。 <P></P> <P>利用類向導在CSolution聲明裡添加消息映射函數</P> <P></P> <PRE class=cpp name="code">public: DECLARE_MESSAGE_MAP() afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct); afx_msg void OnSize(UINT nType, int cx, int cy);</PRE><BR> <PRE class=cpp name="code">int CSolutionWnd::OnCreate(LPCREATESTRUCT lpCreateStruct) { if (CDockablePane::OnCreate(lpCreateStruct) == -1) return -1; // TODO: 在此添加您專用的創建代碼 return 0; } void CSolutionWnd::OnSize(UINT nType, int cx, int cy) { CDockablePane::OnSize(nType, cx, cy); // TODO: 在此處添加消息處理程序代碼 } </PRE><BR> 利用類向導在CMfcFormView裡添加消息映射函數OnCreate以及改寫虛函數Create <P></P> <P></P> <PRE class=cpp name="code">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);</PRE><BR> <PRE class=cpp name="code">// 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); }</PRE> <P></P> <P>在CSolution.h裡聲明CMfcFormView*類型的指針變量 </P> <P></P> <PRE class=cpp name="code">protected: CMfcFormView* m_pformView;</PRE><BR> 在CSolution的構造函數裡創建CMfcFormView對象 <P></P> <P></P> <PRE class=cpp name="code">CSolutionWnd::CSolutionWnd() { m_pformView = (CMfcFormView*) (RUNTIME_CLASS(CMfcFormView)->CreateObject()); } </PRE><BR> 在CSolution的OnCreate函數裡創建FormView <P></P> <P></P> <PRE class=cpp name="code">int CSolutionWnd::OnCreate(LPCREATESTRUCT lpCreateStruct) { if (CDockablePane::OnCreate(lpCreateStruct) == -1) return -1; // TODO: 在此添加您專用的創建代碼 <SPAN style="COLOR: #ff0000">RECT rect; GetClientRect(&rect); m_pformView->Create(NULL, NULL, WS_CHILD|WS_VISIBLE, rect, this, 123, NULL);</SPAN> return 0; }</PRE><BR> 在CSolution的OnSize函數裡調整FormView填充整個DockablePane區域 <P></P> <P></P> <PRE class=cpp name="code">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); } }</PRE><BR> <BR> <P></P> <P>至此結束。。。回答一些疑問。</P> <P>為什麼要改寫CMfcFormView的Create虛函數呢?</P> <P>因為我們要用到這句函數。</P> <P><SPAN style="COLOR: rgb(255,0,0)">m_pformView->Create(NULL, NULL, WS_CHILD|WS_VISIBLE, rect, this, 123, NULL);</SPAN></P> <P></P> <P>調用到FormView::Create函數。由於FormView的Create函數是protected類型的.所以我們必須改寫FormView::Create函數為Publc類型。雖然我們在Create函數裡什麼也沒有做什麼。如果不重寫Create函數的話,那麼會出現編譯錯誤。</P> <P><BR> </P> <P><BR> </P> // 創建停靠窗口 if (!CreateDockingWindows()) _ { TRACE0("未能創建停靠窗口\n"); return -1; } m_wndFileView.EnableDocking(CBRS_ALIGN_ANY); m_wndClassView.EnableDocking(CBRS_ALIGN_ANY); DockPane(&m_wndFileView); | CDockablePane* pTabbedBar = NULL; | m_wndClassView.AttachToTabWnd(&m_wndFileView, DM_SHOW, TRUE, &pTabbedBar); m_wndOutput.EnableDocking(CBRS_ALIGN_ANY); DockPane(&m_wndOutput); m_wndProperties.EnableDocking(CBRS_ALIGN_ANY); DockPane(&m_wndProperties);_ m_wndSolution.EnableDocking(CBRS_ALIGN_ANY); m_wndSolution.AttachToTabWnd(&m_wndProperties, DM_SHOW, TRUE, &pTabbedBar);[cpp] view plaincopyprint?// 紅色為自己添加 // 紅色為自己添加 3.在MainFrm.cpp裡的CMainFrame::CreateDockingWindows()中添加代碼 [cpp] <SPAN style="COLOR: #ff0000">//創建解決方案窗口 CString strSolutionWnd; bNameValid = strSolutionWnd.LoadString(IDS_SOLUTION_WND); ASSERT(bNameValid); if(!</SPAN><SPAN style="COLOR: #3333ff">m_wndSolution.Create</SPAN><SPAN style="COLOR: #ff0000">(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; }</SPAN> //創建解決方案窗口 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; }既然我們要創建CDockablePane那必然需要改寫OnCreate函數和OnSize函數,原因是,通過CDockablePane的創建必然會調用OnCreate函數,在OnCreate函數裡創建FormView,在OnSize裡面調整FormView的大小,覆蓋整個CDockablePane。 利用類向導在CSolution聲明裡添加消息映射函數 [cpp] public: DECLARE_MESSAGE_MAP() afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct); afx_msg void OnSize(UINT nType, int cx, int cy); public: DECLARE_MESSAGE_MAP() afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct); afx_msg void OnSize(UINT nType, int cx, int cy); [cpp] int CSolutionWnd::OnCreate(LPCREATESTRUCT lpCreateStruct) { if (CDockablePane::OnCreate(lpCreateStruct) == -1) return -1; // TODO: 在此添加您專用的創建代碼 return 0; } void CSolutionWnd::OnSize(UINT nType, int cx, int cy) { CDockablePane::OnSize(nType, cx, cy); // TODO: 在此處添加消息處理程序代碼 } int CSolutionWnd::OnCreate(LPCREATESTRUCT lpCreateStruct) { if (CDockablePane::OnCreate(lpCreateStruct) == -1) return -1; // TODO: 在此添加您專用的創建代碼 return 0; } void CSolutionWnd::OnSize(UINT nType, int cx, int cy) { CDockablePane::OnSize(nType, cx, cy); // TODO: 在此處添加消息處理程序代碼 } 利用類向導在CMfcFormView裡添加消息映射函數OnCreate以及改寫虛函數Create [cpp] 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); 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); [cpp] // 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); } // 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); } 在CSolution.h裡聲明CMfcFormView*類型的指針變量 [cpp] protected: CMfcFormView* m_pformView; protected: CMfcFormView* m_pformView; 在CSolution的構造函數裡創建CMfcFormView對象 [cpp] CSolutionWnd::CSolutionWnd() { m_pformView = (CMfcFormView*) (RUNTIME_CLASS(CMfcFormView)->CreateObject()); } CSolutionWnd::CSolutionWnd() { m_pformView = (CMfcFormView*) (RUNTIME_CLASS(CMfcFormView)->CreateObject()); } 在CSolution的OnCreate函數裡創建FormView [cpp] int CSolutionWnd::OnCreate(LPCREATESTRUCT lpCreateStruct) { if (CDockablePane::OnCreate(lpCreateStruct) == -1) return -1; // TODO: 在此添加您專用的創建代碼 <SPAN style="COLOR: #ff0000">RECT rect; GetClientRect(&rect); m_pformView->Create(NULL, NULL, WS_CHILD|WS_VISIBLE, rect, this, 123, NULL);</SPAN> return 0; } 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區域 [cpp] 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); } } 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); } } 至此結束。。。回答一些疑問。 為什麼要改寫CMfcFormView的Create虛函數呢? 因為我們要用到這句函數。 m_pformView->Create(NULL, NULL, WS_CHILD|WS_VISIBLE, rect, this, 123, NULL); 調用到FormView::Create函數。由於FormView的Create函數是protected類型的.所以我們必須改寫FormView::Create函數為Publc類型。雖然我們在Create函數裡什麼也沒有做什麼。如果不重寫Create函數的話,那麼會出現編譯錯誤。 分享到: