Introduction
These classes provides an easy way to implement in WTL, resizable windows with layout management of the children. Support is provided for:
- Form views
- Dialogs
- Property Sheet and property pages
Furthermore, support is also provided for using property sheet as child windows.
How to use the classes in your WTL application
Resizeable form views
- Include the file
LayoutMgr.h
in the header file of your dialog class and add the file LayoutMgr.cpp
to your project.
- Derive your form view class from
CResizableFormViewImpl
instead of CDialogImpl
.
- Add the message map of
CResizableFormViewImpl
before your own message handlers.
- Override the
DefineLayout
method in order to set the layout constraints.
- Define the array
_controlsToClip
which defines the controls which should be clipped when painting the dialog.
Your class should look like:
class MyFormView : public CResizableFormViewImpl<MyFormView>
{
public:
typedef CResizableFormViewImpl<MyFormView> dlgBase;
...
BEGIN_MSG_MAP(MyFormView)
CHAIN_MSG_MAP(dlgBase)
...
END_MSG_MAP()
...
virtual void DefineLayout();
static const UINT _controlsToClip[];
};
Resizeable dialogs
Include the file LayoutMgr.h
in the header file of your dialog class and add the file LayoutMgr.cpp
to your project.
Derive your dialog class from CResizableDialogImpl
instead of CDialogImpl
.
Add the message map of CResizableDialogImpl
before your own message handlers.
Override the DefineLayout
method in order to set the layout constraints.
Define the array _controlsToClip
which defines the controls which should be clipped when painting the dialog.
In the call to CResizableDialogImpl
constructor, you can change the value of the flag useHandle
. If this flag
is set to true (default value), a sizing gripper is displayed in the lower right corner of the dialog.
Your class should look like:
class MyDialog : public CResizableDialogImpl<MyDialog>
{
public:
typedef CResizableDialogImpl<MyDialog> dlgBase;
...
BEGIN_MSG_MAP(MyDialog)
CHAIN_MSG_MAP(dlgBase)
...
END_MSG_MAP()
...
virtual void DefineLayout();
static const UINT _controlsToClip[];
};
Resizeable property sheet
- Include the file
LayoutMgr.h
in the header files of your property sheet and property pages classes and add the file LayoutMgr.cpp
to your project.
- For the property sheet:
- If you want to use your property sheet:
- as a popup window:
- Derive your property sheet class from
CPopupResizablePropertySheetImpl
instead of CPropertySheetImpl
.
- In the call to
CPopupResizablePropertySheetImpl
constructor, you can change the value of the flag useHandle
. If this flag
is set to true (default value), a sizing gripper is displayed in the lower right corner of the property sheet.
- as a child window:
- Derive your property sheet from
CChildResizablePropertySheetImpl
instead of CPropertySheetImpl
.
- Pass the ID of the control which will serve as a place holder for the property sheet to the call of the constructor of
CChildResizablePropertySheetImpl
.
- Call the method
Create
in the parent window for creating the property sheet.
- Add the message map of
CPopupResizablePropertySheetImpl
or CChildResizablePropertySheetImpl
before your own message handlers.
- For the property pages:
- Property sheets don't receive any
WM_INITDIALOG
message. If you want to do something just after the initialisation of the property sheet, you can
override the method OnInitDialog
.
Your property sheet class should look like:
class MyPropertySheet : public CPopupResizablePropertySheetImpl<MyPropertySheet>
{
public:
typedef CPopupResizablePropertySheetImpl<MyPropertySheet> dlgBase;
...
BEGIN_MSG_MAP(MyPropertySheet)
CHAIN_MSG_MAP(dlgBase)
...
END_MSG_MAP()
...
};
Your propety page classes should look like:
class MyPropertyPage : public CResizablePropertyPageImpl<MyPropertyPage>
{
public:
typedef CResizablePropertyPageImpl<MyPropertyPage> dlgBase;
...
BEGIN_MSG_MAP(MyPropertyPage)
CHAIN_MSG_MAP(dlgBase)
...
END_MSG_MAP()
...
virtual void DefineLayout();
static const UINT _controlsToClip[];
};
In order to layout the children when the dialog is resized, you must override the DefineLayout
method. This method is called during the initialisation
of the dialog and allow to define the geometrical relationships between the child window which will alow to move and resize them in the desired way.
The way of setting layout constraints is inspired by the methods of the XmForm
widget of Motif (quite old stuff... ).
It's a little tedious, but very simple and efficient.
Constraints are defined by attaching the sides of a child window to the side of another child window or to one of the side of the parent window.
-
By default all the sides of a child window are without any constraint (method
AttachNone
). It means that when the dialog is resized, the child window is neither resized nor moved:
-
A side of a child window can be attach to the same side of the parent window (method
AttachForm
).
For example the following code:
AttachForm(IDC_1, ATTACH_RIGHT);
will have the following effect:
And the following code:
AttachForm(IDC_1, ATTACH_LEFT);
AttachForm(IDC_1, ATTACH_RIGHT);
will have the following effect:
The horizontal or the vertical center of the child window can be attached to the parent window.
For example the following code:
AttachForm(IDC_1, ATTACH_HCENTER);
will have the following effect:
-
A side of a child window can be attach to the opposite side of the parent window (method
AttachOppositeForm
).
For example the following code:
AttachOppositeForm(IDC_1, ATTACH_LEFT);
will have the following effect:
-
A side of a child window can be attach to the opposite side of another child window (method
AttachWidget
).
For example the following code:
AttachForm(IDC_1, ATTACH_HCENTER);
AttachWidget(IDC_2, ATTACH_LEFT, IDC_1);
will have the following effect:
-
A side of a child window can be attach to the same side of another child window (method
AttachOppositeWidget
).
For example the following code:
AttachForm(IDC_1, ATTACH_LEFT);
AttachForm(IDC_1, ATTACH_RIGHT);
AttachOppositeWidget(IDC_2, ATTACH_LEFT, IDC_1);
AttachOppositeWidget(IDC_2, ATTACH_RIGHT, IDC_1);
will have the following effect:
The horizontal or the vertical center of the child window can be attached to the same side of another child window.
For example the following code:
AttachForm(IDC_1, ATTACH_LEFT);
AttachForm(IDC_1, ATTACH_RIGHT);
AttachOppositeWidget(IDC_2, ATTACH_HCENTER, IDC_1);
will have the following effect:
A side of a child window can be attach to an invisible grid which is resized with the parent window (method AttachPosition
).
For example the following code:
SetNPositions(3);
AttachPosition(IDC_1, ATTACH_LEFT, 0);
AttachPosition(IDC_1, ATTACH_RIGHT, 1);
AttachPosition(IDC_2, ATTACH_LEFT, 1);
AttachPosition(IDC_2, ATTACH_RIGHT, 2);
AttachPosition(IDC_3, ATTACH_LEFT, 2);
AttachPosition(IDC_3, ATTACH_RIGHT, 3);
will have the following effect:
When a dialog is resized, the whole client are is filled with the background color, before the child window are painted.
This causes screen flickering.
What's need to be done is to clip the children windows before painting the dialog background.
Dialogs can have the WS_CLIPCHILDREN
window style which ensure that all the dialog children are clipped before painting.
But in most of the cases, it's not possible to use this style because controls like static controls don't paint their background themselves.
To avoid this, the WM_ERASEBKGND
message is handled by all the CResizableXXXImpl
classes. The classes excludes
all the controls which IDs are in the _controlsToClip
array, from the DC used for painting the background. So for avoiding screen flickering,
you just have to "override" the _controlsToClip
array.
Your classes should look like:
class MyDialog : public CResizableDialogImpl<MyDialog>
{
...
static const UINT _controlsToClip[];
};
const UINT MyDialog::_controlsToClip[] =
{
IDC_IMG,
IDOK,
...
0
};
NB
The current code handles incorrectly the clipping of some controls when using Windows XP themes (the problems occur with tab controls and scrolled windows).
Therefore, the automatic clipping of children control is disallowed when using Windows XP
Hosting ActiveX controls
If your dialog hosts ActiveX controls, use:
CAxResizableDialogImpl
instead of CResizableDialogImpl
CAxResizableFormViewImpl
instead of CResizableFormViewImpl
CAxResizablePropertyPageImpl
instead of CResizablePropertyPageImpl
Minimum size of the dialogs
In order to avoid to deal with dialogs of size 10x10 pixels, a minimum size for the dialogs and FormViews is set.
- For dialogs, the minimum size is the size of the dialog template (the size set in the dialog editor). The user is not able to resize the dialog window under this minimum size.
- For FormViews, the minimum size is the size of the dialog template (the size set in the dialog editor). If the user resizes the view under this minimum size, scrollbars are shown.
- For "popup" property sheet, the minimum size is the size of the property sheet just after creation. This size should be the maximum size of the dialog templates of the property pages.
Latest Updates
- 9th July 2002
- Fixed some class name clashes appearing when using WTL7 & ATL7
- Replaced the SizeGrip window by a standard scrollbar as suggested by Daniel Bowen
- Added the
Unattach
methods for removing a control from the list of windows managed by the layout manager
- Added a maximum size. The maximum size information is only used if _maxWindowSize.cx or _maxWindowSize.cy is greater than 0
- Implements a workaround an ATL7 bug which prevents ActiveX controls to be initialised in CAxPropertySheetImpl
- Disabled the clipping code when working with Windows XP
- 7th September 2001
- Added support for hosting ActiveX controls.
- Changed the user messages from arbitrary constants to registered messages
- 22nd May 2001
- Fixed the way minimum sizes and scrollbars are handled in FormViews
Serge
.