A resizable property sheet within a view

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

More by Author

Must Read