杭州|对话框管理器第二章:创建框架窗口

杭州|对话框管理器第二章:创建框架窗口

文章图片

杭州|对话框管理器第二章:创建框架窗口

对话框模板包含了对话框外观的描述 , 所以对话框管理器只是简单地遍历模板并按照模板的描述来创建对话框 。 这个过程十分简单和直接 , 对话框管理器没有太多自己的决策空间 , 它只是按照模板说的做而已 。
为了简单起见 , 我会假设这里说的对话框管理器是一个扩展版本的对话框模板 。 它是经典的DLGTEMPLATE的超集 , 所以我讲述起来就比较通用 。
另外 , 我还会跳过一些比较特殊的部分(例如WM_ENTERIDLE消息) , 因为它们和我要将的主要部分关系不大 。
同时 , 因为篇幅的原因 , 我也会将错误处理略过 。
最后 , 我假设你已经了解各种对话框模板的结构并忽略模板语句解析方面的问题 。
好了 , 可以开始了 。
首要任务是研究对话框样式并将 DS_* 样式转换为 WS_* 和 WS_EX_* 样式 , 如下图所示:

问题:为什么定义了DS_CONTROL风格会导致去掉WS_CAPTION和WS_SYSMENU呢?
答案:通过简单地添加一个样式标志 , 使人们更容易将现有对话框转换为 DS_CONTROL 子对话框 。
如果对话框模板中包含菜单 , 则从作为创建参数的一部分传递的实例句柄来加载菜单 。
hmenu = LoadMenu(hinst );
这是对话创建中的一个常用方法:传递给对话创建函数的实例句柄用于对话创建期间的所有资源相关活动 。
获取对话框字体的算法如下:


请注意 , DS_SETFONT 优先于 DS_FIXEDFONT 。
一旦对话框管理器拥有字体 , 就会对其进行测量 , 以便可以使用其尺寸将对话框单元 (DLU) 转换为像素 。对话框布局中的所有内容都在 DLU 中完成 。如果您忘记了将 DLU 转换为像素的公式 , 这里有个提醒 。具体公式如下:
// 4 xdlu = 1 average character width
// 8 ydlu = 1 average character height
#define XDLU2Pix(xdlu) MulDiv(xdlu AveCharWidth 4)
#define YDLU2Pix(ydlu) MulDiv(ydlu AveCharHeight 8)
对话框大小来自模板:
cxDlg = XDLU2Pix(DialogTemplate.cx);
cyDlg = YDLU2Pix(DialogTemplate.cy);
【杭州|对话框管理器第二章:创建框架窗口】模板中的对话框大小是客户区的大小 , 所以我们也需要在非客户区添加 。
RECT rcAdjust = { 0 0 cxDlg cyDlg ;
AdjustWindowRectEx(&rcAdjust dwStyle hmenu != NULL dwExStyle);
int cxDlg = rcAdjust.right – rcAdjust.left;
int cyDlg = rcAdjust.bottom – rcAdjust.top;
我怎么知道它是客户区而不是包括非客户区在内的整个窗口? 因为如果是全窗矩形 , 就不可能设计对话框! 模板设计者不知道最终用户的系统将设置为哪些非客户端指标 , 因此无法在设计时考虑它 。
(这是更一般规则的一个特例:如果你不确定某件事是否真实 , 问问自己 , “如果它是真实的 , 世界会是什么样子?”如果你发现一个明显错误的逻辑结果 ,那么你刚刚[通过矛盾
证明你所考虑的事情确实不是真的 。 这是一个重要的逻辑原理 , 我会一次又一次地回到 。 其实你几天前就看到了 。 )
假设 DS_ABSALIGN 样式未设置 , 对话框模板中给出的坐标是相对于对话框的父级的 。
POINT pt = { XDLU2Pix(DialogTemplate.x)YDLU2Pix(DialogTemplate.y) ;
ClientToScreen(hwndParent &pt);
但是如果调用者传递了 hwndParent = NULL 怎么办? 在这种情况下 , 对话框位置相对于主屏幕的左上角 , 但不要这样做 。
> 在多显示器系统上 , 它会将对话框放在主显示器上 , 即使你的程序正在辅助显示器上运行 。
> 用户可能将他们的任务栏停靠在屏幕的顶部或左侧边缘 , 这将覆盖你的对话框 。
> 即使在单显示器系统上 , 你的程序也可能在屏幕的右下角运行 。将对话放在左上角不会在两者之间建立有意义的联系 。
> 如果你的程序的两个副本正在运行 , 它们的对话框将精确地相互覆盖 。我们在之前的文章中看到了这种情况的危险 。
故事的寓意:始终传递一个hwndParent窗口 , 以便对话框出现在相对于程序的其余部分有意义的位置 。(也不要只抓住 GetDesktopWindow!)
好的 , 我们现在已经准备好创建对话框:我们有它的类、它的字体、它的菜单、它的大小和位置等 。