重新计算动态布局属性

Posted

技术标签:

【中文标题】重新计算动态布局属性【英文标题】:Recalculate dynamic layout properties 【发布时间】:2018-06-23 18:36:04 【问题描述】:

这是一个可调整大小的窗口:

设置动态布局属性,以便顶部组框调整宽度,而下部组/框和树在两个维度上与 3 个按钮一起调整大小。

对于高级复选框,我添加了代码来隐藏额外的控件并调整相关框的高度。所以它看起来像这样:

用于切换控制值的代码是:

void CWishListDlg::ToggleAdvancedMode()

    CRect rtSortTalk, rtTalkSettings, rtTreeGroup, rtTree, rtTalkCombo;

    m_staticSortTalk.ShowWindow(m_bAdvancedMode ? SW_SHOW : SW_HIDE);
    m_cbTalkSortField.ShowWindow(m_bAdvancedMode ? SW_SHOW : SW_HIDE);
    m_cbTalkSortOrder.ShowWindow(m_bAdvancedMode ? SW_SHOW : SW_HIDE);
    m_staticSortSpeaker.ShowWindow(m_bAdvancedMode ? SW_SHOW : SW_HIDE);
    m_cbSpeakerSortField.ShowWindow(m_bAdvancedMode ? SW_SHOW : SW_HIDE);
    m_cbSpeakerSortOrder.ShowWindow(m_bAdvancedMode ? SW_SHOW : SW_HIDE);
    m_staticTalkHistory.ShowWindow(m_bAdvancedMode ? SW_SHOW : SW_HIDE);
    m_checkIncludeTalkHistory.ShowWindow(m_bAdvancedMode ? SW_SHOW : SW_HIDE);
    m_staticStyle.ShowWindow(m_bAdvancedMode ? SW_SHOW : SW_HIDE);
    m_cbStyle.ShowWindow(m_bAdvancedMode ? SW_SHOW : SW_HIDE);

    m_staticSortTalk.GetWindowRect(&rtSortTalk);
    m_staticSettings.GetWindowRect(&rtTalkSettings);
    m_staticTreeDetails.GetWindowRect(&rtTreeGroup);
    m_Tree.GetWindowRect(&rtTree);

    if (m_bAdvancedMode)
    
        rtTalkSettings.bottom += m_iOffsetY;
        rtTreeGroup.top += m_iOffsetY;
        rtTree.top += m_iOffsetY;
    
    else
    
        rtTalkSettings.bottom -= m_iOffsetY;
        rtTreeGroup.top -= m_iOffsetY;
        rtTree.top -= m_iOffsetY;
    

    ScreenToClient(&rtTalkSettings);
    ScreenToClient(&rtTreeGroup);
    ScreenToClient(&rtTree);

    m_staticSettings.MoveWindow(&rtTalkSettings);
    m_staticTreeDetails.MoveWindow(&rtTreeGroup);
    m_Tree.MoveWindow(&rtTree);

它工作正常。我可以切换到我心中的内容。直到我尝试调整窗口大小:

我看不到任何基于活动显示的方法。

如果勾选“高级”,以便控件可见(从而匹配资源编辑器),则它可以很好地调整大小。只有当它被取消并且我修改了两个控件时,调整大小才会正常工作。

【问题讨论】:

【参考方案1】:

我发现了这个极好的资源:

https://mariusbancila.ro/blog/2015/07/27/dynamic-dialog-layout-for-mfc-in-visual-c-2015/

你要做的是删除动态布局并重新创建它:

void CWishListDlg::SetupDynamicLayout()

    // Disable dynamic layout (this will delete the pointer and set it to NULL)
    EnableDynamicLayout(FALSE);

    // Enable dynamic layout (this will create a new pointer with no elements)
    EnableDynamicLayout(TRUE);

    // Re-create the dynamic layout content
    auto pManager = GetDynamicLayout();
    if (pManager != nullptr)
    
        pManager->Create(this); // Assign the window!
        auto moveNone = CMFCDynamicLayout::MoveNone();
        auto moveVertical100 = CMFCDynamicLayout::MoveVertical(100);
        auto moveBoth100 = CMFCDynamicLayout::MoveHorizontalAndVertical(100, 100);
        auto sizeBoth100 = CMFCDynamicLayout::SizeHorizontalAndVertical(100, 100);
        auto sizeHorizontal100 = CMFCDynamicLayout::SizeHorizontal(100);
        auto sizeNone = CMFCDynamicLayout::SizeNone();

        pManager->AddItem(m_staticSettings.GetSafeHwnd(), moveNone, sizeHorizontal100);
        pManager->AddItem(m_staticTreeDetails.GetSafeHwnd(), moveNone, sizeBoth100);
        pManager->AddItem(m_Tree.GetSafeHwnd(), moveNone, sizeBoth100);
        pManager->AddItem(IDC_BUTTON_HELP, moveVertical100, sizeNone);
        pManager->AddItem(IDC_BUTTON_REPORT, moveBoth100, sizeNone);
        pManager->AddItem(IDC_BUTTON_EXPAND_ALL, moveBoth100, sizeNone);
        pManager->AddItem(IDC_BUTTON_COLLAPSE_ALL, moveBoth100, sizeNone);
        pManager->AddItem(IDC_STATIC_RESIZE, moveBoth100, sizeNone);
    

很遗憾,您不能只在布局中获取现有控件或告诉它根据活动内容重新初始化。但是这种方式效果很好。它现在可以正确调整大小:

【讨论】:

【参考方案2】:

我遇到了完全相同的问题。但是,我找到了另一种解决方法。我没有手动编写布局,而是从“高级”按钮处理程序中的资源重新加载它。因此,布局会根据新控件的大小自行调整。

// Find the layout resource and store it statically.
// There is no need to unload it every time for optimization.
static const HRSRC LAYOUT_RES = ::FindResource(NULL, MAKEINTRESOURCE(IDD_YOUR_DIALOG), RT_DIALOG_LAYOUT);
static const LPVOID LAYOUT_RES_DATA = ::LockResource(::LoadResource(NULL, LAYOUT_RES));
static const DWORD LAYOUT_RES_SIZE = ::SizeofResource(NULL, LAYOUT_RES);

if(auto lo = GetDynamicLayout())
    lo->LoadResource(this, LAYOUT_RES_DATA, LAYOUT_RES_SIZE);

就是这样。此代码 sn-p 从资源中获取动态对话框布局并将其应用于控件的当前状态(大小和位置)。

编辑:

不过,这里并没有错误的资源 ID 或其他错误情况处理...

【讨论】:

有趣。我还没有测试过这种方法。

以上是关于重新计算动态布局属性的主要内容,如果未能解决你的问题,请参考以下文章

使用自动布局并创建动态界面(隐藏字段时自动重新对齐)

android 开发的时候怎么动态设置控件宽高

在Android中,如何保存“动态创建的布局”并在我重新打开应用程序时重新加载?

css3 calc()属性介绍以及自适应布局使用方法

代码动态修改组件的布局属性

动态添加一个视图及其布局属性(要掌握)