Introduction
First, a few words about the window resizing problem. For example, we have a dialog window with some child controls in it (fig.1).
Fig.1
And we want the following behavior: when the dialog size is changed some of the child controls must change their sizes too. In this example the GroupBox labeled "Static" must have the same spaces from left, top, right and bottom edges of the window and the ListBox must have the same behavior as the GroupBox. "OK" button must stay at the left-bottom corner of the window, "About..." button must stay at the right-bottom corner and the "Cancel" button must stay at the center of the window. Resized dialog is shown in the next picture (fig.2).
Fig.2
There is no simple way to make child controls resize as described above. The most simple method is to handle the WM_SIZE
message and setup every control position in the message handler. This method is good, when the count of controls is not so big. If we have a more complicated dialog then we need some standard methods for description of the controls reposition behavior.
Some time ago I found a perfect library for MFC that helps to design resizable dialog that has no flickering and a very simple description of resize behavior. The library is ResizableLib. It was created by Paolo Messina and you can find it here. I decided to make a port of this library on WTL and here is the result of this work.
WTL also has the implementation of resizing: CDialogResize<>
template, but ResizableLib has more features:
- Anti-flickering support for most part of the controls.
- Support for MinMaxInfo for any window.
- Support for Save/Restore window size and position.
- Support for resizable property sheets and wizards.
- Resizing mechanism can be attached to any window (not just dialogs).
- Simple control behavior description.
- Minimum code needed to make the dialog resizable.
Library content
Files included in this library. |
ResizableDialog.h |
Implementation of resizable dialog. |
ResizableGrip.h |
Implementation of resizable grip control and template for windows that own grip. |
ResizableLayout.h |
Resize layout manager implementation. Handles resizing, child clipping and so on. |
ResizableMinMax.h |
Minimum and maximum window size support. |
ResizablePage.h |
Implementation of resizable property page. |
ResizableSheet.h |
Implementation of resizable property sheet. |
ResizableState.h |
Support for size and position store. |
ResizableMsgSupport.h |
For custom controls we can use messages to determine how it must be clipped and refreshed. |
ResizableVersion.h |
Support file for correctly determining the Windows and shell versions. |
RegisteredMsg.h |
Support file for user registered messages. |
ResizableLib.h |
This file includes all of the above. |
Using the code
If you want to use WTL ResizableLib you must complete the following steps:
- Extract library to a folder named ResizableLib or any other name.
- In your project add library path to include search paths.
- In your stdafx.h insert
#include "ResizableLib.h"
.
- See the next sample of this article to make resizing simple.
There is a small code sample which uses ResizableLib with WTL dialog presented above:
#pragma once
#include <ResizableLib.h>
class CMainDlg:
public CResizableDialogImpl<CMainDlg>,
public CUpdateUI<CMainDlg>,
public CMessageFilter,
public CIdleHandler
{
typedef CResizableDialogImpl<CMainDlg> baseClass;
public:
enum { IDD = IDD_MAINDLG };
virtual BOOL PreTranslateMessage(MSG* pMsg);
virtual BOOL OnIdle();
BEGIN_UPDATE_UI_MAP(CMainDlg)
END_UPDATE_UI_MAP()
BEGIN_MSG_MAP(CMainDlg)
CHAIN_MSG_MAP(baseClass)
MESSAGE_HANDLER(WM_INITDIALOG, OnInitDialog)
COMMAND_ID_HANDLER(ID_APP_ABOUT, OnAppAbout)
COMMAND_ID_HANDLER(IDOK, OnOK)
COMMAND_ID_HANDLER(IDCANCEL, OnCancel)
END_MSG_MAP()
LRESULT OnInitDialog(UINT , WPARAM ,
LPARAM , BOOL& );
LRESULT OnAppAbout(WORD , WORD ,
HWND , BOOL& );
LRESULT OnOK(WORD , WORD wID,
HWND , BOOL& );
LRESULT OnCancel(WORD , WORD wID,
HWND , BOOL& );
};
In the implementation of OnInitDialog
you must add the following lines:
AddAnchor(IDC_S1, TOP_LEFT, BOTTOM_RIGHT);
AddAnchor(IDC_LIST1, TOP_LEFT, BOTTOM_RIGHT);
AddAnchor(IDOK, BOTTOM_LEFT);
AddAnchor(IDCANCEL, BOTTOM_CENTER);
AddAnchor(ID_APP_ABOUT, BOTTOM_RIGHT);
The last step: if you want to save and restore the dialog size and position you must add the following line:
EnableSaveRestore(HKEY_CURRENT_USER, "Software\\AlexTheBoss\\Settings\\",
PLACEMENT_ENT, "MainDlg");
// HKEY_CURRENT_USER: registry root key
// Software\\AlexTheBoss\\Settings\\: your application registry key
// PLACEMENT_ENT: define for windowplacment subkey
// MainDlg: your dialog name for storing placement in registry
That's all you need to make your dialog resizable!
Limitations and problems
- Due to WTL architecture you must manually set
WS_THICKFRAME
in your dialog template.
- Groupboxes still flicker with WinXP themed dialogs.
- With XP themes enabled and if the themed window frame is not rectangle then you can see the invalid window frame while changing the size.
Downloads
To build the demo project create a new folder and extract both the archives in that folder, then open ResizeTest.sln and then build it. Simple demo project contains a very simple dialog resizing sample that you can see in the screenshots above.
In full demo you can see the most powerful features of ResizableLib:
- Resizable dialog with proportional resizing.
- Resizable property sheet and wizard.
- Splitter window with dialog in its right pane.
- Mainframe contains load and save for window placement.
- Mainframe handles MinMaxInfo.
History
- 18th February 2005
- 24th February 2005
WM_NCCALCSIZE
handle in CResizableLayout<T>
bug fixed.
- New big sample added.
- Article updated.