Dynamically creating CFont to fit in CRect area??

What is the best way to resize a CFont to fit in a given area of my Custom Control?  The cx and cy of the control both change and have to be taken into account.  I guess the best way to explain, is using a CRect, I want my text to scale so it always fits in the CRect; top to bottom, left to right.  I know how to tie the CFont height variable to  CRect.Height() but I also need to take into accont the Width().  Anyway... There must be an easy way to accomplish my goal that I am not seeing.  All suggestions welcome and code samples greatly appreciated.

-Michael
SurferAsked:
Who is Participating?

Improve company productivity with a Business Account.Sign Up

x
 
DanRollinsConnect With a Mentor Commented:
Hey Surfer,
I worked a LONG TIME to create that perfect solution for you.  Why have you not responded?

-- Dan
0
 
AlexNekCommented:
2 Surfer
AFAIK it is not possible to "fill exact" any rectangle with font. But for kerning emulation you can try to use char by char output. Or try to use RichEdit from V2.0
0
 
jkrCommented:
You could check the actual size of the text you want to place in the rect using 'GetTextExtentPoint32()' - however, I am not aware that there is a more comfortable "other way round"...
0
Keep up with what's happening at Experts Exchange!

Sign up to receive Decoded, a new monthly digest with product updates, feature release info, continuing education opportunities, and more.

 
DanRollinsCommented:
This code seems to work.  All it does is keep trying smaller and smaller versions of the font until the text fits.  So you can easily end up with a font that is too 'short' just so that its width fits in the box.  There is *no* command that will produce a 'tall,skinny' font from a regular font to handle that situation.  

(However, one idea would be to print tht text to the DC, capture a bitmap of it, then use StretchDIBits to generate one that was 'just right' then display that bitmap -- instead of the actual text.

IMPORTANT: You will need to add some error checking to the code below; it can easily get into an infinte loop.
During testing, I found that the font was staying the same size because the parent dialog's font was MS Sans Serif -- a non TrueType font.  

I am having to release the DC becasue I was working with a EDIT window which as the CS_PARENTDC  class bit.

CFont gcFont;

void CD03Dlg::OnButton1()
{
     CString   sText;
     LOGFONT   rLF;
     CRect     rc;
     CSize     cSz;

     m_ctlEdit.GetWindowText( sText );

     CFont* pFont= m_ctlEdit.GetFont();
     pFont->GetLogFont( &rLF );
     
     m_ctlEdit.GetWindowRect( &rc );

     CDC*   pDC=      m_ctlEdit.GetDC();
     CFont* pOldFont= pDC->SelectObject( pFont );

     while ( 1 ) {
          cSz=  pDC->GetTextExtent( sText );
          if ( cSz.cx <= rc.Width() && cSz.cy <= rc.Height() ) {
               pDC->SelectObject( pOldFont );
               break;
          }
          rLF.lfHeight += (rLF.lfHeight > 0 ? -1: 1);
          gcFont.DeleteObject();
          BOOL fRet= gcFont.CreateFontIndirect( &rLF );

          pDC->SelectObject( &gcFont );
     }
     pDC->SelectObject( pOldFont );
     m_ctlEdit.ReleaseDC( pDC );
     
     m_ctlEdit.SetFont( &gcFont, TRUE );
     m_ctlEdit.Invalidate();
}

0
 
SurferAuthor Commented:
(However, one idea would be to print tht text to the DC, capture a bitmap of it, then use StretchDIBits
to generate one that was 'just right' then display that bitmap -- instead of the actual text.

This sounds interesting.  Can you please give me a code sample?

-Michael
0
 
SurferAuthor Commented:
(However, one idea would be to print tht text to the DC, capture a bitmap of it, then use StretchDIBits
to generate one that was 'just right' then display that bitmap -- instead of the actual text.

This sounds interesting.  Can you please give me a code sample?

-Michael
0
 
DanRollinsCommented:
This works beautifully.  I've outfdone myself here!
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

BOOL TextToBitmap(  LPCSTR szText, CFont* pcFont, CRect* prcDest, CBitmap* pcBmpDest )
{
     CBitmap     cBmpCanvas;
     CWindowDC     dcWin( AfxGetMainWnd() );
     CDC           memSrcDC;
     CDC           memDestDC;

     pcBmpDest->DeleteObject();
     
     memSrcDC.CreateCompatibleDC( &dcWin );

     CFont*   pOldFont=      memSrcDC.SelectObject( pcFont );

     CSize cszSrc= memSrcDC.GetTextExtent( szText, strlen(szText) );

     cBmpCanvas.CreateCompatibleBitmap( &dcWin, cszSrc.cx, cszSrc.cy );

     CBitmap* pOldSrcBitmap= memSrcDC.SelectObject( &cBmpCanvas );

     CRect rcCanvas( CPoint(0,0), cszSrc );
     BOOL fRet= memSrcDC.ExtTextOut( 0,0, ETO_OPAQUE, &rcCanvas, szText, strlen(szText), 0 );

     //------------- now bmpCanvas has the 'raw' image
     //------------- stretch that to fit desired rectangle

     memDestDC.CreateCompatibleDC( &dcWin );

     pcBmpDest->CreateCompatibleBitmap( &dcWin, prcDest->Width(), prcDest->Height() );
     CBitmap* pOldDestBitmap= memDestDC.SelectObject( pcBmpDest );

     memDestDC.SetStretchBltMode( HALFTONE ); // looks good!
     memDestDC.SetBrushOrg(0,0);
     
     memDestDC.StretchBlt(
          0,0, prcDest->Width(), prcDest->Height(),
          &memSrcDC,
          0,0,  cszSrc.cx,cszSrc.cy,
          SRCCOPY
     );

     memSrcDC.SelectObject( pOldSrcBitmap );
     memSrcDC.SelectObject( pOldFont );

     memDestDC.SelectObject( pOldDestBitmap );

     return( TRUE );
}

//--------------------------------- example test
// it takes test fome an edit box, generates a bitmap, and sets it into a CStatic.

void CD03Dlg::OnButton1()
{
     CRect rcDest(   0,0, 100, 20 );

     static CBitmap cBmp; // must persist so that SetBitmap, below won't croak

     CFont cFont;
     cFont.CreatePointFont( 120, "Arial" );

     CString sText;
     GetDlgItemText( IDC_EDIT1, sText );

     BOOL fRet= TextToBitmap( sText, &cFont,  &rcDest, &cBmp );

     m_ctlBmpDisplay.SetBitmap( (HBITMAP)cBmp.m_hObject );
}
0
 
SurferAuthor Commented:
Because I have been EXTREMELY busy working on a couple other projects.  Your solution was indeed a very elegant approach that I think will do the trick.  Thanks for your time and patients!
0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

All Courses

From novice to tech pro — start learning today.