dcsimg

A resizable property sheet within a view

WEBINAR:
On-Demand

Desktop-as-a-Service Designed for Any Cloud ? Nutanix Frame


I have an SDI application, where the main view consists of a CTabCtrl. In order to avoid handling the page changes myself, I decided to try to use a CPropertySheet instead. This gave me some problems handling resizing of the property sheet, when the user resizes the view.
Microsoft Knowledge Base article Q143291 gave a partial answer: How to resize the CPropertySheet at startup.

I tried to manipulate the code from Q143291 so it did what I wanted. And it worked! It flickers quite a lot though, but it is good enough for me.

Please study Q143291 as well. You may find a better way of doing this. All the resizing stuff is in the subclassed CPropertySheet. And that is kind of neat, IMHO.

I have moved most of the stuff from OnInitDialog into Resize, and added
	pParent = GetParent();
	pParent->GetClientRect(&rectParent);
to the subclassed CPropertySheet Resize. The rest of the CPropertySheet stuff is from Q143291. The view stuff is mine.

Note that I don't use OK / Cancel / Apply buttons. It should be a trivial matter to move these buttons in OnInitDialog as well. You can see how to do this in Q143291.

How do you implement a resizable property sheet within a view? Check this:
1. Subclass CPropertySheet.
2. Use only one constructor:

CResizablePropertySheet::CResizablePropertySheet(CWnd* pParentWnd)
	:CPropertySheet(AFX_IDS_APP_TITLE, pParentWnd)
{
	// AddPage here
}
3. Add protected CRect m_rectPage.
4. Create public member Resize():
void CResizablePropertySheet::Resize()
{
	// Find parent
	CWnd* pParent;
	CRect rectParent;

	pParent = GetParent();
	if (pParent == NULL)
		{
		AfxMessageBox("Cannot resize property sheet. Sheet has no parent", MB_ICONEXCLAMATION | MB_OK | MB_APPLMODAL);
		return;
		}

	// Get parents client area
	pParent->GetClientRect(&rectParent);

	// Resize the sheet
	// First find relative change
	CSize sizeRelChange;
	CRect rectWindow;

	GetWindowRect(&rectWindow);
	ScreenToClient(&rectWindow);
	sizeRelChange.cx = rectWindow.Width() - rectParent.Width();
	sizeRelChange.cy = rectWindow.Height() - rectParent.Height();

	rectWindow.right -= sizeRelChange.cx;
	rectWindow.bottom -= sizeRelChange.cy;
	// Then resize the sheet
	MoveWindow(&rectWindow);

	// Resize the CTabCtrl
	CTabCtrl* pTab = GetTabControl();
	ASSERT(pTab);
	pTab->GetWindowRect(&rectWindow);
	ScreenToClient(&rectWindow);
	rectWindow.right -= sizeRelChange.cx;
	rectWindow.bottom -= sizeRelChange.cy;
	pTab->MoveWindow(&rectWindow);

	// Resize the active page
	CPropertyPage* pPage = GetActivePage();
	ASSERT(pPage);
	// Store page size in m_rectPage
	pPage->GetWindowRect(&m_rectPage);
	ScreenToClient(&m_rectPage);
	m_rectPage.right -= sizeRelChange.cx;
	m_rectPage.bottom -= sizeRelChange.cy;
	pPage->MoveWindow(&m_rectPage);
}
5. Overload OnInitDialog:
BOOL CResizablePropertySheet::OnInitDialog() 
{
	BOOL bResult = CPropertySheet::OnInitDialog();

	Resize();

	return bResult;
}

6. Define user-defined message WM_RESIZEPAGE (WM_USER + 111 or something). Add ON_MESSAGE(WM_RESIZEPAGE, OnResizePage) to the message map. Remember to define afx_msg LRESULT OnResizePage(WPARAM wParam, LPARAM lParam) in the header file. OnResizePage:

LONG CResizablePropertySheet::OnResizePage(UINT, LONG)
	{
	// Resize the page using m_rectPage, which was set in
	// Resize().
	CPropertyPage* pPage = GetActivePage();
	ASSERT(pPage);
	pPage->MoveWindow(&m_rectPage);

	return 0;
	}

7. Handle ID_APPLY_NOW (add ON_COMMAND(ID_APPLY_NOW, OnApplyNow) to the message map. Remember to define afx_msg void OnApplyNow() in the header file).
OnApplyNow:

void CResizablePropertySheet::OnApplyNow()
	{
	// The sheet resizes the page whenever the apply button is clicked.
	// So we need to resize it to what we want.
	PostMessage(WM_RESIZEPAGE);
	}
8. Overload OnNotify:
BOOL CResizablePropertySheet::OnNotify(WPARAM wParam, LPARAM lParam, LRESULT* pResult) 
{
	NMHDR* pNMHDR = (LPNMHDR) lParam;
	
	// The sheet resizes the page whenever it is activated
	// so we need to resize it to what we want
	if (pNMHDR->code == TCN_SELCHANGE)
		// user-defined message needs to be posted, not sent, because
		// page must be resized after TCN_SELCHANGE has been processed.
		PostMessage(WM_RESIZEPAGE);

	return CPropertySheet::OnNotify(wParam, lParam, pResult);
}
9. Add private member
CResizablePropertySheet* m_pResizablePropertySheet;

to your CView-derived class. Initialize this member to NULL in the constructor.
10. Override OnInitialUpdate in your CView-derived class:

void CResizableView::OnInitialUpdate() 
	{
	CView::OnInitialUpdate();

	// create the property sheet
	m_pResizablePropertySheet = new CResizablePropertySheet(this);
	if (!m_pResizablePropertySheet->Create(this, 
		WS_CHILD | WS_VISIBLE, 0))
		{
		TRACE("Cannot create property sheet!\n");
		delete m_pResizablePropertySheet;
		m_pResizablePropertySheet = NULL;
		return;
		}
	}
11. Handle WM_SIZE in your CView-derived class:
void CResizableView::OnSize(UINT nType, int cx, int cy) 
	{
	CView::OnSize(nType, cx, cy);

	// Resize property sheet
	if (m_pNetDefPropertySheet != NULL)
		m_pResizablePropertySheet->Resize();
	}

Last updated: 21 July 1998



This article was originally published on August 6th, 1998

Most Popular Programming Stories

More for Developers

RSS Feeds

Thanks for your registration, follow us on our social networks to keep up-to-date