在CView下为MinView创建子窗口






1.62/5 (12投票s)
2004年10月23日
1分钟阅读

72662

1978
本文基于CWnd控件,
引言
此代码使用 CWnd 控件在 CView 下创建 CView 窗口。您需要 Visual C++ 7.1 才能读取此源代码项目。我是在 Visual Studio .NET 2003 上创建此项目的。
描述
许多人希望在 CView 或任何其他视图(CScrollView、CEditView、CFormView 等)上创建多个窗口,而无需新的框架和分割窗口。如何创建此窗口?许多人想到 Create(...) 函数。
许多人使用如下方式为新窗口创建 Create 函数:
CView m_wndView;
m_wndView.Create(NULL, _T("VIEW"), WS_CHILD | WS_VISIBLE, CRect(0,0,0,0), this, 10000);
但是,这种方法在销毁窗口时会发生错误,因为销毁窗口的过程。这种真实的方法需要借助 RUNTIME_CLASS。我们似乎总是需要创建 View、Document 和 Frame。
我的方法
我的方法在 CWnd 创建时使用 RUNTIME_CLASS。首先,您在基本的 CView 窗口中创建一个 CWnd 窗口。我将此窗口称为 CMiniWnd,它继承自 CWnd。
首先,在您的 View 中创建一个 CWnd 控件。
void CsampleView::OnInitialUpdate() { CView::OnInitialUpdate(); // View size CRect clientRect; GetClientRect(&clientRect); clientRect.SetRect(clientRect.right -110, clientRect.top+10, clientRect.right-10, clientRect.top +110); m_wndMiniWnd.Create(NULL, _T("MINI"), WS_VISIBLE | WS_CHILD, clientRect, this, IDR_MINIWND); m_wndMiniWnd.ShowWindow(SW_SHOW); } void CsampleView::OnSize(UINT nType, int cx, int cy) { CView::OnSize(nType, cx, cy); if(m_wndMiniWnd.GetSafeHwnd()) { CRect clientRect; GetClientRect(&clientRect); clientRect.SetRect(clientRect.right -110, clientRect.top+10, clientRect.right-10, clientRect.top +110); m_wndMiniWnd.MoveWindow(clientRect); } }
其次,从 CWnd 控件类创建如下 CWnd 控件:
// MiniWnd.h #pragma once #include "miniview.h" // CMiniWnd class CMiniWnd : public CWnd { DECLARE_DYNAMIC(CMiniWnd) public: CMiniWnd(); virtual ~CMiniWnd(); protected: DECLARE_MESSAGE_MAP() public: CMiniView* m_wndView; afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct); CMiniView* CreateView(CRuntimeClass * pViewClass, const RECT & lprect, CCreateContext * pContext); CMiniView* GetActiveView(void); afx_msg BOOL OnEraseBkgnd(CDC* pDC); afx_msg void OnPaint(); void RecalcLayout(void); afx_msg void OnSize(UINT nType, int cx, int cy); };
// MiniWnd.cpp #include "stdafx.h" #include "sample.h" #include "MiniWnd.h" #include ".\miniwnd.h" // CMiniWnd IMPLEMENT_DYNAMIC(CMiniWnd, CWnd) CMiniWnd::CMiniWnd() : m_wndView(NULL) { } CMiniWnd::~CMiniWnd() { } BEGIN_MESSAGE_MAP(CMiniWnd, CWnd) ON_WM_CREATE() ON_WM_ERASEBKGND() ON_WM_PAINT() ON_WM_SIZE() END_MESSAGE_MAP() int CMiniWnd::OnCreate(LPCREATESTRUCT lpCreateStruct) { if (CWnd::OnCreate(lpCreateStruct) == -1) return -1; CRect rect; GetClientRect(rect); CRuntimeClass* pNewViewClass; pNewViewClass = RUNTIME_CLASS(CMiniView); // create the new view CCreateContext context; context.m_pNewViewClass = pNewViewClass; CMiniView* pNewView = CreateView(pNewViewClass, rect, &context); if (pNewView != NULL) { // the new view is there, but invisible and not active... pNewView->ShowWindow(SW_SHOW); pNewView->OnInitialUpdate(); pNewView->SetActiveWindow(); RecalcLayout(); } return 0; } CMiniView* CMiniWnd::CreateView(CRuntimeClass * pViewClass, const RECT & lprect, CCreateContext * pContext) { #ifdef _DEBUG ASSERT_VALID(this); ASSERT(pViewClass != NULL); ASSERT(pViewClass->IsDerivedFrom(RUNTIME_CLASS(CWnd))); ASSERT(AfxIsValidAddress(pViewClass, sizeof(CRuntimeClass), FALSE)); #endif BOOL bSendInitialUpdate = FALSE; CCreateContext contextT; if (pContext == NULL) { // if no context specified, generate one from the currently selected // client if possible CMiniView* pOldView = NULL; if (pOldView != NULL && pOldView->IsKindOf(RUNTIME_CLASS(CMiniView))) { // set info about last pane ASSERT(contextT.m_pCurrentFrame == NULL); contextT.m_pLastView = pOldView; contextT.m_pCurrentDoc = pOldView->GetDocument(); if (contextT.m_pCurrentDoc != NULL) contextT.m_pNewDocTemplate = contextT.m_pCurrentDoc->GetDocTemplate(); } pContext = &contextT; bSendInitialUpdate = TRUE; } CWnd* pWnd; TRY { pWnd = (CWnd*)pViewClass->CreateObject(); if (pWnd == NULL) AfxThrowMemoryException(); } CATCH_ALL(e) { TRACE0("Out of memory creating a splitter pane.\n"); // Note: DELETE_EXCEPTION(e) not required return (CMiniView*) NULL; } END_CATCH_ALL ASSERT_KINDOF(CWnd, pWnd); ASSERT(pWnd->m_hWnd == NULL); // not yet created DWORD dwStyle = WS_VISIBLE | WS_CHILD | WS_BORDER;//AFX_WS_DEFAULT_VIEW |; // Create with the right size (wrong position) CRect rect(lprect); if (!pWnd->Create(NULL, NULL, dwStyle, rect, this, 0, pContext)) { TRACE0("Warning: couldn't create client pane for splitter.\n"); // pWnd will be cleaned up by PostNcDestroy return (CMiniView*) NULL; } // send initial notification message if (bSendInitialUpdate); // pWnd->SendMessage(WM_INITIALUPDATE); m_wndView = (CMiniView*) pWnd; return m_wndView; } CMiniView* CMiniWnd::GetActiveView(void) { return m_wndView; } BOOL CMiniWnd::OnEraseBkgnd(CDC* pDC) { return FALSE; } void CMiniWnd::OnPaint() { CPaintDC dc(this); // device context for painting } void CMiniWnd::RecalcLayout(void) { CWnd* pWnd = (CWnd*) GetActiveView(); CRect rect; GetClientRect(&rect); } void CMiniWnd::OnSize(UINT nType, int cx, int cy) { CWnd::OnSize(nType, cx, cy); if(m_wndView->GetSafeHwnd()); { CRect rcView(0, 0, cx, cy); m_wndView->MoveWindow(rcView); } }
创建子窗口
您将看到 OnCreate 函数和 CreateView 函数。
OnCreate 函数创建 CRuntimeClass 和 CCreateContext。您需要在 CreateView 函数中使用这些成员。CRuntimeClass 成员使用 CView 类型创建 CMiniView,而 CCreateContext 成员使用 CRuntimeClass 插入 pNewViewClass。
CRuntimeClass* pNewViewClass;
pNewViewClass = RUNTIME_CLASS(CMiniView);
// create the new view
CCreateContext context;
context.m_pNewViewClass = pNewViewClass;
然后在 CreateView 函数中在 CWnd 控件上创建 View 窗口。
CMiniView* pNewView = CreateView(pNewViewClass, rect, &context);
下一步是使窗口可见并进行初始化。
if (pNewView != NULL)
{
// the new view is there, but invisible and not active...
pNewView->ShowWindow(SW_SHOW);
pNewView->OnInitialUpdate();
pNewView->SetActiveWindow();
RecalcLayout();
}
实际操作
实际操作方法是 CreateView 函数。
CMiniView* CMiniWnd::CreateView(CRuntimeClass * pViewClass, const RECT & lprect, CCreateContext * pContext) { #ifdef _DEBUG ASSERT_VALID(this); ASSERT(pViewClass != NULL); ASSERT(pViewClass->IsDerivedFrom(RUNTIME_CLASS(CWnd))); ASSERT(AfxIsValidAddress(pViewClass, sizeof(CRuntimeClass), FALSE)); #endif BOOL bSendInitialUpdate = FALSE; CCreateContext contextT; if (pContext == NULL) { // if no context specified, generate one from the currently selected // client if possible CMiniView* pOldView = NULL; if (pOldView != NULL && pOldView->IsKindOf(RUNTIME_CLASS(CMiniView))) { // set info about last pane ASSERT(contextT.m_pCurrentFrame == NULL); contextT.m_pLastView = pOldView; contextT.m_pCurrentDoc = pOldView->GetDocument(); if (contextT.m_pCurrentDoc != NULL) contextT.m_pNewDocTemplate = contextT.m_pCurrentDoc->GetDocTemplate(); } pContext = &contextT; bSendInitialUpdate = TRUE; } CWnd* pWnd; TRY { pWnd = (CWnd*)pViewClass->CreateObject(); if (pWnd == NULL) AfxThrowMemoryException(); } CATCH_ALL(e) { TRACE0("Out of memory creating a splitter pane.\n"); // Note: DELETE_EXCEPTION(e) not required return (CMiniView*) NULL; } END_CATCH_ALL ASSERT_KINDOF(CWnd, pWnd); ASSERT(pWnd->m_hWnd == NULL); // not yet created DWORD dwStyle = WS_VISIBLE | WS_CHILD | WS_BORDER;//AFX_WS_DEFAULT_VIEW |; // Create with the right size (wrong position) CRect rect(lprect); if (!pWnd->Create(NULL, NULL, dwStyle, rect, this, 0, pContext)) { TRACE0("Warning: couldn't create client pane for splitter.\n"); // pWnd will be cleaned up by PostNcDestroy return (CMiniView*) NULL; } // send initial notification message if (bSendInitialUpdate); // pWnd->SendMessage(WM_INITIALUPDATE); m_wndView = (CMiniView*) pWnd; return m_wndView; }
此函数的核心是 pWnd = (CWnd*)pViewClass->CreateObject(); 行。该行使用预定义的类型创建 CMiniView 对象。
其他函数用于实现可移动操作并获取 ActiveView 指针。
CView 窗口
// MiniView.h #pragma once // CMiniView class CMiniView : public CView { DECLARE_DYNCREATE(CMiniView) public: CMiniView(); virtual ~CMiniView(); public: virtual void OnDraw(CDC* pDC); #ifdef _DEBUG virtual void AssertValid() const; virtual void Dump(CDumpContext& dc) const; #endif protected: DECLARE_MESSAGE_MAP() public: virtual void OnInitialUpdate(); afx_msg void OnSize(UINT nType, int cx, int cy); };
// MiniView.cpp #include "stdafx.h" #include "sample.h" #include "MiniView.h" #include ".\miniview.h" // CMiniView IMPLEMENT_DYNCREATE(CMiniView, CView) CMiniView::CMiniView() { } CMiniView::~CMiniView() { } BEGIN_MESSAGE_MAP(CMiniView, CView) ON_WM_SIZE() END_MESSAGE_MAP() // CMiniView Draw void CMiniView::OnDraw(CDC* pDC) { CDocument* pDoc = GetDocument(); pDC->TextOut(0, 0, "Hello"); } // CMiniView DEBUG. #ifdef _DEBUG void CMiniView::AssertValid() const { CView::AssertValid(); } void CMiniView::Dump(CDumpContext& dc) const { CView::Dump(dc); } #endif //_DEBUG void CMiniView::OnInitialUpdate() { CView::OnInitialUpdate(); } void CMiniView::OnSize(UINT nType, int cx, int cy) { CView::OnSize(nType, cx, cy); }