Настройка динамического макета во время выполнения на основе видимости элемента управления - PullRequest
1 голос
/ 27 марта 2019

У меня есть многоцелевой 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

Примечание вернулось в исходное положение.

Я знаю, что у меня есть ответ на похожую проблему, но действительно ли мне нужно перестраивать весь макет?

Обновление 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 Ответ

2 голосов
/ 28 марта 2019

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(), размер не будет изменен правильно.

...