Automatic Dialog Resizing

WEBINAR: On-demand webcast

How to Boost Database Development Productivity on Linux, Docker, and Kubernetes with Microsoft SQL Server 2017 REGISTER >



Click here for a larger image.

Environment: VC.NET, VC6, Win32, MFC, WTL

Every GUI developer uses dialogs. Sometimes, dialogs should support resizing to make the user's life easier. To create a resizable dialog, you just need to handle a WM_SIZE message and resize/move child controls. But, when a dialog contains many controls, resizing it would be a pain for the developer, and the OnSize function will look like a monster!

When I ran into this problem, I wrote a simple resizer that could help significantly in making resizable dialogs. All you have to do now is:

  1. Create a dialog resource and position the controls as you wish.
  2. Make CResizer m_resizer a member of your dialog class.
  3. Initialize the resizer in OnInitDialog (m_resizer.Init(...)).
  4. Move controls in OnSize simply by calling m_resizer.Move()!

Let's consider the implementation of CResizer class in detail.

The main idea is the following: Each side of a child window (left, top, right, and bottom) is connected to a side of another window, the so-called relative window. The dialog window that owns the children also can be a relative window. When the dialog window is resized, the child window sides are moved after the relative window, thus preserving the connections.

There are several types of connections:

Connection Type Constant Name Description
Fixed CResizer::eFixed Preserves the distance between the side of the child window and the specified side of the relative window
Proportional CResizer::eProportional Preserves the ratio of distance between the side of the child window and left (top) side of the relative window to width (height) of the relative window.
Preserving width CResizer::eWidth An auxiliary connection that preserves the width of the specified child window. It also can be implemented with a fixed connection.
Preserving height CResizer::eHeight An auxiliary connection that preserves the height of the specified child window. It also can be implemented with a fixed connection.

The connections for child windows are specified in a static array of the CResizer::CBorderInfo structures. The format is as follows:

{IDC_CTRL_ID, {(conn type), (rel id), (rel side)}, //Left side
              {(conn type), (rel id), (rel side)}, //Top side
              {(conn type), (rel id), (rel side)}, //Right side
              {(conn type), (rel id), (rel side)}, //Bottom side

Here, (conn type) is one of the connection types listed above, (rel id) is an identifier of the relative window or IDC_MAIN if you want to reference parent dialog, and (rel side) is the side of the relative window to which a connection is bound.

Each child window has four sides, so it has four connections—for left, top, right, and bottom. They are listed subsequently in the CResizer::CBorderInfo initialization above.

Let's consider the connection format (CResizer::CBorder structure) in more detail.

 {(conn type)            , (rel id)    , (rel side)         }

  CResizer::eFixed                       CResizer::eLeft
  CResizer::eProportional  IDC_MAIN      CResizer::eTop
 {CResizer::eWidth       , IDC_CTRL_ID , CResizer::eRight   }
  CResizer::eHeight                      CResizer::eBottom
                                         CResizer::eXCenter
                                         CResizer::eYCenter

A fixed connection can bind the child window side not only to a side of the relative window, but also to its horizontal (CResizer::eXCenter) or vertical (CResizer::eYCenter) center line.

A proportional connection needs only the width or height as relative window side. To specify width, use one of the horizontal sides (eLeft, eRight, or eXCenter); to specify height, use one of vertical sides (eTop, eBottom, or eYCenter).

Connections preserving width or height don't require relative window info. So, there can be any.

Typical Usage

  1. Make CResizer m_resizer a member variable of your dialog class.

  2. Add the following code to OnInitDialog(), replacing the control IDs to your specific ones and adjusting connections as you wish (described above).

    static const CResizer::CBorderInfo s_bi[] = {
     {IDC_CTRL1, {CResizer::eFixed, IDC_MAIN, CResizer::eLeft},   //l
                 {CResizer::eFixed, IDC_MAIN, CResizer::eTop},    //t
                 {CResizer::eFixed, IDC_MAIN, CResizer::eRight},  //r
                 {CResizer::eFixed, IDC_MAIN, CResizer::eBottom}},//b
     {IDC_CTRL2, {CResizer::eFixed, IDC_MAIN, CResizer::eLeft},
                 {CResizer::eFixed, IDC_MAIN, CResizer::eBottom},
                 {CResizer::eFixed, IDC_MAIN, CResizer::eRight},
                 {CResizer::eFixed, IDC_MAIN, CResizer::eBottom}},
    };
    const nSize = sizeof(s_bi)/sizeof(s_bi[0]);
    m_resizer.Init(m_hWnd, NULL, s_bi, nSize);
    
  3. Add the following code to the OnSize() handler:

    m_resizer.Move();
  4. Everything should work now.

Some Final Tips

  1. Resizer resizes controls in the order they are defined in the array, so (rel id) should always be defined (and, therefore, moved by the resizer) before it is used as relative window. Otherwise, resizer ASSERTs.
  2. Windows that are defined earlier in the array have higher priority. When windows have too small a size and child windows overlap, the window with lower priority is hidden.
  3. If you need to limit minimum or maximum window size, you can handle the WM_GETMINMAXINFO message.

Downloads

Download demo project - 103 Kb
Download source - 5 Kb


Comments

  • updates

    Posted by Sharon on 07/04/2012 04:43am

    Are there any updates on this Where can I find the update of Andrey del Pozo? Thanks

    Reply
  • Problem with button

    Posted by Dasein on 08/27/2007 10:19pm

    I have a button IDC_BUTTON3 in the right top corner of the dialog. I added code like this
    
    {IDC_BUTTON3,     {CResizer::eWidth, IDC_MAIN, CResizer::eLeft},
                              {CResizer::eHeight, IDC_MAIN, Resizer::eBottom},
                              {CResizer::eFixed, IDC_MAIN, CResizer::eRight},
                              {CResizer::eFixed, IDC_MAIN, CResizer::eTop}},
    
    After resizing this button disappeared only. Wherein was I wrong?

    Reply
  • My dialog having ActiveX control

    Posted by dino on 07/19/2005 06:10am

    This class is really very useful and easy to use..thnx for that. But I am facing problem when I try to resize my dialog which is containing ActiveX control on it. The ActiveX control is not getting resized when i resize the dialog. What may be the problem?

    Reply
  • license and copyright considerations to use this class

    Posted by padmawar on 06/13/2005 10:14am

    This is a great class to resize the controls. I would like to know are there any license and copyright considerations to use this class. Thanks.

    Reply
  • license and copyright considerations to use this class

    Posted by padmawar on 06/13/2005 10:09am

    This is a great class to resize the controls. I would like to know are there any license and copyright considerations to use this class. Thanks.

    Reply
  • Suggested improvement for ovelapping problem

    Posted by floppystein on 05/11/2004 08:29pm

    I had a problem with my Group boxes hiding the controls they were grouping.
    So, I made the following improvement to allow the option of not doing any hiding,
    which is just what I needed.
    1. Added a bool member variable m_bHideOverlapped and set it to true in the constructor.
    2. Added bool parameter bHideOverlapped to the Init() method, defaulted to true, and simply
    copied it to the member variable.
    3. In Andrey Del Pozos version of the MoveAndHideOverlapped() method, I bypassed the
    section which checked for overlapping if bHideOverlapped is false:
      
      :
      :
      CRectInfo &riSlave = m_vRectInfo[i];
      if (m_bHideOverlapped)
      {
        for(int j=0; j<i j++){
          const CRectInfo &riMaster = m_vRectInfo[j];
          if(riMaster.bVisible && riSlave.bVisible && !riSlave.bHide){ 
            RECT rc;
            ::IntersectRect(&rc, &riMaster.rc, &riSlave.rc);
            riSlave.bHide = !::IsRectEmpty(&rc);
          }
        }
      }
      else
      {
        riSlave.bHide = false;
      }
      :
      :
    
    Works for me. There may be other better ways, and I'd be happy to hear them.

    • Parent Window Corruption

      Posted by Kiarra on 07/20/2005 02:56am

      I discovered that when using a modeless dialog with microsft examples of a tool bar and status window, I had quite a bit of screen corruption, with parts of the dialog appearing as transparent. A cure for this was to to invalidate the parent window after the status bar and tool bar where moved and then call the resizer move. Although this does create a lot of Paint messages, especially as they ripple down through the children, it does cure the problem. Id be grateful if anyone has discovered an better cure for this. But thanks for a great utility

      Reply
    • Re: Original Code & Various improvements

      Posted by neauva on 06/25/2004 01:11am

      Thanks to Dmitry for the original code. And also thanks to Andrey and Andrew for improvements which were just what I needed as well!

      Reply
    Reply
  • Andrey del pozo improvmnet works perfectly and solves the problem

    Posted by elloko on 04/02/2004 09:42am

    I faced a problem when resizing more than 60 controls it was simply too slow thus, I have implemented Andrey del pozo improvement (DeferWindowPos) and now the class rock and rolls. Thanks Guys,

    Reply
  • Andrey del pozo improvmnet works perfectly and solves the problem

    Posted by elloko on 04/02/2004 09:40am

    I faced a problem when resizing more than 60 controls it was simply too slow thus, I have implemented Andrey del pozo improvement (DeferWindowPos) and now the class rock and rolls. Thanks Guys,

    Reply
  • Andrey del pozo improvmnet works perfectly and solves the problem

    Posted by elloko on 04/02/2004 06:10am

    I faced a problem when resizing more than 60 controls it was simply too slow thus, I have implemented Andrey del pozo improvement (DeferWindowPos) and now the class rock and rolls. Thanks Guys,

    Reply
  • too slow when resizing more than 60 control in a dialog...

    Posted by elloko on 04/02/2004 05:59am

    First of all the class is great and very useful. Second, I bump into a problem when resizing for example 60 controls on a dialog. The function SetWindowPos consumes most of the time. It can take several seconds to resize the dialog! Can any one suggest a solution for the problem or a pointer where in the code I need to intervene? Thanks,

    Reply
  • Loading, Please Wait ...

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

Top White Papers and Webcasts

  • As all sorts of data becomes available for storage, analysis and retrieval - so called 'Big Data' - there are potentially huge benefits, but equally huge challenges...
  • The agile organization needs knowledge to act on, quickly and effectively. Though many organizations are clamouring for "Big Data", not nearly as many know what to do with it...
  • Cloud-based integration solutions can be confusing. Adding to the confusion are the multiple ways IT departments can deliver such integration...

Most Popular Programming Stories

More for Developers

RSS Feeds

Thanks for your registration, follow us on our social networks to keep up-to-date