Click here to Skip to main content
15,886,199 members
Articles / Desktop Programming / WTL

WTL Wizard-style CPropertySheet Resizable View

Rate me:
Please Sign up or sign in to vote.
4.86/5 (3 votes)
10 Apr 20022 min read 69.8K   2.4K   20  
How to use WTL's CPropertySheet implementation in wizard-style as a resizable view instead of a modal or modeless dialog
// WizView.h : interface of the CWizView resizable propertysheet class
//
// Contents:
//
// 1. CWizTabCtrl - subclass for the wizard propertysheet tab control
// 2. CWizView - resizable wizard-style property sheet usable as a view
//
// Copyright 2002 by SoftGee
//////////////////////////////////////////////////////////////////////////////

#if !defined(AFX_WIZVIEW_H__A312271D_3926_11D6_B652_0048548B09C5__INCLUDED_)
#define AFX_WIZVIEW_H__A312271D_3926_11D6_B652_0048548B09C5__INCLUDED_

#pragma once

#include "WizPage.h"
#include "bmpbtn.h"

// forward declaration
class CWizView;

// wizard static controls
#define ATL_IDC_STATIC1 0x3026 // lower, WIZ and WIZ97
#define ATL_IDC_STATIC2 0x3027 // upper, WIZ97 only

/////////////////////////////////////////////////////////////////////////////
// CWizTabCtrlImpl - implements a wizard propertysheet tab control subclass

// user defined message sent when property page needs resizing
#define WM_RESIZEPAGE WM_USER + 111

template <class T, class TBase = CTabCtrl>
class ATL_NO_VTABLE CWizTabCtrlImpl : public CWindowImpl< T, TBase >
{
public:
	BOOL SubclassWindow(HWND hWnd)
	{
		// subclass the propertysheet tab control window
		return CWindowImpl< T, TBase >::SubclassWindow(hWnd);
	}

	BEGIN_MSG_MAP(CWizTabCtrlImpl)
		MESSAGE_HANDLER(WM_WINDOWPOSCHANGING, OnWindowPosChanging)
		MESSAGE_HANDLER(WM_WINDOWPOSCHANGED, OnWindowPosChanged)
		MESSAGE_HANDLER(TCM_SETCURSEL, OnSetCurSel)
		MESSAGE_HANDLER(WM_RESIZEPAGE, OnResizePage)
	END_MSG_MAP()

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

		// limit maximum tab height to 0
		if (lpWP->cy > 0) lpWP->cy = 0;

		return 0;
	}

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

		// SEND resize message to ourselves with the new tab width
		::SendMessage(m_hWnd, WM_RESIZEPAGE, 0, lpWP->cx);

		return 0;
	}

	LRESULT OnSetCurSel(UINT, WPARAM, LPARAM, BOOL& bHandled)
	{
		// get the tab control client rect
		RECT rc;
		GetClientRect(&rc);

		// POST resize message to ourselves with the tab width
		::PostMessage(m_hWnd, WM_RESIZEPAGE, 0, rc.right);

		// further default processing is required to handle the tab 
		// change, so set bHandled to false
		bHandled = false;

		return 0;
	}

	LRESULT OnResizePage(UINT, WPARAM, LPARAM lParam, BOOL&)
	{
		// initialize a property sheet variable with the parent's handle
		CWizView sheet;
		sheet.m_hWnd = GetParent();

		// create a lower bound for the property page just above
		// the lower static control
		RECT rc;
		CStatic st = sheet.GetDlgItem(ATL_IDC_STATIC1);
		st.GetWindowRect(&rc);
		sheet.ScreenToClient(&rc);
		int nBottom = rc.top - 15;

		// adjust lower bound if WIZARD97 style
		DWORD dwFlags = sheet.GetPshStyle();
		dwFlags |= PSH_WIZARD97;
		if (dwFlags == sheet.GetPshStyle())
			nBottom -= 60;

		// set the size of the active property page to the tab 
		// control's new client area width and slightly above
		// the lower static control and wizard buttons
		::SetWindowPos(sheet.GetActivePage(), NULL,
						0, 0, lParam, nBottom, 
						SWP_NOMOVE | SWP_NOZORDER);

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

		return 0;
	}
};

class CWizTabCtrl : public CWizTabCtrlImpl<CWizTabCtrl>
{ };

/////////////////////////////////////////////////////////////////////////////
// CWizView - resizable wizard-style property sheet usable as a view

class CWizView : public CPropertySheetImpl<CWizView>,
					public CDialogResize<CWizView>
{
public:
	// property pages. Pass in dialog and control resource IDs
	CWizPage<IDD_PAGE0, IDC_EDIT0> m_page0;
	CWizPage<IDD_PAGE1, IDC_FRAME1> m_page1;

	// tab control variable
	CWizTabCtrl m_tab;

	BOOL PreTranslateMessage(MSG* pMsg)
	{
		pMsg;
		return FALSE;
	}

	// constructor. At least one page must be added before window is created
	CWizView()
	{
		// disable Apply button, set Wizard style
		m_psh.dwFlags |= PSH_NOAPPLYNOW | PSH_WIZARD97 | PSH_WIZARDHASFINISH;

		// title must be set before page is added
		m_page0.SetTitle("Zero");
		AddPage(m_page0);

		m_page1.SetTitle("One");
		AddPage(m_page1);

		SetActivePage(0);
	}

	// override the callback procedure and add a pre-creation message
	// handler so that we can change the window style
	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
			return CPropertySheetImpl<CWizView>::PropSheetCallback(hWnd, uMsg, lParam);
	}

	// add button handlers and chain both inherited message maps
	BEGIN_MSG_MAP(CWizView)
		COMMAND_ID_HANDLER(ID_WIZBACK, OnBack)
		COMMAND_ID_HANDLER(ID_WIZNEXT, OnNext)
		COMMAND_ID_HANDLER(IDCANCEL, OnCancel)
		COMMAND_ID_HANDLER(ID_WIZFINISH, OnFinish)
		CHAIN_MSG_MAP(CPropertySheetImpl<CWizView>)
		CHAIN_MSG_MAP(CDialogResize<CWizView>)
	END_MSG_MAP()

	// add the tab control and buttons to the resize map. Tab must
	// be last because it handles property page sizing and uses the
	// lower static control's position as an input
	BEGIN_DLGRESIZE_MAP(CWizView)
		DLGRESIZE_CONTROL(ID_WIZBACK, DLSZ_MOVE_X | DLSZ_MOVE_Y)
		DLGRESIZE_CONTROL(ID_WIZNEXT, DLSZ_MOVE_X | DLSZ_MOVE_Y)
		DLGRESIZE_CONTROL(IDCANCEL, DLSZ_MOVE_X | DLSZ_MOVE_Y)
		DLGRESIZE_CONTROL(ID_WIZFINISH, DLSZ_MOVE_X | DLSZ_MOVE_Y)
		DLGRESIZE_CONTROL(ATL_IDC_STATIC1, DLSZ_SIZE_X | DLSZ_MOVE_Y)
		DLGRESIZE_CONTROL(ATL_IDC_STATIC2, DLSZ_SIZE_X)
		DLGRESIZE_CONTROL(ATL_IDC_TAB_CONTROL, DLSZ_SIZE_X | DLSZ_MOVE_Y)
	END_DLGRESIZE_MAP()

	// Since WTL's CPropertySheet does not receive a WM_INITDIALOG message,
	// this needs to be called to handle the remaining initialization tasks
	LRESULT _Init(HWND hwndParent)
	{
		SetParent(hwndParent);

		// remove dialog modal frame, set client edge style
		ModifyStyleEx(0, WS_EX_CLIENTEDGE);

		// initialize the resize code
		DlgResize_Init(false, false, 0);

		// subclass the property sheet tab control
		m_tab.SubclassWindow(GetTabControl());

		return 0;
	}

	// button handlers
	LRESULT OnBack(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& bHandled)
	{
		// TODO: add code for desired action on Back click
		bHandled = false;
		return 0;
	}
	LRESULT OnNext(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& bHandled)
	{
		// TODO: add code for desired action on Next click
		SetWizardButtons(PSWIZB_BACK | PSWIZB_NEXT | PSWIZB_FINISH);
		bHandled = false;
		return 0;
	}
	LRESULT OnCancel(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/)
	{
		// TODO: add code for desired action on Cancel click

		return 0;
	}
	LRESULT OnFinish(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/)
	{
		// TODO: add code for desired action on Finish click

		return 0;
	}

	// propertysheet style getter
	DWORD GetPshStyle()
	{
		return m_psh.dwFlags;
	}
};

#endif // !defined(AFX_PROPVIEW_H__A312271D_3926_11D6_B652_0048548B09C5__INCLUDED_)

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

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