AutoSizeDlg - ATL/WTL 自动调整大小类
AutoSizeDlg - ATL/WTL 自动调整大小类
引言
哈哈哈哈…… 我的第二篇教程/库/程序!这个库(基于 ATL 库并支持 WTL 库)将使你的窗口控件自动调整大小。它们会适应窗口的大小。这个库相当高级…… 它支持透明控件、嵌套控件组、跨越多行和多列的控件、可滚动窗口、自动设置窗口的最小和最大尺寸等等…… 但它还处于 Beta 阶段…… 我还没有在所有可能的组合中测试过所有功能。
该库需要 VC++(我已用 VC++ 8.0 测试过,但应该也能在早期版本上工作…… 我不太确定能早到多少,因为我使用了许多 VC++ 的“怪招”)、ATL(可能至少需要 7.0)并且支持 WTL 库(要编译 AutoSizeScroll,你需要一个较新的 WTL 版本。WTL 7.5 是较新的…… 其他都不是!)。
注释
如果你是 C++ 的纯粹主义者,你不应该看这个库…… 我做了太多错误的事情,你光是看到就会生病 :-) 我相当随意地使用了 `_alloca` “函数”,甚至在数组初始化中间,使用了“,”运算符,以及太多其他“错误”的事情…… 但我用 Doxygen 注释了所有主要方法和常量,所以你可以“编译”文档(已编译为 .html 和 .chm 格式)。该库不使用堆内存。它只使用栈…… 而且用得很多……(不,你不需要几兆字节的栈…… 大概只需要一千字节左右)。库如何工作
(请注意,此图像与 https://codeproject.org.cn/dialog/EvaLayout.asp 中的一幅非常相似…… 但抄袭也是一种赞美)
注意,我们将窗口分成了列和行(橙色线)。浅灰色矩形是窗口的控件。白色矩形是无控件区域。
我们的控件可以跨越多列/行(例如,控件 6 和 9 分别跨越 2 列和 3 列,控件 8 跨越 2 行)。
控件甚至可以是控件的聚合组(嵌套区域)(参见 11-12-13-14 控件下方有一个浅灰色矩形,跨越三列和两行)。
聚合控件组又可以细分为列和行(3 列和 2 行,深灰色矩形)。现在我们将学习如何向库描述这一点。
使用库
你需要包含 `atlautosizedlg.h`,放在 `atlwin.h` 之后(可能在 `stdafx.h` 中)。在 `stdafx.h` 中,在第一个 `#include` 之前,加入这个:
#define WINVER 0x0500 #define _WIN32_WINNT 0x0500然后在 dlg/窗口类声明中加入这个:
class MyClass : public ..., public CAutoSizeWindow<MyClass> BEGIN_WINDOW_MAP(MyClass, 10, 10, 8, 8) WMB_HEAD( WMB_COL(60), WMB_COL(_exp), WMB_COL(25), WMB_COL(75)), WMB_ROW(15, ID1, _, ID3, ID4), WMB_ROW(15, ID5, ID6, _r, ID7), WMB_ROW(15, ID8, ID9, _r, _r), WMB_ROW(_exp, _d), WMB_ROW(15, ID10), WMB_END() END_WINDOW_MAP()
我们看到了什么?我们看到必须从 `BEGIN_WINDOW_MAP()` 开始。第一个参数是类名,然后是左/右边距、上/下边距、控件之间的水平间距和控件之间的垂直间距。然后是一个列标题。每列都以 `WMB_COL(size)` 的格式描述。
请记住:所有尺寸都可以用对话框单位(在 MSDN 中查找 DLGUnit 是什么,并记住它是 Visual Studio 使用的度量单位)或像素表示。要使用像素,请将数字设为负数。所以 `60` 是 60 DLGUnits,`-60` 是 60 像素。如果你有特殊的标志要传递给宏,你可以这样做:`60|FLAG1` 或 `-60 ^ FLAG1`(对于负数,你必须使用异或(`^`)运算符)。对于空的 `ID2`,我们使用单个下划线(`_`)(甚至双下划线(`__`)也可以)。
请注意,并非所有行都需要“完整”。最后一行(包含 `ID10` 的那一行)不完整,但一切正常。
我们使用 `_r` 和 `_d` 使控件跨越多列和多行(`_r` = 右,`_d` = 下)。`_exp` 意味着列/行将按比例扩展,而不是固定宽度/高度。
我们还没有包含控件 11-14。现在我们将包含它们…… 相反
WMB_ROW(_exp, _d),
WMB_ROW(15, ID10),
加入这个
WMB_ROW(_exp, _d, WMB_HEAD( WMB_COL(35), WMB_COL(_exp), WMB_COL(30)), WMB_ROW(_exp, ID12, ID13, ID14), WMB_ROW(30, ID15, _r, _r), WMB_END()), _r, _r), WMB_ROW(15, ID10, _d),
注意逗号的使用。宏后面几乎总是有逗号,除非该宏是另一个宏的最后一个参数。在 `END_WINDOW_MAP()` 之前的最后一个 `WMB_END()` 之前 **不能** 有逗号。请注意,要使一个控件(或一组控件)跨越多列 **和** 行,你可以这样做:
IDCtrl, _r, _r, _d, __, __, _d, __, __
在 `_r` 下面,你不需要添加 `_d` 或 `_r`…… 你甚至可以放另一个控件(提示:组合框带控件)。
IDGroup, _r, _r, _r, _d, ID1, ID2, _d, ID3, ID4, _d
额外的 `_r` 和 `_d` 是为了在 `ID2` 和 `ID4` 的右边距与组合框的右边距之间留出一些空间。
为了让一切正常工作,在 `BEGIN_MSG_MAP()` 的末尾必须添加:
BEGIN_MSG_MAP(MyClass) ... CHAIN_MSG_MAP(CAutoSizeWindow<MyClass>) END_MSG_MAP()
为了让一切完美工作,你应该激活容器窗口的 `WS_CLIPCHILDREN`、`WS_CLIPSIBLINGS` 样式,并为组合框和用作矩形的 IMAGE 控件设置透明样式。现在一切都应该正常了……
透明控件
这个库支持透明组合框和用作矩形的 IMAGE 控件。要激活此支持,请添加:
TRANSPARENT_LIST(MyClass, IDGroupBox1, IDImageCtrl1, IDGroupBox2, IDImageCtrl2)
在 `BEGIN_WINDOW_MAP()` 之前或 `END_WINDOW_MAP()` 之后,并记住为控件设置 `WS_EX_TRANSPARENT` 扩展样式!!
其他技巧
你可以做太多“特殊”的事情……列/行大小
- [`_auto`] 使用列/行中控件的最大宽度/高度作为大小。没有可选参数。
- [`_exp`] 列/行将按比例扩展。可选参数:“权重”(默认:100)。
- [`_contr`] 如果所有其他行/列都已最大化,剩余空间将按比例分配给可收缩列。可选参数:“权重”(默认:100)。
- [`_eq`] 列/行将具有与其他列/行相同的宽度/高度以及相同的最小/最大宽度/高度。必需参数:列/行的编号(从零开始。第一列/行编号为 0)。
- [`_gap`] 列/行将是 GAP 宽(对于某些技巧很有用)。可选参数:“额外”宽度/高度 **添加到** 列。如果是 DLGUnits 则为正数,如果是像素则为负数(记住 `^`)。
- [`_gapm`] 列/行将是 GAP 宽(对于某些技巧很有用)。可选参数:“额外”宽度/高度 **从** 列中 **减去**(最小为 0)。如果是 DLGUnits 则为正数,如果是像素则为负数(记住 `^`)。
- [(无)] 列的宽度/高度是固定的。必需参数:列/行的宽度/高度。如果是 DLGUnits 则为正数,如果是像素则为负数(记住 `^`)。请注意,你不需要使用 `WMSRC_FIXED`,因为它就是 0。
- [`_nog`](这是一个特殊的标志,你必须将其添加到其他标志中)。不要在此列/行前面加上通常的间隙。第一列/行没有间隙。
单元格扩展
- [`_r`] 此单元格左侧的控件将继续在此单元格中。
- [`_d`] 此单元格顶部的控件将继续在此单元格中。
- [`_` & `__`] 单元格为空(你可以直接使用 0,但调试起来会更困难)。
列和行的最小和最大尺寸
你可以使用其他宏代替 `WMB_COL(size)` 或 `WMB_ROW(size, ctrls...)`,这些宏将允许你决定列/行的最小和最大宽度/高度。
这些宏的命名方式是标准的:`MIN` 在 `MAX` 之前,无表示程序将尝试自行计算值,`NOMIN` 或 `NOMAX` 表示没有最小值(最小值为 0)或没有最大值。
所以我们有 `WMB_COL`、`WMB_COLMIN`、`WMB_COLMAX`、`WMB_COLMINMAX`、`WMB_COLNOMIN`、`WMB_COLNOMAX`、`WMB_COLNOMINNOMAX`、`WMB_COLNOMINMAX`、`WMB_COLMINNOMAX` 以及相应的 `WMB_ROW*`。最小和/或最大值按如下方式给出:
WMB_COLMIN(sizeflag, minsize) WMB_COLMAX(sizeflag, maxsize) WMB_COLMINMAX(sizeflag, minsize, maxsize) WMB_ROWMIN(sizeflag, minsize, ctrls...) WMB_ROWMAX(sizeflag, maxsize, ctrls...) WMB_ROWMINMAX(sizeflag, minsize, maxsize, ctrls...)
`NOMIN` 和 `NOMAX` 修饰符不需要参数。所以 `WMB_COLNOMIN(sizeflag)`,`WMB_ROWNOMINMAX(sizeflag, maxsize, ctrls...)`…… 请记住:所有尺寸都可以用对话框单位或像素表示。要使用像素,请将数字设为负数。
参考文献
虽然我懒得真正阅读它们,但这个库是基于图片(意思是,我打开了页面,看了图片,发现它们非常漂亮,给了我正确的方向)的:
- http://msdn.microsoft.com/msdnmag/issues/01/07/winmgr/ 和
- https://codeproject.org.cn/dialog/EvaLayout.asp
(不,我没开玩笑…… 最初我只想创建一个宏版本的 EvaLayout……(记住,我没有真正阅读文章…… 在那个时期我的注意力很不集中)所以库的 1.0 版本诞生了…… 然后我决定想要可嵌套的控件组…… 最后,这两个文章的奇怪混合体诞生了。但我真的很懒得读它们……它们太长了…… 所以如果你不完整地阅读这篇文章,我不会生气 :-) 我不确定我会读我的文章 :-))。
与其他类似库的比较
我添加这一节是因为有些人问过。世界上充满了移动窗口中控件的库。WTL 有一个。Paul DiLascia 在 2001 年做了一个最著名的。你可以使用任何你想要的库。我的生活不会改变。我甚至会帮助你…… 这里有一个小小的选择:(第一个是 DiLascia 的,它是纯 Windows API。接下来的三个是 MFC(我不确定,但它们应该是)……或许它们有 ATL 支持。其他的 WTL(至少有一个只是对标准 WTL 库的解释,另一个是对标准 WTL 库的小扩展))。
- http://msdn.microsoft.com/msdnmag/issues/01/07/winmgr/
- https://codeproject.org.cn/dialog/EvaLayout.asp
- https://codeproject.org.cn/dialog/layoutmgr.asp
- https://codeproject.org.cn/dialog/easysize.asp
- https://codeproject.org.cn/wtl/wtldlgresize.asp
- https://codeproject.org.cn/wtl/wtl_dialog_resize_ex.asp
- https://codeproject.org.cn/wtl/sizingframework.asp
- https://codeproject.org.cn/wtl/layout_mgr.asp
- https://codeproject.org.cn/wtl/dialoglayout.asp
- https://codeproject.org.cn/wtl/ResizableLib_WTL.asp
我讨厌将我的程序与其他人的程序进行比较……当我这样做时,我总是觉得自己太骄傲了。事物有无数种实现方式,就像有无数程序员一样……程序并不总是更好或更差……很多时候它们只是不同。如果你看不出库之间的差异,那么你不应该编程。如果你没有时间为你的程序选择合适的库,那么你应该随机选择一个,并希望它是最好的。有些人会买他们看到的第一件东西……有些人会试图发现相似产品之间的差异,然后购买更好的/更便宜的/最平衡的那一个……
我可以告诉你我的库做了什么
- 它是 ATL/WTL(有些库是 MFC)。
- 它是基于宏的。宏中的布局与屏幕上的布局相似(从左到右,从上到下,行是行,列是列)。
- 它速度非常快。矩阵每次 `OnSize` 事件至少读取一次,从第一个元素到最后一个元素。不分配堆内存。API 调用受到限制,并且其结果被缓存。初始化不分配额外内存。对于单层控件组,矩阵大约为 21 + (3 * 列数 + 5 * 行数 + 1 * 控件数) 个整数(多一两个整数)。
- 它有一个解决组合框闪烁问题的方案,支持 WinXP 中的 Alt 键(在 XP 中,加速键通常隐藏,除非按下 Alt 键。然后它们才会显示)。
- 它可以实现几乎所有的布局……有些布局比其他布局更难。你需要运用智慧来使用这个库……你需要可变间距?将标准间距设置为 0,并在你的行/列之间添加空的行/列。你需要将控件对齐到边界框的左侧或右侧?在控件的左侧或右侧添加一个空的、可扩展(或可收缩)的列。
我甚至可以告诉你我的库不能做什么
- 这是一个用于移动窗口中控件的库。它不是一个窗口管理库。我不会提供将窗口位置保存在注册表中的方法。我不会提供用于调整窗口大小的抓手。我不会提供滚动条(但滚动条可以通过 `CScrollImpl` 支持)。
- 矩阵的内部格式很混乱。矩阵是静态分配的,所以直接修改它不是个好主意,**但是** 你可以给库提供另一个矩阵:注意所有方法都将矩阵作为参数。
- 我不会给你一个“占总大小 30%”的控件,因为这是不可能的……你有一个 5 像素的列,一个 75% 的列,还有一个 10 像素宽的窗口。会发生什么?两个约束中的一个无法被满足。
最后,我可以告诉你库之间的主要区别
- 有些是基于宏的(例如我的和 Paul DiLascia 的),有些是基于类的(你在窗口初始化时将控件添加到类中……类似于 `Handler += ctrl1; Handler += ctrl2; ...`,或者有一个库的布局存储在字符串中,甚至可以保存在外部文件中)。
- 一些库只处理控件的重排。它们从你在对话框编辑器中给定的信息开始,然后按比例扩展/收缩控件。它们可以移动控件,但它们是相对于它们在对话框编辑器中的初始位置来移动的(例如 WTL 标准库和许多其他库……几乎所有非网格的)。其他库(包括我的和其他)允许你在程序中的某个地方决定控件的位置。对话框编辑器仅用于添加控件和修改它们的样式。
- 有些是纯 Windows API,有些是 MFC,有些是 ATL/WTL(或许还有 MFC/ATL 库)。
历史
- atlautosizedlg.h 1.0 2006 年 4 月 首次发布(未发布)
- atlautosizedlg.h 2.0 2006 年 6 月 基本重建。现在支持多层。
许可证
我是一个 BSD 用户,所以我会根据 MIT 许可证(一个简化的 BSD 许可证)来许可这个库。
Copyright (c) 2006 Massimiliano Alberti xanatos(at)geocities.com
兹授予任何人获取本软件及相关文档文件(“软件”)副本的权利,不受限制地处理软件,包括但不限于使用、复制、修改、合并、发布、分发、再许可和/或销售软件副本的权利,并允许接收本软件的个人这样做,但须遵守以下条件:
上述版权声明和本许可声明应包含在软件的所有副本或重要部分中。
本软件按“原样”提供,不附带任何形式的保证,明示或暗示,包括但不限于适销性、特定用途适用性和非侵权性的保证。在任何情况下,作者或版权持有人均不对任何索赔、损害或其他责任负责,无论是合同、侵权或其他形式的诉讼,无论是否因使用本软件或在软件中的其他交易而引起。