65.9K
CodeProject 正在变化。 阅读更多。
Home

在CView下为MinView创建子窗口

starIcon
emptyStarIcon
starIcon
emptyStarIconemptyStarIconemptyStarIcon

1.62/5 (12投票s)

2004年10月23日

1分钟阅读

viewsIcon

72662

downloadIcon

1978

本文基于CWnd控件,在CView下制作了一个CView。

Sample Image - sample.jpg

引言

此代码使用 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);
}

 

 

© . All rights reserved.