重新计算动态布局属性
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 或其他错误情况处理...
【讨论】:
有趣。我还没有测试过这种方法。以上是关于重新计算动态布局属性的主要内容,如果未能解决你的问题,请参考以下文章