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