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;
}