Click here to Skip to main content
Click here to Skip to main content
Go to top

Customizable Window Layouts

, 28 Jul 2008
Rate this:
Please Sign up or sign in to vote.
A class to facilitate user defined dialog and window control layouts.

positionwnd.example.jpg

Description

There are times when it might be useful to provide a user the ability to reorganize the layout of a dialog or window. This submission provides a number of MFC classes which, when compiled into an application, can enable a user to reorganize the layout of controls in the application's dialogs and windows.

Design

We want to give the user the ability to reorganize, at runtime, the layout of a dialog/window. We will accomplish this by using the window subclassing mechanism. Window subclassing essentially allows us to catch and process all of a window's messages before they are dispatched to the original window message handler(s). We will be using window subclassing to catch and process a window's mouse and paint messages. The intercepted mouse messages will be used to toggle the control/window in and out of the layout editing mode and to provide a means to actually edit the control's layout. While in the layout editing mode, the control/window will be highlighted in orange and will have six orange control points to allow the user to configure the control's layout. One control point will be used to move the control. Another control point will be used to size the control. The remaining four control points will be used to specify how the control should be repositioned and resized when its parent window is resized.

We want it to be fairly trivial to include the new layout editing mechanism into existing code. The simplest way to include the new mechanism is to add an object into the dialog or window and have the object "automatically" include all the controls in that dialog or window with one method call on the object - ideally in the OnInitDialog or OnInitializeView handlers. Once the call has been made to subclass the controls, it is up to the user to do the rest.

What good would it be allowing the user to customize a dialog or window layout if we had no way of persisting the user's layout? So, we will add methods to save and load the layout to and from an XML-formatted string. The developer will need to decide how and where the XML-formatted layouts will be stored.

Classes

CPositionWnd

CPositionWnd is the primary class used to subclass and manipulate the layout of dialog or window controls. The CPositionWnd class only exposes a few methods. Ideally, you could include a CPositionWnd object in your dialog or window, and have it recursively subclass all of the controls/windows in the dialog or window, with a single call to SubclassWindowEx. Layout persistence can be achieved with calls to LoadConfigFromString and SaveConfigToString. The methods of interest include:

  • void SubclassWindowEx(CWnd* pWindow = NULL, BOOL bIncludeChildren = TRUE) - This method allows the developer to setup a window for customizable layouts.
  • void LoadConfigFromString(LPCSTR lpszConfig) - This method allows the developer to load the layout for subclassed windows.
  • CString SaveConfigToString(void) - This method allows the developer to save the layout for subclassed windows.

CPositionWndContainer

CPositionWndContainer provides a more flexible way of configuring only specific controls/windows for layout editing. You can create the CPositionWndContainer object and attach specific controls/windows to the object. It will then handle persistence and subclassed layouts for the developer. The methods of interest include:

  • BOOL Create(LPCTSTR lpszWindowName, DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID, CCreateContext* pContext = NULL) - This method creates a window that acts sort-of like a container window. The developer can then attach the customizable controls/windows to the object. When this window is resized, it will update all of its attached windows.
  • void LoadConfigFromString(LPCSTR lpszConfig) - This method allows the developer to load the layout for subclassed windows.
  • CString SaveConfigToString(void) - This method allows the developer to save the layout for subclassed windows.
  • void AttachWindow(CWnd* pWnd, BOOL bIncludeChildren = TRUE) - This method allows a developer to assign various controls/windows to the container.

CPositionWndXMLConfigParser

CPositionWndXMLConfigParser is a worker class that aids CPositionWnd and CPositionWndContainer in the parsing of XML-formatted layouts. The developer should not really need to worry about this class, as it is used internally by CPositionWnd and CPositionWndContainer.

Note: The developer will need to include xmlfile.cpp/.h in their project in order to use the CPositionWndXMLConfigParser class.

Example of Developer Usage

Utilizing the CPositionWnd class is fairly simple. Add a CPositionWnd object to your dialog or window class, and have the object subclass your dialog or window in the OnInitDialog or OnInitializeView method.

BOOL CMyTestDialog::OnInitDialog()
{
    CDialog::OnInitDialog();

    // Attach the position window code to the dialog...
    m_posWnd.SubclassWindowEx(this);

    // Load the persisted lyaout...
    m_posWnd.LoadConfigFromString(m_strLayoutConfiguration);

    // Restore the dialog's layout size...
    int nWidth = m_posWnd.GetLayoutWidth();
    int nHeight = m_posWnd.GetLayoutHeight();
    SetWindowPos(NULL, 0, 0, nWidth, nHeight, SWP_NOMOVE | SWP_NOZORDER);

    return TRUE;
}

Example of User Usage

A user can edit any subclassed control by holding the Ctrl key and clicking the right mouse button. Once in layout edit mode, the control will be highlighted in orange, and will have six orange control points.

positionwnd.controlineditmode.jpg

The control point in the upper-left corner of the control is the move control point. If the user hovers over the move control point, the cursor will change to a move cursor. The user can left mouse button click and hold the control point to move the control to another location.

positionwnd.movingcontrol.jpg

The control point in the lower-right corner of the control is the size control point. If the user hovers over the size control point, the cursor will change to a sizing cursor. The user can left mouse button click and hold the control point to change the size of the control.

positionwnd.sizecontrol.jpg

The control points to the right and below the move control point dictate how the control should behave when its parent is resized. When checked-on, they essentially anchor/dock the top and/or left side(s) of the control to the location where the user placed the control - relative to the parent window's top and left sides.

The control points to the left and above the size control point dictate how the control should behave when its parent is resized. When checked-on, they essentially anchor/dock the bottom and/or right side(s) of the control to the location where the sized control is - relative to the parent window's bottom and right sides.

Using different combinations of the anchor/docking control points, the user is given a certain amount of control over how the control will reposition and resize with a change in the parent window's size.

The user can right mouse button click the control, while it is in layout edit mode, to get access to a menu that can aid the user in the layout. For example, some controls have child controls that obscure the parent control. Once you toggle the child control for layout editing, right mouse button click the control and use the "Select Parent" menu option to put the parent into layout editing mode.

Caveats

There are times when a control in layout mode might leave "tracers" behind when being moved. A repaint of the parent will clean-up the tracers, but it is an issue that needs to be addressed.

It is possible to move a control outside of the parent window's visible range and lose access to the move control point. Another issue that will need to be addressed.

Some controls may have borders, frames, scrollbars, etc., that throw-off the returned size of the control, and it can make it challenging to position the said controls.

The time required for becoming proficient at setting-up a layout might be long, depending on the user.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Roland Trainor
Software Developer (Senior)
United States United States
No Biography provided

Comments and Discussions

 
GeneralMy vote of 5 PinmemberDean Wyant3-Aug-13 9:04 
QuestionIs an updated version available? PinmemberDean Wyant3-Aug-13 9:02 
Generalgreat works! Pinmembermaninthewind2-Dec-09 0:26 
GeneralB-E-A-U-TIFUL Pinmemberitskumaranand24-Sep-09 23:02 
GeneralPerfect PinmemberExtruder29-Jul-08 4:40 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web01 | 2.8.140926.1 | Last Updated 28 Jul 2008
Article Copyright 2008 by Roland Trainor
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid