Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Resizable dialogs, form views and property sheets for WTL

0.00/5 (No votes)
7 Jul 2002 1  
Implementation of resizable dialogs, form views and property sheets for WTL

Resizable Form View

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[];
    };	
    

    Setting the layout constraints

    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:

      No constraints

    • 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:

      AttachForm(ATTACH_RIGHT)

      And the following code:
      	AttachForm(IDC_1, ATTACH_LEFT);
      	AttachForm(IDC_1, ATTACH_RIGHT);
      
      will have the following effect:

      AttachForm(ATTACH_LEFT & ATTACH_RIGHT)

      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:

      AttachForm(ATTACH_HCENTER)

    • 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:

      AttachOppositeForm(ATTACH_LEFT)

    • 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:

      AttachWidget

    • 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:

      AttachOppositeWidget

      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:

      AttachOppositeWidget(ATTACH_HCENTER)

    • 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:

      AttachPosition

    Avoiding screen flickering

    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 .

    License