Click here to Skip to main content
15,867,141 members
Articles / Desktop Programming / WTL
Article

WTL CPropertySheet as a Resizable View

Rate me:
Please Sign up or sign in to vote.
4.92/5 (8 votes)
31 Mar 20024 min read 101.3K   3.2K   42   7
How to use WTL's CPropertySheet implementation as a resizable view instead of a modal or modeless dialog
CPropertySheet Sample Image  CPropertySheet Sample Image

Introduction

This article describes how to use WTL's CPropertySheetImpl template within a resizable view. An overridden PropSheetCallback changes the property sheet style for use as a view. A subclass of the property sheet's tab control handles resizing of the property pages. The property sheet and property pages use CDialogResize to handle control resizing. CPropertySheetImpl is in the atldlgs.h header file while CDialogResize is in atlframe.h.

Property Sheet

Our new property sheet class, CPropView, inherits from both CPropertySheetImpl and CDialogResize to acquire its desired behavior. The property sheet template provides an encapsulation of the standard Windows property sheet control while the resize template provides a mechanism for moving or resizing child controls.

However, standard property sheets are designed for use as modal or modeless dialog windows, not views. To overcome the default behavior, override the callback procedure and add a pre-creation message handler to change the window style as shown below.

static int CALLBACK PropSheetCallback(HWND hWnd, UINT uMsg, LPARAM lParam)
{ // dialog template is available and changeable pre-creation
  if(uMsg == PSCB_PRECREATE)
  {
    LPDLGTEMPLATE lpDT = (LPDLGTEMPLATE)lParam;

    // remove dialog border styles
    lpDT->style -= DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU;

    // add child window and clipping styles
    lpDT->style |= WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS;

    return 0;
  }
  else // call inherited method to handle PSCB_INITIALIZED
    return CPropertySheetImpl< CPropView >::PropSheetCallback(hWnd, uMsg, lParam); }

One other style change is required to complete the transition from standalone dialog to view but there are two obstacles to overcome. The first obstacle is that the style is an extended style, and it is not possible to change extended styles in precreate. Secondly, the property sheet template does not process the WM_INITDIALOG message, which is where one might also change extended styles.

Therefore, we created an initialization method. This method, _Init, modifies the extended style setting for the property sheet by setting WS_EX_CLIENTEDGE. It also initializes the dialog resize code and subclasses the property sheet's tab control. _Init is called by the main frame's OnCreate() handler just after the view is created.

Tab Control

The Windows property sheet uses an ordinary tab control to host property pages. The tab control identifier is ATL_IDC_TAB_CONTROL. In order to resize the tab control, and subsequently, its property pages, add it to the property sheet resize map as a sizable control. The property sheet buttons, not shown in the example below, are also added to the resize map but as movable controls.

BEGIN_DLGRESIZE_MAP(CPropView)
  DLGRESIZE_CONTROL(ATL_IDC_TAB_CONTROL, DLSZ_SIZE_X | DLSZ_SIZE_Y)
END_DLGRESIZE_MAP()

Once the tab control is placed in the resize map, it will receive sizing messages from the dialog resize code. However, one additional step is required, since the messages are not relayed to the property pages. This is accomplished with a template for the tab control that provides WM_WINDOWPOSCHANGED message handling. Subclass the tab control in the _Init method of the property sheet class, CPropView.

Here is the handler for the position changed message:

LRESULT OnWindowPosChanged(UINT, WPARAM, LPARAM lParam, BOOL&)
{ // get window position structure from lParam
  LPWINDOWPOS lpWP = (LPWINDOWPOS)lParam;

  // initialize a property sheet variable with the parent's handle
  CPropertySheet m_sheet;
  m_sheet.m_hWnd = GetParent();

  // set the size of the active property page to slightly smaller
  // than the tab control's new client area size
  ::SetWindowPos(m_sheet.GetActivePage(), NULL, 0, 0, lpWP->cx - 8,
      lpWP->cy - 25, SWP_NOMOVE);

  // release the property sheet handle since we don't own it
  m_sheet.m_hWnd = NULL;

  return 0; }

Now the tab control resizes the active property page upon notice from the property sheet resize handler. Other property pages are resized when they become active. (Note: If you wish to control the minimum or maximum size that the view or page can reach, see "Sidebar About Window Sizing" later in this article.)

Property Pages

Property pages also inherit from CDialogResize so that their child controls are resized. Although you could override the callback procedure to change the page style, it is simpler to just pass in the appropriate window style to the dialog resize initializer like this:

LRESULT OnInitDialog(UINT, WPARAM, LPARAM, BOOL&)
{ // init resize code. No gripper, no min size tracking, Child window style
  DlgResize_Init(false, false, WS_CHILD | WS_CLIPCHILDREN);
	return 0; }

Add whatever controls or groups of controls you wish to resize or move to the resize map, just as you would for any dialog using the dialog resize class.

Reminders

When working with property sheets and pages, remember:

  • Create at least one property page in the constructor of the property sheet
  • Some parameter changes must occur before the sheet or page is created

Also, please note that groupboxes do not peacefully coexist with the WS_CLIPCHILDREN style. If you intend to use them, remove the clip children style from the property page's DlgResize_Init() and be prepared to suffer some screen flicker.

Sidebar About Window Sizing

There are certain window styles that inherently provide the capability to limit minimum and maximum window size. For example, WS_THICKFRAME and WS_CAPTION. Compound styles that include either or both of those styles, such as WS_OVERLAPPEDWINDOW, provide the capability as well. These styles receive the WM_GETMINMAXINFO message whenever they are moved or sized.

You can enable mimimum (or maximum) size tracking in any window with those styles, such as main frame, by initializing the appropriate member variable in the constructor like this:

POINT m_ptMinTrackSize;

CMainFrame()
{ // initialize minimum size tracking variables
  m_ptMinTrackSize.x = -1;
  m_ptMinTrackSize.y = -1; }

Next, add an entry to the message map for WM_GETMINMAXINFO and add the following message handler:

LRESULT OnGetMinMaxInfo(UINT, WPARAM, LPARAM lParam, BOOL&)
{ if (m_ptMinTrackSize.x != -1 && m_ptMinTrackSize.y != -1)
  {
    LPMINMAXINFO lpMMI = (LPMINMAXINFO)lParam;
    lpMMI->ptMinTrackSize =  m_ptMinTrackSize;
  }
  return 0; }

Finally, set m_ptMinTrackSize.x and m_ptMinTrackSize.y to your desired minimum values in the OnCreate handler.

For window styles that do not inherently support minimum size tracking, use a handler for the WM_WINDOWPOSCHANGING message to achieve similar results, as shown below. Set your x and y track values in the create or initialize handler as appropriate.

LRESULT OnWindowPosChanging(UINT, WPARAM, LPARAM lParam, BOOL&)
{ // get window position structure from lParam
  LPWINDOWPOS lpWP = (LPWINDOWPOS)lParam;

  // don't allow resizing below minimum x
  if (lpWP->cx <= m_ptMinTrackSize.x) lpWP->cx = m_ptMinTrackSize.x;

  // don't allow resizing below minimum y
  if (lpWP->cy <= m_ptMinTrackSize.y) lpWP->cy = m_ptMinTrackSize.y;

  return 0; }

Terms Of Use

The sample project and property sheet/page classes available with this article are free. Use them however you wish.

THIS SOFTWARE IS DISTRIBUTED AS-IS, WITHOUT WARRANTIES OF ANY KIND.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Founder Choycer
United States United States
Ed has over 40 years experience in computer technology and a bachelor's degree in Business Administration. He's currently a marketing technology consultant. During his career, he's led software development departments and created software still in use in the communications and healthcare industries. Ed is a veteran of the United States Army. He lives in Arizona in the United States.

Find Ed on Linkedin.

This material is copyright 2019 by Ed Gadziemski. Unauthorized use is strictly prohibited. All rights reserved.

Comments and Discussions

 
GeneralMy vote of 5 Pin
majid torfi26-Oct-14 5:01
professionalmajid torfi26-Oct-14 5:01 
GeneralAccess the edit control inside the tab Pin
iulikii_026-Apr-06 3:13
iulikii_026-Apr-06 3:13 
GeneralRe: Access the edit control inside the tab Pin
cabbage9822-Jul-09 23:48
cabbage9822-Jul-09 23:48 
GeneralProject Won't Compile Pin
Tim Brooks22-Oct-05 18:14
Tim Brooks22-Oct-05 18:14 
This project doesn't compile with the current WTL library (7.5 (build 5280)).
It doesn't like the template definition in Proppage.h....Numerous related errors:

c:\temp\propviewdemo\proppage.h(11) : error C3203: 'CPropPage' : unspecialized class template can't be used as a template argument for template parameter 'T', expected a real type
c:\temp\propviewdemo\proppage.h(42) : see reference to class template instantiation 'CPropPage<t_wdlgtemplateid,t_ncontrol0>' being compiled

WTL newbie so not really sure how to fix this....
GeneralResizable property sheet Pin
fspafford13-Sep-04 3:46
fspafford13-Sep-04 3:46 
GeneralTab key and accelerator keys Pin
rx73-221-Feb-04 21:56
rx73-221-Feb-04 21:56 
QuestionHow to hide the default buttons &amp; inflate TabCtrl Pin
mango_lier13-Feb-04 10:06
mango_lier13-Feb-04 10:06 

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

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