Automatic Dialog Resizing

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:
- Create a dialog resource and position the controls as you wish.
- Make CResizer m_resizer a member of your dialog class.
- Initialize the resizer in OnInitDialog (m_resizer.Init(...)).
- 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
- Make CResizer m_resizer a member variable of your dialog class.
- 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); - Add the following code to the OnSize() handler:
m_resizer.Move();
- Everything should work now.
Some Final Tips
- 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.
- 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.
- If you need to limit minimum or maximum window size, you can handle the WM_GETMINMAXINFO message.
Downloads
Download demo project - 103 KbDownload source - 5 Kb

Comments
Problem with button
Posted by Dasein on 08/27/2007 10:19pmI 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?ReplyMy dialog having ActiveX control
Posted by dino on 07/19/2005 06:10amThis 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?
Replylicense and copyright considerations to use this class
Posted by padmawar on 06/13/2005 10:14amThis 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.
Replylicense and copyright considerations to use this class
Posted by padmawar on 06/13/2005 10:09amThis 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.
ReplySuggested improvement for ovelapping problem
Posted by floppystein on 05/11/2004 08:29pmI 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.-
-
ReplyParent Window Corruption
Posted by Kiarra on 07/20/2005 02:56amI 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
ReplyRe: Original Code & Various improvements
Posted by neauva on 06/25/2004 01:11amThanks to Dmitry for the original code. And also thanks to Andrey and Andrew for improvements which were just what I needed as well!
ReplyAndrey del pozo improvmnet works perfectly and solves the problem
Posted by elloko on 04/02/2004 09:42amI 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,
ReplyAndrey del pozo improvmnet works perfectly and solves the problem
Posted by elloko on 04/02/2004 09:40amI 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,
ReplyAndrey del pozo improvmnet works perfectly and solves the problem
Posted by elloko on 04/02/2004 06:10amI 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,
Replytoo slow when resizing more than 60 control in a dialog...
Posted by elloko on 04/02/2004 05:59amFirst 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,
ReplyWho can help me to use this class with CFormView?
Posted by tsigdz on 03/24/2004 06:38pmThis is a wonderful class. But I don't know how to use it in a CFormView. Does any one can help me with it? Thank you very much. I need it very urgent.
ReplyLoading, Please Wait ...