SHARE
Facebook X Pinterest WhatsApp

Wrap-Around Draw Function for Printing Text

Why did I write this function? I basically had an application where I needed to print the contents of a Listbox control and I couldn’t use the built-in doc/view printing. Now this data had fields with widths longer than the field width I could allow for each column. So I thought I would use the […]

Written By
thumbnail
CodeGuru Staff
CodeGuru Staff
Feb 4, 2000
CodeGuru content and product recommendations are editorially independent. We may make money when you click on links to our partners. Learn More

Why did I write this function? I basically had an application where I needed to
print the contents of a Listbox control and I couldn’t use the built-in doc/view printing.
Now this data had fields with widths longer than the field width I
could allow for each column. So I thought I would use the DrawText to do a wrap
around print. Then I spent 1 1/2 days around DrawText, because I was lazy.
Being left with no option, I wrote this fn using little bit of code sample
from Drawtext itself. (I was printing into a MetaFile DC for PrintPreview
Implementation. I guess DrawText dint like it)

MAX_NO_OF_LINES_PER_FIELD is the Maximum no of lines of you allow
for the text in case of wrapping – I made it 2, a reasonable count. But if you
want you can provide the above #define as an additional argument or change it and
print as many lines of wrap as possible.

Now a short example: if you had the fist column a persons name, which on
truncating makes no much sense you may want to wrap around

Name Sex
Cindy C  
rawford Female
Linda T  
ripp Female

Note how “r” in Crawford is printed the way it is wrapped around. This is
how the function works.

//This array contains the character widths, 
//used by PrintStringInRect
int 	m_aiCharWidths[256];
//This is set each time when the 
//OnPrint is being called
CDC*	m_pDC;
//The char width
int	m_iCharWidth;
// This variable is going to 
// contain char height
int	m_iHeightText;
void CMyView::OnPrint(CDC* pDC, CPrintInfo* pInfo)
{
 //temporarily store DC for the use of 
 //other member functions
 m_pDC = pDC;
 //Get the charwidths of all ascii characters
 m_pDC -> GetCharWidth(0, 255, m_aiCharWidths);
 //Get the text metrics
 m_pDC ->GetTextMetrics(&m_TextMetric);
 //This is the height of the Text
 m_iHeightText =
  m_TextMetric.tmHeight+m_TextMetric.tmExternalLeading;
 //This is the width of the text (or you 
 //can very well take the width of ‘w’ 
 //from m_aiCharWidths)
 m_iCharWidth = (m_TextMetric.tmAveCharWidth
              + m_TextMetric.tmMaxCharWidth)/2;
}
void CMyView ::PrintStringInRect(CString& strText, CRect* pRect)
{
 char* lpsz = NULL;
 int iNoOfLines=1;
 int iRectLeft = pRect -> left;
 int iMaxCharCount = strText.GetLength();
 if(0 >= iMaxCharCount) return;
 try
 {
  lpsz = new char[iMaxCharCount+1];
 }
 catch(CMemoryException* e)
 {
  e -> ReportError();
  e -> Delete();
 }
 strcpy(lpsz,strText);
 int iCharCurrentCount=0;
 int iOffset=0;
 while(iCharCurrentCount < iMaxCharCount)
 {
  if(lpsz[iOffset] <= 0xFF)
  {
   if(pRect->right
   > iRectLeft + m_aiCharWidths[(BYTE)lpsz[iOffset]])
   {
    iRectLeft += m_aiCharWidths[(BYTE)lpsz[iOffset]];
    iOffset++;
   }
   else
   {
    //print 1 character less, now I am sure no character 
    //caught the corner
    iOffset–;
    m_pDC -> TextOut(pRect -> left,pRect->top,lpsz,iOffset);
    pRect->top -= m_iHeightText;
    iRectLeft = pRect -> left;
    lpsz += iOffset;
    iOffset=0;
    //minus 1 for the extra increment from the loop, 1 for 
    //the space of a //character which is left out
    iCharCurrentCount-=2;
    iNoOfLines++;
    if(iNoOfLines > MAX_NO_OF_LINES_PER_FIELD)
    iCharCurrentCount = iMaxCharCount;
   }
  }
  else
  {
   if(pRect->right > iRectLeft + m_iCharWidth)
   {
    iRectLeft += m_iCharWidth;
    iOffset++;
   }
   else
   {
    //print 1 character less, now I am sure no 
    //character caught the corner
    iOffset–;
    m_pDC -> TextOut(pRect->left,pRect->top,lpsz,iOffset);
    pRect->top -= m_iHeightText;
    iRectLeft = pRect -> left;
    lpsz += iOffset;
    iOffset=0;
    //minus 1 for the extra increment from the loop, 1 
    //for the space of a //character which is left out
    iCharCurrentCount-=2;
    iNoOfLines++;
    if(iNoOfLines > MAX_NO_OF_LINES_PER_FIELD)
    iCharCurrentCount = iMaxCharCount;
   }
  }
  iCharCurrentCount++;
 }
 if(iOffset)
  m_pDC -> TextOut(pRect -> left,pRect->top,lpsz,iOffset);
}

Again the variables m_iCharWidth, m_iHeightText can be used for your
other calculations as to the no of lines in a page, width of the page, etc.

How I decide whether I have wrapped the text around (for adjusting for the Next line)?

While printing a line I keep a flag whether ever I needed to use a wrap, how do
I set the value of this flag?

UINT uCount;

UCount is the Number of characters wide you want each field to be.
So field width = Ucount* m_iCharWidth

You can manage it several ways, but I do it by maintaining an array of how
many characters wide each column is, in each report.

//so if the text takes more space than allowed 
//uCount* m_iCharWidth – you need to wrap around
m_bWrap = (m_pMetaDC->GetTextExtent(strText)).cx
          > uCount * m_iCharWidth);

Now the next part of this post:

If a few of you ever use this post, there will be a frequently asked question for
sure, the size of the characters and widths for different screen resolutions and
drivers and monitors, between print and print preview. Well I will briefly give an
insight to my solution to avoid those problems


  1. I was not using DOC-VIEW architecture for printing.

  2. I was basing my print by writing into a metafile and then playing it back into the DC provided by OnPrint when it has to be printed or previewed. This method was used to be able to implement Print Preview functionality.

  3. I used CDC*pDC provided by OnPrint function only to determine the size of the page and its co-rdinates.

  4. For creating the metafile and for setting its attribute DC and for all other purposes I used the Printer DC created using
  5. 	CDC rDC;
    	if(AfxGetApp()->CreatePrinterDC(rDC))
    	m_pDC = &rDC;
    	

    The reasons for if statement is that, we wont get a printer DC if the machine
    dont have a printer configured to it. This approach assured me that Print
    Preview and Print functionality’s worked identically. WYSIWYG, for all types
    of printers.

  6. Below given is how I retrieve the dimensions of the screen or printer paper and I
    do it only for the first page in case of printing and for every page in case of Print
    Preview.
  7. 	CRect	m_originalRect;
    	void CMyView::OnPrint(CDC* pDC, CPrintInfo* pInfo)
    	{
    	 //if its preview or if Ist page printing find 
    	 //screen coordinates
    	 if(pInfo->m_bPreview || 0 == m_nPage)
    	 {
    	  CPoint point;
    	  //find the device offsets while writing
    	  point.y = pDC->GetDeviceCaps(PHYSICALOFFSETY);
    	  point.x = pDC->GetDeviceCaps(PHYSICALOFFSETX);
    	  pDC->DPtoLP(&point);
    	  pInfo->m_rectDraw.bottom -= point.y;
    	  pInfo->m_rectDraw.right -= point.x;
    	  //save the original rectangle before we 
    	  //perform all sorts of header/footer adjustments
    	  m_originalRect = pInfo->m_rectDraw;
    	 }
    	}
    	

Recommended for you...

How To Make Windows 11 Faster
Enrique Stone
Nov 30, 2022
Working with the Windows Registry in C#
Joydip Kanjilal
Jun 17, 2022
Using Multiple Programming Languages to Create an ASP.NET Website
Tariq Siddiqui
Jun 11, 2022
Finding a Microsoft Office version with .NET
Hannes DuPreez
May 20, 2022
CodeGuru Logo

CodeGuru covers topics related to Microsoft-related software development, mobile development, database management, and web application programming. In addition to tutorials and how-tos that teach programmers how to code in Microsoft-related languages and frameworks like C# and .Net, we also publish articles on software development tools, the latest in developer news, and advice for project managers. Cloud services such as Microsoft Azure and database options including SQL Server and MSSQL are also frequently covered.

Property of TechnologyAdvice. © 2025 TechnologyAdvice. All Rights Reserved

Advertiser Disclosure: Some of the products that appear on this site are from companies from which TechnologyAdvice receives compensation. This compensation may impact how and where products appear on this site including, for example, the order in which they appear. TechnologyAdvice does not include all companies or all types of products available in the marketplace.