CMFCPropertySheet "Страница" ресурсы не меняются с динамическим макетом

Я действительно смущен.:(

Вот новый список свойств:

#include "stdafx.h"
#include "resource.h"
#include "VisitsRotaMFCPropertySheet.h"


CVisitsRotaMFCPropertySheet::CVisitsRotaMFCPropertySheet()
    :CResizingMFCPropertySheet(_T("VisitsRota"), AFX_IDS_APP_TITLE, nullptr, 0)
{
    ConstructSheet();
}

CVisitsRotaMFCPropertySheet::~CVisitsRotaMFCPropertySheet()
{
}


BOOL CVisitsRotaMFCPropertySheet::OnInitDialog()
{
    BOOL bResult = CResizingMFCPropertySheet::OnInitDialog();

    m_Menu.LoadMenu(IDR_MENU);
    SetMenu(&m_Menu);

    return bResult;
}


void CVisitsRotaMFCPropertySheet::ConstructSheet()
{
    m_psh.dwFlags |= PSH_NOAPPLYNOW;

    AddPage(&m_ElderlyInfirmPage);
    AddPage(&m_ShepherdingPage);
}

Это получено из CResizingMFCPropertySheet, Это источник для этого класса:

https://www.dropbox.com/s/fzpfo4c3dpt6l51/ResizingMFCPropertySheet.cpp?dl=0

Теперь у меня есть две страницы в этом окне. Вот один из определений:

IDD_PAGE_ELDERLY_INFIRM DIALOGEX 0, 0, 420, 202
STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_CAPTION
CAPTION "Elderly && Infirm"
FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
    GROUPBOX        "Elders ...",IDC_STATIC,6,7,132,188
    LISTBOX         IDC_LIST_BOOKSTUDY,12,18,120,147,LBS_SORT | LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP
    PUSHBUTTON      "Add",IDC_BUTTON_ADD_GROUP,12,172,35,18
    PUSHBUTTON      "Edit",IDC_BUTTON_EDIT_ELDER,55,172,35,18
    PUSHBUTTON      "Delete",IDC_BUTTON_DELETE_GROUP,97,172,35,18
    GROUPBOX        "Publishers ...",IDC_STATIC,144,7,132,188
    LISTBOX         IDC_LIST_ELDERY_INFIRM,150,18,120,147,LBS_SORT | LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP
    PUSHBUTTON      "Add",IDC_BUTTON_ADD_ELDERLY,150,172,35,18
    PUSHBUTTON      "Edit",IDC_BUTTON_EDIT_ELDERLY,193,172,35,18
    PUSHBUTTON      "Delete",IDC_BUTTON_DELETE_ELDERLY,235,172,35,18
    GROUPBOX        "Report Settings ...",IDC_STATIC,281,7,132,188
    LTEXT           "Starting month:",IDC_STATIC,286,18,120,8
    COMBOBOX        IDC_COMBO_MONTH,286,31,120,12,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
    LTEXT           "Number of months:",IDC_STATIC,286,49,78,12
    COMBOBOX        IDC_COMBO_NUM_MONTHS,376,49,30,96,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
    LTEXT           "Number of publishers to visit each month:",IDC_STATIC_NUM_PUB,286,65,84,18
    COMBOBOX        IDC_COMBO_PUB_PER_MONTH,376,66,30,12,CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP
    LTEXT           "Starting publisher:",IDC_STATIC,286,90,120,8
    COMBOBOX        IDC_COMBO_PUBLISHER,286,103,120,12,CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP
END

Это правильно настроено как страница, и я первоначально установил управляющие данные через IDE:

IDD_PAGE_ELDERLY_INFIRM AFX_DIALOG_LAYOUT
BEGIN
    0,
    0, 0, 0, 100,
    0, 0, 0, 100,
    0, 100, 0, 0,
    0, 100, 0, 0,
    0, 100, 0, 0,
    0, 0, 0, 100,
    0, 0, 0, 100,
    0, 100, 0, 0,
    0, 100, 0, 0,
    0, 100, 0, 0,
    100, 0, 0, 100,
    100, 0, 0, 0,
    100, 0, 0, 0,
    100, 0, 0, 0,
    100, 0, 0, 0,
    100, 0, 0, 0,
    100, 0, 0, 0,
    100, 0, 0, 0,
    100, 0, 0, 0
END

Я поправил CDialog приложение, чтобы вызвать лист свойств вместо. Размеры самого листа:

Простынь

Почему контроль листа не изменяется автоматически? Я просто не понимаю Мое другое приложение использует тот же базовый класс, но все эти страницы свойств корректно изменяют размеры элементов управления и т. Д., Используя функции динамического макета.

Обновить

Я добавил это на одну из моих страниц:

void CElderlyInfirmPage::OnSize(UINT nType, int cx, int cy)
{
    CMFCPropertyPage::OnSize(nType, cx, cy);

    AfxMessageBox(_T("Size"));

    // TODO: Add your message handler code here
    auto pManager = GetDynamicLayout();
    if (pManager != nullptr)
    {
        AfxMessageBox(_T("Valid"));
    }
}

Это подтверждает, что "страница" на самом деле не имеет менеджера динамического макета. Только лист делает. Поэтому я думаю, что проблема в том, что мы не можем использовать механизм динамического размещения.

Обновление 2

Я добился определенного прогресса. Пример:

Измененный размер

Оказывается, страница свойств, похоже, не загружает ресурсы динамического макета, как это делается для диалога. Я начал создавать его вручную:

BOOL CElderlyInfirmPage::OnInitDialog()
{
    CMFCPropertyPage::OnInitDialog();

    // TODO:  Add extra initialization here
    ReadSettings();
    InitMonthCombo();

    // Init to THIS month
    COleDateTime    datNow = COleDateTime::GetCurrentTime();
    m_cbMonth.SetCurSel(datNow.GetMonth()-1);

    EnableDynamicLayout(TRUE);
    auto pManager = GetDynamicLayout();
    if (pManager != nullptr)
    {
        pManager->Create(this);
        pManager->AddItem(IDC_COMBO_MONTH, CMFCDynamicLayout::MoveHorizontal(100), CMFCDynamicLayout::SizeNone());
        pManager->AddItem(IDC_COMBO_NUM_MONTHS, CMFCDynamicLayout::MoveHorizontal(100), CMFCDynamicLayout::SizeNone());
        pManager->AddItem(IDC_COMBO_PUB_PER_MONTH, CMFCDynamicLayout::MoveHorizontal(100), CMFCDynamicLayout::SizeNone());
        pManager->AddItem(IDC_COMBO_PUBLISHER, CMFCDynamicLayout::MoveHorizontal(100), CMFCDynamicLayout::SizeNone());
    }

    return TRUE;  // return TRUE unless you set the focus to a control
    // EXCEPTION: OCX Property Pages should return FALSE
}

Как вы можете видеть, элементы управления теперь перемещаются, так что это прогресс. Но проблема в том, что у меня много IDC_STATIC элементы управления на этих страницах, и я не хочу менять идентификационные номера. Это связано с тем, что в приложении уже есть переводы для локализации, и если я изменяю значения идентификатора, я взрываю переводы. Так что мне интересно, могу ли я использовать [CMFCDynamicLayout::LoadResource][3] способ загрузить полные настройки из файла RC. Но я не могу понять, как позвонить LoadResource Вот. Я уверен, что это будет ответом на этот вопрос.

Обновление 3

Я только что проследил код, и если вы посмотрите здесь:

LRESULT CPropertySheet::HandleInitDialog(WPARAM, LPARAM)
{
    LRESULT lResult = OnInitDialog();

    CMFCDynamicLayout* pDynamicLayout = GetDynamicLayout();
    if (pDynamicLayout != NULL)
    {
        CRect rectWindow;
        GetWindowRect(rectWindow);
        m_sizeMin = rectWindow.Size();

        for (CWnd *pChild = GetWindow(GW_CHILD); pChild->GetSafeHwnd() != NULL; pChild = pChild->GetWindow(GW_HWNDNEXT))
        {
            HWND hwndChild = pChild->GetSafeHwnd();
            if (!pDynamicLayout->HasItem(hwndChild))
            {
                if (pChild->SendMessage(WM_GETDLGCODE) & DLGC_BUTTON)
                {
                    pDynamicLayout->AddItem(hwndChild, CMFCDynamicLayout::MoveHorizontalAndVertical(100, 100), CMFCDynamicLayout::SizeNone());
                }
                else if (IsLeftNavigationPane(hwndChild))
                {
                    pDynamicLayout->AddItem(hwndChild, CMFCDynamicLayout::MoveNone(), CMFCDynamicLayout::SizeVertical(100));
                }
                else if (DYNAMIC_DOWNCAST(CPropertyPage, pChild) == NULL || CanAddPageToDynamicLayout())
                {
                    pDynamicLayout->AddItem(hwndChild, CMFCDynamicLayout::MoveNone(), CMFCDynamicLayout::SizeHorizontalAndVertical(100, 100));
                }
            }
        }
    }

    return lResult;
}

Кажется, он не работает с версткой должным образом.

Я пытался использовать:

LoadDynamicLayoutResource(m_lpszTemplateName);

И я проследил это. В конечном итоге это закончилось здесь:

BOOL CMFCDynamicLayout::LoadResource(CWnd* pHostWnd, LPVOID lpResource, DWORD dwSize)
{
    if (pHostWnd->GetSafeHwnd() == NULL || !::IsWindow(pHostWnd->GetSafeHwnd()) || lpResource == NULL)
    {
        return FALSE;
    }

    CMFCDynamicLayoutData layoutData;
    BOOL bResult = layoutData.ReadResource(lpResource, (UINT)dwSize);
    layoutData.ApplyLayoutDataTo(pHostWnd, FALSE);

    return bResult;
}

Это не удалось на ApplyLayoutDataTo позвони, по первому if заявление:

BOOL CMFCDynamicLayoutData::ApplyLayoutDataTo(CWnd* pHostWnd, BOOL bUpdate)
{
    if (pHostWnd->GetSafeHwnd() == NULL || m_listCtrls.IsEmpty())
    {
        return FALSE;
    }

    ASSERT_VALID(pHostWnd);

    pHostWnd->EnableDynamicLayout(FALSE);
    pHostWnd->EnableDynamicLayout();

m_listCtrls.IsEmpty() был пуст. Так что он все равно не прочитал это правильно.

Я думаю, что у меня нет выбора, кроме как назначить идентификаторы всем моим элементам управления, даже статическим, и вручную создать динамический макет. Если у вас нет других идей.

1 ответ

Решение

Динамическое расположение уже включено для всех классов, производных от CDialog которые называют по умолчанию CDialog::OnInitDialogкоторый в свою очередь использует CMFCDynamicLayout::LoadResource читать информацию об изменении размера для дочерних элементов управления.

Это включает CMFCPropertyPage, Информация уже загружена, так что если вы позвоните EnableDynamicLayout удаляет существующий объект и создает новый. Просто удалите звонок EnableDynamicLayout,

Сюда pManager->Create(this); не будет необходимости, но вы можете держать его там. Это ничего не сделает, потому что pManager уже создан и метод знает не создавать дважды.

CPropertySheet действительно требует EnableDynamicLayout а также pManager->Create, Таблица свойств не может быть разработана в диалоговом редакторе, поэтому MFC игнорирует изменение размеров для своих дочерних окон. Динамическое изменение размера должно быть реализовано вручную.

MCVE:

class CMyPage : public CMFCPropertyPage
{
    CButton bn;
    BOOL OnInitDialog()
    {
        CMFCPropertyPage::OnInitDialog();

        //add test button dynamically
        bn.Create(L"Test", WS_CHILD | WS_VISIBLE, CRect(0, 0, 100, 30), this, 301);

        auto pManager = GetDynamicLayout();
        if(pManager != nullptr)
        {
            pManager->AddItem(bn.GetDlgCtrlID(),
              CMFCDynamicLayout::MoveHorizontal(100),
              CMFCDynamicLayout::SizeNone());
        }
        return TRUE;
    }
};

class CMySheet :public CMFCPropertySheet
{
public:
    CMyPage Page1;
    CMySheet()
    {
        Page1.Construct(IDD_PAGE1);
        AddPage(&Page1);
    }

    static 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);
        if (message == PSCB_PRECREATE)
            ((LPDLGTEMPLATE)lParam)->style |= (DS_3DLOOK | DS_SETFONT
                | WS_THICKFRAME | WS_SYSMENU | WS_POPUP | WS_VISIBLE | WS_CAPTION);
        return nRes;
    }

    BOOL OnInitDialog()
    {
        BOOL res = CMFCPropertySheet::OnInitDialog();
        EnableDynamicLayout(TRUE);//required for propertysheet
        auto pManager = GetDynamicLayout();
        if(pManager)
        {
            pManager->Create(this);
            for(CWnd *child = GetWindow(GW_CHILD); 
              child; child = child->GetWindow(GW_HWNDNEXT))
            {
                if(child->SendMessage(WM_GETDLGCODE) & DLGC_BUTTON)
                    pManager->AddItem(*child, 
                      CMFCDynamicLayout::MoveHorizontalAndVertical(100, 100),
                      CMFCDynamicLayout::SizeNone());
                else
                    pManager->AddItem(*child, 
                      CMFCDynamicLayout::MoveNone(),
                      CMFCDynamicLayout::SizeHorizontalAndVertical(100, 100));
            }
        }

        return res;
    }

    INT_PTR DoModal()
    {
        // Hook into property sheet creation code
        m_psh.dwFlags |= PSH_USECALLBACK;
        m_psh.pfnCallback = XmnPropSheetCallback;
        return CMFCPropertySheet::DoModal();
    }
};

...
CMySheet sh;
sh.DoModal();
Другие вопросы по тегам