Making a CMFCPropertySheet resizable with dynamic

2019-06-07 22:11发布

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?

标签: mfc
3条回答
放我归山
2楼-- · 2019-06-07 22:48

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;
}
查看更多
forever°为你锁心
3楼-- · 2019-06-07 22:58

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.

查看更多
ら.Afraid
4楼-- · 2019-06-07 23:02

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.

查看更多
登录 后发表回答