MFC Dialog Dynamic Layout 实践
今天接触到一个 MFC Dialog 项目,对于一个 resizeable 的对话框,控件的布局一直是个棘手的问题,由于 MFC 框架较老并且为了保持向前兼容,所以一直没有提供这方面的支持,直到 VisualStudio 2015 在 MFC 中引进了 Dynamic Layout,关于 Dynamic Layout 的说明可以参见 MSDN 的 blog : MFC Dynamic Dialog Layout。
简单地说就是可以在 VisualStudio 的资源编辑器中设置控件的 Dynamic Layout 的 Moving 和 Sizing 属性实现控件的对其和按比例缩放。
但是如果只设置控件的 Dynamic Layout 属性会出现如下问题,当窗口缩小到小于初始大小时,控件会被挤出显示范围:
通过跟踪 Dynamic Layout 功能的源代码到 wincore2.cpp 中可以看到 CMFCDynamicLayout::GetHostWndRect
的定义有:
1 | rect.right = rect.left + max(m_MinSize.cx, rect.Width()); |
控件的大小受到 m_MinSize 的大小的制约,这个 m_MinSize 即为对话框初始化时的大小。
现在知道了原因,那么有两个解决办法:
1. 通过 OnGetMinMaxInfo 限制对话框的大小不能小于初始大小
这样需要在对话框设计时将其缩放到最小尺寸,然后通过定义 WM_GETMINMAXINFO 消息函数确保其不会进一步缩小:
1 | // |
其中 CMFCDynamicLayout::GetMinSize() 获取到的即为对话框的初始大小。
2. 通过 SetMinSize 设置初始大小为 CSize(0, 0)
设置对话框初始大小为 CSize(0, 0), 只要对话框大小大于 CSize(0, 0) 就不会出现控件被挤出窗口的问题
1 | BOOL CMylDlg::OnInitDialog() |
当然以上两个方法可以结合起来, 在 OnInitDialog 中设置窗口最小大小为一个指定值,而不使用资源编辑器中设计的大小。
WTL
值得一提的是,在 2018 年 WTL 也对 DynamicLayout 也提供了支持,将对话框继承于 CDynamicDialogLayout ,并在 OnInitDialog 中调用 InitDynamicLayout 即可
1 | class CMainDlg : |
其中 InitDynamicLayout 的参数含义为:
- bAddGripper 是否显示 Gripper,右下的拖动手柄
- bMinTrackSize 是否限定窗口最小尺寸
MFC Dialog Dynamic Layout 实践