Create Sub Window for MiniView under CView






1.62/5 (12 votes)
Oct 23, 2004
1 min read

72242

1978
This Article is make of a CView under CView using CWnd control
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(); // 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); } }
Second, You make CWnd control like this from CWnd control class.
// 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); } }
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);
// create the new view
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)
{
// the new view is there, but invisible and not active...
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) { // 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; }
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
// 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); }