VC++
MFC example: Micrsoft Visio 12 like Print Preview
Source Code
|
|
Introduction
A print preview window
that showing the printer's paper margins is a very good
idea, for most flow diagramming or printing applications
(such as Micrsoft Visio 2007,
GADWin, E-XD++ Flow Diagramming Kit, etc.), they all have
this feature, below is a screen shot of the latest edition
of Micrsoft Visio 2007:
There is no topic with
this on codeguru or codeproject,
so I created it by myself, below is how it works:
1. At first, We
need to create a new class that use CPreviewView
as base class, please remember to include afxpriv.h.
2. Override the
OnDraw method of CPreviewView,
and change it's code to below:
void
CExtPreviewView::OnDraw(CDC* pDC)
{
ASSERT_VALID(pDC);
// don't do anything if not fully initialized
if (m_pPrintView == NULL || m_dcPrint.m_hDC == NULL)
return;
CPoint ViewportOrg = pDC->GetViewportOrg();
CPen rectPen;
rectPen.CreatePen(PS_SOLID, 2, GetSysColor(COLOR_WINDOWFRAME));
CPen shadowPen;
shadowPen.CreatePen(PS_SOLID, 3, GetSysColor(COLOR_BTNSHADOW));
m_pPreviewInfo->m_bContinuePrinting = TRUE; // do this once each paint
for (UINT nPage = 0; nPage < m_nPages; nPage++)
{
int nSavedState = m_dcPrint.SaveDC(); // Save pristine state of DC
// Use paint DC for print preview output
m_pPreviewDC->SetOutputDC(pDC->GetSafeHdc());
m_pPreviewInfo->m_nCurPage = m_nCurrentPage + nPage;
// Only call PrepareDC if within page range, otherwise use default
// rect to draw page rectangle
if (m_nCurrentPage + nPage <= m_pPreviewInfo->GetMaxPage())
m_pPrintView->OnPrepareDC(m_pPreviewDC, m_pPreviewInfo);
// Set up drawing rect to entire page (in logical coordinates)
m_pPreviewInfo->m_rectDraw.SetRect(0, 0,
m_pPreviewDC->GetDeviceCaps(HORZRES),
m_pPreviewDC->GetDeviceCaps(VERTRES));
m_pPreviewDC->DPtoLP(&m_pPreviewInfo->m_rectDraw);
// Draw empty page on screen
pDC->SaveDC(); // save the output dc state
CSize* pRatio = &m_pPageInfo[nPage].sizeScaleRatio;
CRect* pRect = &m_pPageInfo[nPage].rectScreen;
if (pRatio->cx == 0)
{ // page position has not been determined
PositionPage(nPage); // compute page position
if (m_nZoomState != ZOOM_OUT)
ViewportOrg = -GetDeviceScrollPosition();
}
pDC->SetMapMode(MM_TEXT); // Page Rectangle is in screen device coords
pDC->SetViewportOrg(ViewportOrg);
pDC->SetWindowOrg(0, 0);
pDC->SelectStockObject(HOLLOW_BRUSH);
pDC->SelectObject(&rectPen);
pDC->Rectangle(pRect);
pDC->SelectObject(&shadowPen);
pDC->MoveTo(pRect->right + 1, pRect->top + 3);
pDC->LineTo(pRect->right + 1, pRect->bottom + 1);
pDC->MoveTo(pRect->left + 3, pRect->bottom + 1);
pDC->LineTo(pRect->right + 1, pRect->bottom + 1);
// erase background to white (most paper is white)
CRect rectFill = *pRect;
rectFill.left += 1;
rectFill.top += 1;
rectFill.right -= 2;
rectFill.bottom -= 2;
CBrush brush(RGB(240,240,240));
::FillRect(pDC->m_hDC, rectFill, (HBRUSH)brush);
brush.DeleteObject();
pDC->RestoreDC(-1); // restore to synchronized state
if (!m_pPreviewInfo->m_bContinuePrinting ||
m_nCurrentPage + nPage > m_pPreviewInfo->GetMaxPage())
{
m_pPreviewDC->ReleaseOutputDC();
m_dcPrint.RestoreDC(nSavedState); // restore to untouched state
// if the first page is not displayable, back up one page
// but never go below 1
if (nPage == 0 && m_nCurrentPage > 1)
SetCurrentPage(m_nCurrentPage - 1, TRUE);
break;
}
// Display page number
OnDisplayPageNumber(m_nCurrentPage, nPage + 1);
// Set scale ratio for this page
m_pPreviewDC->SetScaleRatio(pRatio->cx, pRatio->cy);
CSize PrintOffset;
VERIFY(m_pPreviewDC->Escape(GETPRINTINGOFFSET, 0, NULL, (LPVOID)&PrintOffset));
m_pPreviewDC->PrinterDPtoScreenDP((LPPOINT)&PrintOffset);
PrintOffset += (CSize)pRect->TopLeft();
PrintOffset += CSize(1, 1);
PrintOffset += (CSize)ViewportOrg; // For Scrolling
m_pPreviewDC->SetTopLeftOffset(PrintOffset);
m_pPreviewDC->ClipToPage();
CTestPreviewView *pView = static_cast<CTestPreviewView *>(m_pPrintView);
pView->OnPrint(m_pPreviewDC, m_pPreviewInfo);
m_pPreviewDC->ReleaseOutputDC();
m_dcPrint.RestoreDC(nSavedState); // restore to untouched state
}
rectPen.DeleteObject();
shadowPen.DeleteObject();
}
3. Add a new global
method at the head of class CExtPreviewView, as below:
// Print preview.
void AFX_API FOPrintPreview(CTestPreviewView* pView);
and
void FOPrintPreview (CTestPreviewView* pView)
{
ASSERT_VALID (pView);
CPrintPreviewState *pState= new CPrintPreviewState;
#if (_MFC_VER < 0x0700) // Visual Studio 6.0
if (!pView->DoPrintPreview (IDD_FO_PREVIEW_TOOLBAR, pView,
RUNTIME_CLASS(CExtPreviewView), pState))
{
TRACE0("Error: OnFilePrintPreview failed.\n");
AfxMessageBox (AFX_IDP_COMMAND_FAILURE);
delete pState; // preview failed to initialize, delete State now
}
#else
if (!pView->DoPrintPreview (IDD_FO_PREVIEW_TOOLBAR, pView,
RUNTIME_CLASS(CExtPreviewView), pState))
{
TRACE0("Error: OnFilePrintPreview failed.\n");
AfxMessageBox (AFX_IDP_COMMAND_FAILURE);
delete pState; // preview failed to initialize, delete State now
}
#endif
}
If you want to change the
color of paper margins, you need change the following
codes:
CBrush brush(RGB(240,240,240));
::FillRect(pDC->m_hDC, rectFill, (HBRUSH)brush);
brush.DeleteObject();
4. Add a method for menu
item ID_FILE_PRINT_PREVIEW, and then change it's codes to:
void CTestPreviewView::OnFilePrintPreview()
{
// TODO: Add your command handler code here
FOPrintPreview(this);
}
That's all, I created a
test program on testing this feature, below is a screen
shot of how it looks like:
and
For testing, choose
"File | Print Preview" menu item, these
codes are full tested on Visual
C++ 6.0, Visual
C++.NET 2003, and Visual
C++.NET 2005, it should also works with MDI,
SDI applications.
|