The Doc/View architecture in MFC is not the fastest
way to create a simple print preview. This article
will explain how to create your own print preview.
MFC
Doc/View is designed to make the MSVC programmers
get their work done in minutes, including print
preview. Sometimes we do not need to use Doc/View
framework
but we really do need its print-preview power.
The key to Print Preview is in the following functions
-
CreateCompatibleBitmap
-
CreateCompatibleDC
-
GetDeviceCaps
-
GetTextExtent
Beside those four functions Print Preview needs a
function that work for scaling and painting on the
screen DC.
Luckily we have StretchBlt and BitBlt ready to
do the dirty work, but sometimes StretchBlt might need to be
replaced
by your favourite routine (for dithering, filtering,
antialiasing etc.).
The function to perform print preview in a window is as follows.
void PrintPreview(CWnd *pWnd)
{
CString strWords;
CWnd* pWnd = GetDlgItem(IDC_STATIC_PREVIEW); CDC* dc;
CDC memoriDC;
CBitmap memBMP;
CBitmap* pOldBMP;
CFont fnt;
CFont* pOldFnt;
CRect rect;
CRect rectMemory;
CSize zMetrix;
CPrintDialog pdlg(FALSE);
DOCINFO di;
CDC prnDC;
di.cbSize = sizeof(DOCINFO);
di.lpszDocName = "This string will appear in Printer Queue";
di.lpszOutput = NULL;
di.lpszDatatype = NULL;
di.fwType = 0;
pdlg.GetDefaults();
dc = pWnd->GetDC();
pWnd->GetClientRect(&rect);
if( !prnDC.Attach(pdlg.GetPrinterDC()) )
AfxMessageBox("Invalid Printer DC");
memoriDC.CreateCompatibleDC(&prnDC);
int iPrnX = prnDC.GetDeviceCaps(HORZRES);
int iPrnY = prnDC.GetDeviceCaps(VERTRES);
int iMonX = dc->GetDeviceCaps(HORZRES); int iMonY = dc->GetDeviceCaps(VERTRES);
rectMemory.top = 0;
rectMemory.left = 0;
rectMemory.bottom = iPrnY;
rectMemory.right = iPrnX;
memBMP.CreateCompatibleBitmap(&prnDC, rectMemory.Width(), rectMemory.Height());
pOldBMP = memoriDC.SelectObject(&memBMP);
memoriDC.SetBkMode(TRANSPARENT);
memoriDC.SetTextColor(RGB(0, 0, 0));
memoriDC.PatBlt(0, 0, rectMemory.Width(), rectMemory.Height(), WHITENESS);
int iPointz = 100;
fnt.CreatePointFont(iPointz, "OCR A", &memoriDC);
strWords.Format("This is line number "); pOldFnt = memoriDC.SelectObject(&fnt);
zMetrix = memoriDC.GetTextExtent(strWords);
int iPos = 0;
int iMaksimal = 0;
int iLineHeight = 1;
int iLoop;
CString strPuncak;
for(iLoop = 1; iLoop < 100; iLoop++)
{
if( ((zMetrix.cy+iLineHeight)*iLoop) < iPrnY )
iMaksimal++;
}
strPuncak.Format("Maximum Amount of line(s) for %d points are %d lines",
iPointz, iMaksimal);
for(iLoop = 0; iLoop < iMaksimal; iLoop++)
{
strWords.Format("This is line %d", iLoop);
memoriDC.TextOut(0, iLoop*(zMetrix.cy+iLineHeight), strWords);
}
memoriDC.SelectObject(pOldFnt);
float fXRatio = (float) iMonX/iPrnX;
float fYRatio = (float) iMonY/iPrnY;
int iLebar = rect.Width()*fXRatio;
int iTinggi = rect.Height()*fYRatio;
int iXPosisiPreview = (rect.Width() - iLebar)/2;
int iYPosisiPreview = (rect.Height() - iTinggi)/2;
CPen pen(PS_SOLID, 2, RGB(255, 0, 0));
CPen* pOldPen;
pOldPen = dc->SelectObject(&pen);
dc->Rectangle(iXPosisiPreview, iYPosisiPreview,iXPosisiPreview + iLebar + 2,
iYPosisiPreview + iTinggi + 2);
dc->SelectObject(pOldPen);
dc->StretchBlt(iXPosisiPreview , iYPosisiPreview, iLebar, iTinggi,
&memoriDC, 0, 0, rectMemory.Width(), rectMemory.Height(), SRCCOPY);
fnt.DeleteObject();
memoriDC.SelectObject(pOldBMP);
memoriDC.DeleteDC();
memBMP.DeleteObject();
prnDC.Detach();
pWnd->ReleaseDC(dc);
}