DeferWindowPos 这个 API 的目标是:同一时间,移动多个子窗口。这在一定程度上减少了窗户移动时进行的重绘工作量。
修改我们之前的例子代码,如下图所示:
>> 请移步至 topomel.com 查看图片 <<
请注意,我正在使用控件 ID 来保存所需的颜色,我们在选择背景颜色时在获取它。
>> 请移步至 topomel.com 查看图片 <<
我特意调用了 Sleep,这样就可以看到实际的绘制效果。
>> 请移步至 topomel.com 查看图片 <<
我们将两个子窗口并排放置在工作区中。对于我们的第一次测试,我们将使用 SetWindowPos 函数用来移动窗口。
编译并运行此程序,一旦启动,单击最大化框。仔细观察绿色矩形的哪些部分被重新绘制。
现在让我们修改移动窗口的代码以使用 DeferWindowPos 函数。DeferWindowPos 的使用模式如下:
>> 请移步至 topomel.com 查看图片 <<
要点如下
> 传递给 BeginDeferWindowPos 函数的值是要移动的窗口数量。如果弄错了这个值也没关系,但正确的处理会减少内部重新分配的数量。
> 来自 DeferWindowPos 的返回值将存储回 hdwp 中,因为返回值不一定与最初传入的值相同。如果延迟记录需要执行重新分配,则 DeferWindowPos 函数返回新延迟信息的句柄;旧的延迟信息不再有效。更重要的是,如果延迟失败,旧的延迟信息将被销毁。这与 realloc 函数不同,如果重新分配失败,则原始对象保持不变。模式 p = realloc(p, …) 是内存泄漏,但模式 hdwp = DeferWindowPos(hdwp, …) 不是。
上述第二个要点很重要,有很多人经常容易忽略它。
好的,现在你们可能都害怕这个函数,让我们修改窗口移动代码以利用延迟窗口定位。真的一点也不难。(不过,将这些更改保存到新文件中。我们希望并排运行旧版本和新版本。
>> 请移步至 topomel.com 查看图片 <<
编译并运行此程序,一旦启动,再次最大化窗口并观察哪些区域重新绘制。请注意,与旧版本相比,新版本中的重绘量会减少。
总结
完美主义者有福了。
如果你一直纠结于为什么你的窗口控件会闪烁,则不妨试试 DeferWindowPos 。
它的存在,一定是有原因的。
最后
Raymond Chen的《The Old New Thing》是我非常喜欢的博客之一,里面有很多关于Windows的小知识,对于广大Windows平台开发者来说,确实十分有帮助。
本文来自:《What’s the point of DeferWindowPos?》