Click here to Skip to main content
Click here to Skip to main content

Calculating a Rich Edit Control Minimum Size

By , 1 Dec 1999
 

This explains a technique to calculate the minimum size that's required by a Rich Edit Control to fully display all its contents. The Rich Edit Control already has what's called a "bottomless" behavior, but as we'll see, it's doesn't solve the problem of calculating the optimal "width".

Your application can resize a Rich Edit Control (CRichEditControl) as needed, so that the control is always the same height as its contents. This is what's called a "bottomless" behavior. The CRichEditControl supports it by sending its parent window a EN_REQUESTRESIZE notification whenever the height of its contents changes.

When processing the EN_REQUESTRESIZE notification the parent window should resize the control to the dimensions in the specified REQRESIZE structure. Of course the parent window should also move any graphical element near the control to open room for the control's change in height.

In order to activate the EN_REQUESTRESIZE notification, the application must set the ENM_REQUESTRESIZE event flag of the control's event mask. The application can also "force" the control to send a EN_REQUESTRESIZE notification by calling the control's RequestResize member function. For example, the following code does that:


   // m_Ctrl is a CRichEditCtrl object

   // Set the ENM_REQUESTRESIZE event flag
   m_Ctrl .SetEventMask( ENM_REQUESTRESIZE );

   // Force the control to issue a EN_REQUESTRESIZE notification
   m_edCtrl.RequestResize( );

In the EN_REQUESTRESIZE handler, the parent window can use CWnd::SetWindowPos or CWnd::MoveWindow to resize the control.

This mechanism works very well, but for one detail. It works only to adjust the "height" of the control, not its "width". The point is that the control can always solve problems of width by word breaking lines, thus turning it again in a "height" problem. Yet, this is automatic and there's nothing you can do to prevent this behavior. You can change the right margin (CRichEditCtrl::SetRect), but you can't ask the control what's the optimal value for the width.

Now, suppose you have very short single line paragraphs that you really want to display unbroken. Yet, you would like the control to not waste horizontal real state, and to be as narrow as the wider text line - no one single pixel wider (for an example of a UI that has such requirements, take a look in my TCX Message Box class).

Well, with the CRichEditCtrl's normal bottomless behavior you don't get it. If you use a too narrow width, the control will break the text lines. And if you use a too wide width, the UI might look wasting space.

The technique I used in the TCX Message Box class is a "binary search" for the best width. Basically I start by sizing the control to the largest width that I can afford in the UI (in the TCX Message Box that means 1/2 the of the screen width), then I force a EN_REQUESTRESIZE notification and take the required height. This is the minimum height the control needs to show its contents.

All I have to do now is to find the minimum width that still keeps that height. If I set a too small width, the control will break the lines and require a larger height. Since the relation is linear, I can optimize the search with a binary search algorithm.

Here're the code.

   // Calculating the CRichEditCtrl m_Ctrl minimum size

   m_Ctrl.SetEventMask( ENM_REQUESTRESIZE );

   // m_dimRtf is a CSize object that stores m_Ctrl required size

   m_dimRtf.cx = 0;
   m_dimRtf.cy = 0;

   // Performing the binary search for the best dimension

   int cxFirst = 0;
   int cxLast = ::GetSystemMetrics( SM_CXFULLSCREEN ) / 2;
   int cyMin = 0;

   cxLast *= 2;

   do
   {
      // Taking a guess
      int cx = ( cxFirst + cxLast ) / 2;

      // Testing this guess
      CRect rc( 0, 0, cx, 1 );
      m_Ctrl.MoveWindow( rc );
      m_Ctrl.RequestResize();

      // If it's the first time, take the result anyway.
      // This is the minimum height the control needs
      if( cyMin == 0 )
         cyMin = m_dimRtf.cy;

      // Iterating
      if( m_dimRtf.cy > cyMin )
      {
         // If the control required a larger height, then
         // it's too narrow.
         cxFirst = cx + 1;
      }
      else
      {
         // If the control didn't required a larger height,
         // then it's too wide.
         cxLast = cx - 1;
      }
   }
   while( cxFirst < cxLast );

   // Giving it a few pixels extra width for safety
   m_dimRtf.cx += 2;

   // Moving the control
   m_Ctrl.MoveWindow( xMsg, cyTop, m_dimRtf.cx, m_dimRtf.cy );

And, the parent's window EN_REQUESTRESIZE notification handler member function:

   void CParenWindow::OnRequestResize( NMHDR* pNMHDR, LRESULT* pResult )
   {
      _ASSERT( pNMHDR->code == EN_REQUESTRESIZE );

      // Storing the requested sized to be used in the binary search

      REQRESIZE* prr = (REQRESIZE*)pNMHDR;
      m_dimRtf.cx = prr->rc.right - prr->rc.left;
      m_dimRtf.cy = prr->rc.bottom - prr->rc.top;

      *pResult = NULL;
   }

Final Notes

Do note that, in the TCX Message Box class, I do all this calculation and resizing before I actually display the window. Otherwise, it will flick crazily as the application traverses the binary search loop. Therefore, if you need to recalculate the Rich Edit Control size when it's already visible, you must first freeze the parent window redraw, or you should move the Rich Edit Control to outside of the visible area, do all the calculation and, when it's done, you get it back to the visible area.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here

About the Author

Thales P. Carvalho
United States United States
Member
No Biography provided

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
Hint: For improved responsiveness ensure Javascript is enabled and choose 'Normal' from the Layout dropdown and hit 'Update'.
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
GeneralIt is possible to get the widthmemberdomehead15 Jul '08 - 1:56 
GeneralRe: It is possible to get the widthmemberAcidtech8 Mar '10 - 17:41 
GeneralI run your rcxmessagebox sample, the size is not correctmembercode_discuss25 Feb '08 - 14:23 
GeneralGets wrong size sometimes: SolutionmemberPaul S. Vickery4 Mar '05 - 0:22 
GeneralFIX for Windows 2000sussHarold Harkema26 Feb '00 - 4:57 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Permalink | Advertise | Privacy | Mobile
Web02 | 2.6.130516.1 | Last Updated 2 Dec 1999
Article Copyright 1999 by Thales P. Carvalho
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid