Introduction
Using the default properties supplied for printer output does not give consistent results. The printable region and the pixel density cause variations. If you are outputting pages for a formal report, consistent margins and font size are often required. The following functions provide a method for obtaining consistent output between printers.
Included functions are:
UserPage which returns a CRect which defines a consistent printable area for each printer (Your margins must be within the printable region of all printers of course!)
CreateFontSize which returns a CSize which defines the font attribute with respect to the desired point size and printer characteristics.
The remaining code shows sample usage of these functions.
CRect CChildView::UserPage(CDC * pDC, float margin)
{
int OriginalMapMode = pDC->SetMapMode(MM_TWIPS);
CSize PrintOffset,Physical,Printable;
Physical.cx = pDC->GetDeviceCaps(PHYSICALWIDTH);
Physical.cy = pDC->GetDeviceCaps(PHYSICALHEIGHT);
pDC->DPtoLP(&Physical);
PrintOffset.cx = pDC->GetDeviceCaps(PHYSICALOFFSETX);
PrintOffset.cy = pDC->GetDeviceCaps(PHYSICALOFFSETY);
pDC->DPtoLP(&PrintOffset);
Printable.cx = (int)((float)pDC->GetDeviceCaps(HORZSIZE)*56.69);
Printable.cy = (int)((float)pDC->GetDeviceCaps(VERTSIZE)*56.69);
int inch = 1440; int Dx1, Dx2, Dy1, Dy2; Dx1 = PrintOffset.cx;
Dy1 = PrintOffset.cy;
Dy2 = Physical.cy-Printable.cy-Dy1;
Dx2 = Physical.cx-Printable.cx-Dx1;
CRect PageArea;
PageArea.left = (long)(margin*inch-Dx1);
PageArea.right = (long)(Printable.cx-margin*inch+Dx2);
PageArea.top = (int)-(margin*inch-Dy1); PageArea.bottom = (int)-(Printable.cy-margin*inch+Dy2);
pDC->LPtoDP(&PageArea);
return PageArea;
}int CChildView::CreateFontSize(CDC *pdc, int points)
{
CSize size;
int perinch = pdc->GetDeviceCaps(LOGPIXELSY);
size.cx = size.cy = (perinch*points)/72;
pdc->DPtoLP(&size);
return size.cy;
}
To use CreateFontSize, just insert the function call into the CreateFont function:
BaseFont.CreateFont( -CreateFontSize(pdc,11), 0, 0, 0, FW_MEDIUM,
FALSE, FALSE, 0, ANSI_CHARSET,
OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
DEFAULT_QUALITY, DEFAULT_PITCH , "Courier New" );
The UserPage function can be used internal to your OnPrint function. Where you call it, use the returned area rather than the region found from the pDC's GetDeviceCaps function. (Usually sent in the PrintInfo data.) Or you can call it to set the region in to be passed.
void CChildView::PrintSetup(int item)
{
BOOL bStdSetUpDlg = TRUE;
PD_NOPAGENUMS | PD_HIDEPRINTTOFILE | PD_NOSELECTION;
DWORD dwFlags = PD_ALLPAGES;
CWnd *pParent = this;
CPrintDialog MyPrintDlg(bStdSetUpDlg,dwFlags,pParent);
CPrintInfo MyPrintInfo;
MyPrintInfo.m_pPD = &MyPrintDlg;
int MyAnswer;
MyAnswer = MyPrintDlg.DoModal();
if(MyAnswer==IDCANCEL) return;
DEVMODE *MyPrintMode;
MyPrintMode = MyPrintDlg.GetDevMode();
CDC MyPrintDC;
MyPrintDC.CreateDC(MyPrintDlg.GetDriverName(), MyPrintDlg.GetDeviceName(), MyPrintDlg.GetPortName(), MyPrintMode); DOCINFO MyDocInfo;
MyDocInfo.cbSize=sizeof(DOCINFO);
CString DocName;
DocName.LoadString(AFX_IDS_APP_TITLE);
MyDocInfo.lpszDocName="DocName";
MyDocInfo.lpszOutput="";
int iErr = MyPrintDC.StartDoc(&MyDocInfo);
if(iErr < 0)
{
MyPrintDC.AbortDoc();
GlobalUnlock(MyPrintMode); return;
}
MyPrintDC.m_bPrinting=TRUE;
CRect MyArea;
MyArea = UserPage(&MyPrintDC, 0.9f);
MyPrintInfo.m_rectDraw.SetRect(MyArea.left,
MyArea.top,MyArea.right,MyArea.bottom);
MyPrintDC.StartPage();
MyPrintDC.SetMapMode(MM_TEXT);
switch(item)
{
case(1):
PrintLoose(&MyPrintDC,MyArea);
break;
case(2):
PrintRecord(&MyPrintDC,MyArea);
break;
}
MyPrintDC.m_bPrinting=FALSE;
MyPrintDC.EndPage();
MyPrintDC.EndDoc();
GlobalUnlock(MyPrintMode); return;
}
Began programming in 1968 on a Wang 720. Move to Fortran and began developing FEM (finite element model) applications on an IBM 360 in 1973. Developed custom FEM editors for most of my career until 1995. Since then I have been focusing on improving information flow and quality with web based communications (Web Services and SOA concepts.) Mostly in an evangelist role.