2

我真的很困惑。:(

这是一个新的属性表:

#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控件,我不想更改 ID 号。这是因为应用程序已经有本地化翻译,如果我更改 ID 值,我会破坏翻译。所以我想知道我是否可以使用该[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()是空的。所以它无论如何都没有正确读取它。

我想我别无选择,只能为我的所有控件分配 ID,甚至是静态控件,并手动构建动态布局。除非你有其他想法。

4

1 回答 1

1

CDialog所有调用 default 的类都已启用动态布局,而 defaultCDialog::OnInitDialog又用于CMFCDynamicLayout::LoadResource读取子控件的大小调整信息。

这包括CMFCPropertyPage. 该信息已加载,因此如果您调用EnableDynamicLayout它,则会删除现有对象并创建一个新对象。只需删除对EnableDynamicLayout.

这种方式pManager->Create(this);不是必需的,但您可以将其保留在那里。它不会做任何事情,因为pManager已经创建并且该方法知道不要创建两次。

CPropertySheet确实需要EnableDynamicLayoutpManager->Create。PropertySheet 不能在对话框编辑器中设计,因此 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();
于 2018-11-08T18:49:28.130 回答