2

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?

Barmak Shemirani
  • 30,904
  • 6
  • 40
  • 77
Andrew Truckle
  • 17,769
  • 16
  • 66
  • 164

3 Answers3

4

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.

Andrew Truckle
  • 17,769
  • 16
  • 66
  • 164
  • 2
    This worked well for me, but I didn't have a m_pNavigationControl or m_lblResize. I got rid of those lines, and everything seemed to work fine. Thanks a lot! – kindrobot Jun 28 '21 at 12:56
  • 1
    Dunno if it was the case when this answer was written, but MFC (as of v14.16.27023, perhaps earlier) has essentially the same code implemented in `CPropertySheet::HandleInitDialog` (see `dlgprop.cpp`), which is a handler for `WM_INITDIALOG`. It is so similar that one or the other of you must have copied the other. :-) The trick is that `HandleInitDialog` only sets up dynamic layout if the result of `GetDynamicLayout` is non-NULL, and this handler is always called before your derived class's `WM_INITDIALOG` handler, so you need to call `EnableDynamicLayout(TRUE)` in your ctor or somewhere early – Cody Gray - on strike May 19 '23 at 10:13
  • @CodyGray Don’t remember what I coded 5 years ago? I’m over 50 now. – Andrew Truckle May 19 '23 at 11:12
2

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;
}
Barmak Shemirani
  • 30,904
  • 6
  • 40
  • 77
  • Cool. I tweaked your code for `DoModal` based on mine. Ofcourse, the sheet is lacking the maximize, minimise and restore buttons. And it lacks the limiting of the size of the window. And I need to add the anchor again. For my `CResizingDiaog` I was adding the anchor to the dynamic layout, Have to see what I can do here. But those are other issues. I will look at your links too. – Andrew Truckle Jun 20 '18 at 20:37
  • That looks better, thanks. So the only outstanding thing is if I can add my resize icon. I do it like this for dialogs: https://pastebin.com/ai1K8mg1 – Andrew Truckle Jun 20 '18 at 21:26
  • They managed to add the anchor here: http://www.ucancode.net/Visual_C_Source_Code/Visual-C-Sample-Resize-dialog-Resize-Property-Sheet-Resize-Property-Page-CPropertySheet-CPropertyPage.htm Just a pity we can't use `GetDynamicLayout`. – Andrew Truckle Jun 20 '18 at 21:50
  • I tried: https://www.dropbox.com/s/e9527bglygmo7ce/MyPropertySheet.zip?dl=0 But whilst it looks good initially, when I redraw it goes funny. – Andrew Truckle Jun 20 '18 at 22:12
  • 1
    The method `CMyPropertySheet::OnSize` note the part that says "override" - ps, I deleted some earlier comments because this was getting too busy – Barmak Shemirani Jun 21 '18 at 15:28
  • Sorted. :) Thanks. – Andrew Truckle Jun 21 '18 at 16:10
1

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.

Andrew Truckle
  • 17,769
  • 16
  • 66
  • 164
thomiel
  • 2,467
  • 22
  • 37