Print Preview without the Doc/View Architecture

Environment: VC6 SP3, NT4 SP5, Windows 2000 Beta 3

This code allows you to make use of the MFC print preview architecture without using the document/ view architecture. This is accomplished by overriding some key functions from the MFC CView class and CPreview class. I have introduced two new classes with the required overrides called CWrapperView and CMyPrintPreview. I will explain how to integrate these classes into a new MFC project created without the use of the document/ view architecture.

Create a new MFC project without the document view architecture. Add WrapperView.cpp, WrapperView.h, and MyPreview.h to your project.

Open the ChildView.h file and include the header file WrapperView.h. Now change the parent class to CWrapperView and add the DECLARE_DYNCREATE macro to the class.


	class CChildView : public CWrapperView
	{
		DECLARE_DYNCREATE(CChildView)
		:
		:
		:
	}

Open MainFrm.h and change


	ChildView m_wndView;

To


	CChildView  *m_pView;

Open MainFrm.cpp and remove the following code from the OnCreate function


	if (!m_wndView.Create(NULL, NULL, AFX_WS_DEFAULT_VIEW,
	CRect(0, 0, 0, 0), this, AFX_IDW_PANE_FIRST, NULL))
	{
		TRACE0("Failed to create view window\n");
		return -1;
	}

And replace it with


	CCreateContext context;
	context.m_pNewViewClass = RUNTIME_CLASS(CChildView);
	context.m_pCurrentFrame = this;
	context.m_pCurrentDoc = NULL;
	context.m_pLastView = NULL;

	m_pView = STATIC_DOWNCAST(CChildView, CreateView(&context));
	if(m_pView != NULL)
	{
		m_pView->ShowWindow(SW_SHOW);
		SetActiveView(m_pView);
	}

Use the class wizard to add command handlers for ID_FILE_PRINT and ID_FILE_PRINT_PREVIEW to CMainFrame and edit the new functions to...


	void CMainFrame::OnFilePrint() 
	{
		m_pView->OnFilePrint();
	}

	void CMainFrame::OnFilePrintPreview() 
	{
		m_pView->OnFilePrintPreview(this);
	}

OnFilePrintPreview has been overriden to take a pointer to the owner frame (in this case CMainFrame) as this is needed in the overriden DoPrintPreview function. The defualt implementation uses AfxGetMainWnd() but sometimes we don't want to use the main window we want to use another frame window derived from CFrameWnd

Open ChildView.cpp and add the following code


	void CChildView::OnFilePrint()
	{
		CView::OnFilePrint();
	}

	IMPLEMENT_DYNCREATE(CChildView, CWrapperView)

Now add a command handler to the CChildView message map


	ON_COMMAND(ID_FILE_PRINT, OnFilePrint)

Open ChildView.h and add


	public:
		void OnFilePrint();

We have to add this overide for the OnFilePrint function because the default implementation in CView is protected and seeing as we need to invoke it from our frame window (CMainFrame, in the File Print Command Handler) we have to make it public in our derived view and then call the default implementation.

Now use the class wizard to add an OnDraw function to your view class and add code to call OnDraw from OnPaint.


	void CChildView::OnPaint() 
	{
		CPaintDC dc(this); // device context for painting
		
		OnDraw(&dc);

		// Do not call CWnd::OnPaint() for painting messages
	}

Now all that remains is to add some code to your OnDraw function.


	OnDraw(CDC *pDC)
	{
		CRect client;
		GetClientRect(&client);
		client.DeflateRect(50, 50);
		CBrush brush(RGB(255, 0, 0));
		pDC->FillRect(&client, &brush);
	}

The same process needs to take place if you have derived a class from CFrameWnd and want to add MFC print preview support to it. The only difference is that you have to do a bit more work by creating the view class yourself.

Downloads

Download demo - 8 Kb
Download source - 21 Kb