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


Comments

  • Sorry i Forget the Email

    Posted by Seu_why on 01/15/2006 09:14pm

    Seu_why@msn.com

    Reply
  • hi

    Posted by Seu_why on 01/15/2006 09:13pm

    Will you kind enough to send me the source code?

    Reply
Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • Managing your company's financials is the backbone of your business and is vital to the long-term health and viability of your company. To continue applying the necessary financial rigor to support rapid growth, the accounting department needs the right tools to most efficiently do their job. Read this white paper to understand the 10 essentials of a complete financial management system and how the right solution can help you keep up with the rapidly changing business world.

  • Event Date: April 15, 2014 The ability to effectively set sales goals, assign quotas and territories, bring new people on board and quickly make adjustments to the sales force is often crucial to success--and to the field experience! But for sales operations leaders, managing the administrative processes, systems, data and various departments to get it all right can often be difficult, inefficient and manually intensive. Register for this webinar and learn how you can: Align sales goals, quotas and …

Most Popular Programming Stories

More for Developers

Latest Developer Headlines

RSS Feeds