I saw this question but the link in the answer is no longer valid.
I also found this which I tried and doesn't work and this.
My task should be simple. I have several pages on a CMFCPropertySheet
and I want to take advantage of the new dynamic resizing features in the IDE. So I set the resizing of the controls and alas, when shown in a sheet there is no ability to resize the sheet/pages.
Trying the above resources has failed.
The header for CMyPropertySheet
:
https://pastebin.com/k8yjhZh7
The source for CMyPropertySheet
:
https://pastebin.com/kxexFPbU
To test I just created a dialog application and added a page and assigned it to this sheet.
I just want to support dynamic resizing with property sheets / pages. What am I missing and is any of this code actually needed any more?
For modeless property sheet:
See this SO link
Resizing a modeless property sheet
For modal property sheet:
How to implement a resizable property sheet
https://www.codeproject.com/Tips/214744/How-to-implement-a-resizable-property-sheet-class
Add WS_THICKFRAME
style to the property sheet window.
int CALLBACK XmnPropSheetCallback(HWND hWnd, UINT message, LPARAM lParam)
{
extern int CALLBACK AfxPropSheetCallback(HWND, UINT message, LPARAM lParam);
// XMN: Call MFC's callback
int nRes = AfxPropSheetCallback(hWnd, message, lParam);
switch(message)
{
case PSCB_PRECREATE:
// Set our own window styles
((LPDLGTEMPLATE)lParam)->style |= (DS_3DLOOK | DS_SETFONT
| WS_THICKFRAME | WS_SYSMENU | WS_POPUP | WS_VISIBLE | WS_CAPTION);
break;
}
return nRes;
}
INT_PTR CMyPropertySheet::DoModal()
{
// Hook into property sheet creation code
m_psh.dwFlags |= PSH_USECALLBACK;
m_psh.pfnCallback = XmnPropSheetCallback;
return CMFCPropertySheet::DoModal();
}
ps, the original article is a little old. This uses m_psh
to access property sheet's parameters.
For resizing:
void CMyPropertySheet::OnSize(UINT nType, int cx, int cy)
{
CPropertySheet::OnSize(nType, cx, cy);
if(!GetActivePage()) return;
if(!GetTabControl()) return;
if(nType == SIZE_MINIMIZED)
return;
int dx = cx - save_rc.Width();
int dy = cy - save_rc.Height();
int count = 0;
for(CWnd *child = GetWindow(GW_CHILD); child; child = child->GetWindow(GW_HWNDNEXT))
count++;
HDWP hDWP = ::BeginDeferWindowPos(count);
for(CWnd *child = GetWindow(GW_CHILD); child; child = child->GetWindow(GW_HWNDNEXT))
{
bool move = false;
//override***
//If you add child controls manually, you want to move not resize
//if(child == &static_control)
//move = true;
CRect r;
child->GetWindowRect(&r);
ScreenToClient(&r);
if(move || child->SendMessage(WM_GETDLGCODE) & DLGC_BUTTON)
{
//move the main buttons and the child controls
r.left += dx;
r.top += dy;
::DeferWindowPos(hDWP, child->m_hWnd, 0, r.left, r.top, 0, 0,
SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
}
else
{
//this must be a child window, resize it
r.right += dx;
r.bottom += dy;
::DeferWindowPos(hDWP, child->m_hWnd, 0, 0, 0, r.Width(), r.Height(),
SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
}
}
::EndDeferWindowPos(hDWP);
GetClientRect(&save_rc);
Invalidate(TRUE);
}
BOOL CMyPropertySheet::OnInitDialog()
{
CPropertySheet::OnInitDialog();
GetClientRect(&save_rc);
GetClientRect(&minimum_rc);
return TRUE;
}
Just in case you are good with a CPropertySheet instead of CMFCPropertySheet, consider using ResizableLib. It includes a class CResizableSheet
that implements a resizable version of CPropertySheet.
Here is an alternative answer that I have come up with. It occured to me that there is no reason at all that we don't use the new dynamic layout features. It is just that the dynamic layout pointer is NULL
to begin with.
If you add the following private method to your derived property sheet class:
void CResizingMFCPropertySheet::SetupDynamicLayout()
{
EnableDynamicLayout(TRUE);
auto pManager = GetDynamicLayout();
if (pManager != nullptr)
{
pManager->Create(this);
// The navigation control only needs to be stretched vertically
pManager->AddItem(m_pNavigationControl->GetSafeHwnd(),
CMFCDynamicLayout::MoveNone(), CMFCDynamicLayout::SizeVertical(100));
// The resize control needs to be moved 100% in both directions
pManager->AddItem(m_lblResize.GetSafeHwnd(),
CMFCDynamicLayout::MoveHorizontalAndVertical(100, 100), CMFCDynamicLayout::SizeNone());
for (CWnd *child = GetWindow(GW_CHILD); child; child = child->GetWindow(GW_HWNDNEXT))
{
if (child->GetSafeHwnd() != m_lblResize.GetSafeHwnd() &&
child->GetSafeHwnd() != m_pNavigationControl->GetSafeHwnd())
{
// All buttons need to be moved 100% in all directions
if (child->SendMessage(WM_GETDLGCODE) & DLGC_BUTTON)
{
pManager->AddItem(child->GetSafeHwnd(),
CMFCDynamicLayout::MoveHorizontalAndVertical(100, 100), CMFCDynamicLayout::SizeNone());
}
else // This will be the main tab control which needs to be stretched in both directions
{
pManager->AddItem(child->GetSafeHwnd(),
CMFCDynamicLayout::MoveNone(), CMFCDynamicLayout::SizeHorizontalAndVertical(100, 100));
}
}
}
}
}
And call it from OnInitDialog
then you do not need any OnSize
event handler and no manual drawing of any kind.