【问题标题】:Customising a dynamic layout at runtime based on control visibility基于控件可见性在运行时自定义动态布局
【发布时间】:2019-03-27 19:32:43
【问题描述】:

我有一个多用途的CDialog,它支持调整大小。它可以显示 3 种变化的内容。

变体 1:

变体 2:

变体 3:

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

变体 1 很好,不需要更改。

变体 2 不显示组合和日期按钮。因此,我希望“Text will ...”标签位于底部,“edit”框更高。

变体 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());
}

起初我认为它有效:

注释现在位于底部。但只要我调整窗口大小:

笔记已恢复到原来的位置。

我知道我有这个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");
        }

    }
}

当我尝试上述方法时,控件宽度是原始宽度,即使对话框已恢复到更宽的对话框宽度。

【问题讨论】:

    标签: mfc dialog


    【解决方案1】:

    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(),它将无法正确调整大小。

    【讨论】:

    • 谢谢。我必须做的是在将控件添加到布局之前重新计算控件的默认大小(因为对话框已调整大小)。已排序。
    • 我不确定您想出了什么解决方案。我认为您决定手动移动/调整所有子控件的大小!
    • 没有。只有我需要调整大小的控件。我只需要先正确地“调整”它们的大小。 EG:当“移动”到正确的位置时,我必须正确更改宽度。所有其他的都通过 IDE 资源属性保留为默认值。
    • 在您的示例代码中注意您有 SizeNone。那不好。我的控件在宽度或高度上都在拉伸。但我必须先更改控件的基本尺寸。所以我不得不重新计算正确的尺寸。
    • 我对你的回答做了一些调整。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-05-29
    • 1970-01-01
    • 1970-01-01
    • 2015-07-07
    • 1970-01-01
    • 2013-08-24
    • 1970-01-01
    相关资源
    最近更新 更多