根据控件的可见性在运行时自定义动态布局

时间:2019-03-27 19:32:44

标签: mfc dialog

我有一个多功能的CDialog,它支持调整大小。它可以显示3种版本的内容。

变化1:

Variation 1

变化2:

Variation 2

变化3:

Variation 3

对话控件正在使用资源编辑器中的动态布局设置。

版本1很好,不需要更改。

版本2不显示组合和日期按钮。因此,我希望“文本将...”标签在底部,“编辑”框在底部。

版本3也存在类似的问题,其中日期按钮应移至底部,而编辑框应更高。

能否通过更改代码中的动态布局来实现?

更新

我在OnInitDialog中尝试过:

if (!m_bShowWeekCombo)
{
    CRect rctCombo;
    m_cbWeek.GetWindowRect(rctCombo);
    ScreenToClient(rctCombo);

    CRect rctNote;
    m_staticInfo.GetWindowRect(rctNote);
    ScreenToClient(rctNote);

    m_staticInfo.MoveWindow(rctCombo.left, rctCombo.top, rctNote.Width(), rctNote.Height());
}

起初我以为它可以正常工作:

Example

注释现在在底部。但是,一旦我调整窗口大小:

Example 2

笔记已恢复到原始位置。

我知道我有一个与此类似的问题answer,但是我真的必须重新构建整个布局吗?

更新2

if (!m_bShowWeekCombo)
{
    CRect rctEdit;
    m_editText.GetWindowRect(rctEdit);
    ScreenToClient(rctEdit);

    CRect rctCombo;
    m_cbWeek.GetWindowRect(rctCombo);
    ScreenToClient(rctCombo);

    CRect rctNote;
    m_staticInfo.GetWindowRect(rctNote);
    ScreenToClient(rctNote);

    //m_staticInfo.MoveWindow(rctCombo.left, rctCombo.top, rctNote.Width(), rctNote.Height());
    m_staticInfo.SetWindowPos(NULL, rctCombo.left, rctCombo.top, 0, 0,
        SWP_NOSIZE | SWP_NOZORDER);
    m_editText.SetWindowPos(NULL, 0, 0, rctEdit.Width(), rctEdit.Height() + (rctCombo.top - rctNote.top),
        SWP_NOMOVE | SWP_NOZORDER);

    if (m_pDynamicLayout)
    {
        if (!m_pDynamicLayout->HasItem(m_staticInfo.m_hWnd))
        {
            m_pDynamicLayout->AddItem(m_staticInfo.m_hWnd,
                CMFCDynamicLayout::MoveVertical(100), CMFCDynamicLayout::SizeHorizontal(100));
        }
        else
        {
            TRACE(L"item already has dynamic move/size\n");
        }
        if (!m_pDynamicLayout->HasItem(m_editText.m_hWnd))
        {
            m_pDynamicLayout->AddItem(m_editText.m_hWnd,
                CMFCDynamicLayout::MoveNone(), CMFCDynamicLayout::SizeHorizontalAndVertical(100, 100));
        }
        else
        {
            TRACE(L"item already has dynamic move/size\n");
        }

    }
}

当我尝试上述操作时,即使对话框已恢复为更宽的对话框宽度,控件的宽度仍是原始宽度。

1 个答案:

答案 0 :(得分:2)

CMFCDynamicLayout读取对话框资源,它存储子控件的坐标及其动态调整大小/移动属性。

这一切都在CDialog::OnInitDialog中完成。如果移动子控件,例如m_staticInfo,则CMFCDynamicLayout不会知道您已移动控件或调整控件的大小。因此,在下一个对话框调整大小请求时,CMFCDynamicLayout使用旧值。

您可以为m_staticInfo以外的所有控件以及您打算手动移动的其他控件添加动态调整大小/移动。然后分别添加m_staticInfo

BOOL CMyDialog::OnInitDialog()
{
    CDialog::OnInitDialog();

    CRect rctCombo;
    m_cbWeek.GetWindowRect(rctCombo);
    ScreenToClient(rctCombo);
    m_staticInfo.SetWindowPos(NULL, rctCombo.left, rctCombo.top, 0, 0, 
        SWP_NOSIZE | SWP_NOZORDER);

    if(m_pDynamicLayout)
    {
        if(!m_pDynamicLayout->HasItem(m_staticInfo.m_hWnd))
        {
            m_pDynamicLayout->AddItem(m_staticInfo.m_hWnd,
                CMFCDynamicLayout::MoveVertical(100), CMFCDynamicLayout::SizeNone());
        }
        else
        {
            TRACE(L"item already has dynamic move/size\n");
            AfxDebugBreak(0);
        }
    }

    return 1;
}

在内部,MFC调用LoadDynamicLayoutResource(m_lpszTemplateName)来初始化动态大小/移动。但是文档说不要直接使用此方法。

澄清

如果使用支持调整大小的对话框,则在将控件移到新位置时必须记住要计算新的宽度和高度。然后,您将使用适当的Size调用之一。例如:

// The EDIT control height now needs increasing
iNewEditHeight = rctButton.top - iTextMarginY - rctEdit.top;
m_editText.SetWindowPos(nullptr, 0, 0, iNewWidth, iNewEditHeight, SWP_NOMOVE | SWP_NOZORDER);

由您决定如何调整控件的初始大小。

然后,在OnInitDialog中,我调用了一个新方法:

void CEditTextDlg::SetupDynamicLayout()
{
    if (m_pDynamicLayout != nullptr)
    {
        m_pDynamicLayout->AddItem(IDC_BUTTON_INSERT_DATE, 
            CMFCDynamicLayout::MoveHorizontalAndVertical(100, 100), CMFCDynamicLayout::SizeNone());
        m_pDynamicLayout->AddItem(IDC_STATIC_INFO,
            CMFCDynamicLayout::MoveVertical(100), CMFCDynamicLayout::SizeHorizontal(100));
        m_pDynamicLayout->AddItem(IDC_EDIT_TEXT,
            CMFCDynamicLayout::MoveNone(), CMFCDynamicLayout::SizeHorizontalAndVertical(100, 100));
    }
}

如果使用SetWindowPos时宽度设置不正确,而仅使用SizeNone(),则宽度将无法正确调整。