Introduction
This source make CView window under CView using CWnd control. You need Visual C++ 7.1 to read this source project. I create this project on Visual Studio .NET 2003.
Description
Many people wish to make multiful window on CView or any other View(CScrollView, CEditView, CFormView, etc...) without new frame and splitter window. How to make this window? Many people think about Create(...) Function.
Many People make Create function for new window creation, like this
CView m_wndView;
m_wndView.Create(NULL, _T("VIEW"), WS_CHILD | WS_VISIBLE, CRect(0,0,0,0), this, 10000);
But this method occur the error while destory window because DestoryWindow procedure. This real method need to help RUNTIME_CLASS. We seem to create always View, Document, Frame.
My Method
My method using RUNTIME_CLASS at CWnd creattion. First, You make CWnd window at basic CView Window. I called this window CMiniWnd from CWnd.
First, You make CWnd control at your View.
void CsampleView::OnInitialUpdate()
{
CView::OnInitialUpdate();
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);
}
}
Second, You make CWnd control like this from CWnd control class.
#pragma once
#include "miniview.h"
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);
};
#include "stdafx.h"
#include "sample.h"
#include "MiniWnd.h"
#include ".\miniwnd.h"
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);
CCreateContext context;
context.m_pNewViewClass = pNewViewClass;
CMiniView* pNewView = CreateView(pNewViewClass, rect, &context);
if (pNewView != NULL)
{
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)
{
CMiniView* pOldView = NULL;
if (pOldView != NULL && pOldView->IsKindOf(RUNTIME_CLASS(CMiniView)))
{
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");
return (CMiniView*) NULL;
}
END_CATCH_ALL
ASSERT_KINDOF(CWnd, pWnd);
ASSERT(pWnd->m_hWnd == NULL);
DWORD dwStyle = WS_VISIBLE | WS_CHILD | WS_BORDER;
CRect rect(lprect);
if (!pWnd->Create(NULL, NULL, dwStyle,
rect, this, 0, pContext))
{
TRACE0("Warning: couldn't create client pane for splitter.\n");
return (CMiniView*) NULL;
}
if (bSendInitialUpdate);
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);
}
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);
}
}
Create SubWindow
You see the OnCreate Function and CreateView Function.
OnCreate Function is make CRuntimeClass and CCreateContect. You need this member at that CreateView Function. CRuntimeClass member make CMiniView from CView type. and CCreateContect member insert pNewViewClass using CRuntimeClass.
CRuntimeClass* pNewViewClass;
pNewViewClass = RUNTIME_CLASS(CMiniView);
CCreateContext context;
context.m_pNewViewClass = pNewViewClass;
and Create View window on CWnd control at CreateView Function.
CMiniView* pNewView = CreateView(pNewViewClass, rect, &context);
Next step is to make visible and initialization of window.
if (pNewView != NULL)
{
pNewView->ShowWindow(SW_SHOW);
pNewView->OnInitialUpdate();
pNewView->SetActiveWindow();
RecalcLayout();
}
Real Action
Real Action method is CreateView function.
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)
{
CMiniView* pOldView = NULL;
if (pOldView != NULL && pOldView->IsKindOf(RUNTIME_CLASS(CMiniView)))
{
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");
return (CMiniView*) NULL;
}
END_CATCH_ALL
ASSERT_KINDOF(CWnd, pWnd);
ASSERT(pWnd->m_hWnd == NULL);
DWORD dwStyle = WS_VISIBLE | WS_CHILD | WS_BORDER;
CRect rect(lprect);
if (!pWnd->Create(NULL, NULL, dwStyle,
rect, this, 0, pContext))
{
TRACE0("Warning: couldn't create client pane for splitter.\n");
return (CMiniView*) NULL;
}
if (bSendInitialUpdate);
m_wndView = (CMiniView*) pWnd;
return m_wndView;
}
This Function Key point is pWnd = (CWnd*)pViewClass->CreateObject(); line. This line make object of CMiniView using predefine type.
And the other function make movable action and get ActiveView pointer.
CView Window
#pragma once
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);
};
#include "stdafx.h"
#include "sample.h"
#include "MiniView.h"
#include ".\miniview.h"
IMPLEMENT_DYNCREATE(CMiniView, CView)
CMiniView::CMiniView()
{
}
CMiniView::~CMiniView()
{
}
BEGIN_MESSAGE_MAP(CMiniView, CView)
ON_WM_SIZE()
END_MESSAGE_MAP()
void CMiniView::OnDraw(CDC* pDC)
{
CDocument* pDoc = GetDocument();
pDC->TextOut(0, 0, "Hello");
}
#ifdef _DEBUG
void CMiniView::AssertValid() const
{
CView::AssertValid();
}
void CMiniView::Dump(CDumpContext& dc) const
{
CView::Dump(dc);
}
#endif
void CMiniView::OnInitialUpdate()
{
CView::OnInitialUpdate();
}
void CMiniView::OnSize(UINT nType, int cx, int cy)
{
CView::OnSize(nType, cx, cy);
}