虽然 TortoiseSVN 的主要关注点在于易用性,但我有时也喜欢添加一些不增加实际价值但看起来很漂亮的东西。
上周我想实现的就是这样的东西:看起来很漂亮,但不会打扰用户。Windows 资源管理器在右下角显示一个略微可见的图像,具体取决于当前显示的文件夹中包含哪些文件。该图像几乎不可见,就像一个水印。我想在我们的主对话框文件列表中显示这样的水印图像。
要实现这一点,最明显的方法是使用 SetBkImage 方法,该方法属于 CListCtrl 类,因为我们使用该控件在对话框中显示文件列表。因此,我像这样调用该方法
但当然,这根本不起作用。没有显示背景图像。逐步调试 SetBkImage
的代码显示它只是 LVM_SETBKIMAGE 消息的包装器。阅读有关该消息的 MSDN 文档发现了一些在 SetBkImage
文档中完全缺失的内容:LVBKIMAGE 结构的 hbm
参数“当前未使用”。太棒了。然后我尝试使用另一个选项
这实际上起作用了。但一方面,图像以实心方式绘制,所有透明像素都被绘制为黑色,并且当控件的内容滚动时,图像不会停留在右下角。我既无法使用 alpha 通道正确绘制图像,也无法使图像停留在右下角,即使在滚动事件处理程序中设置图像位置也是如此。显然,我走错了路。
接下来我尝试直接在列表控件的 NM_CUSTOMDRAW 处理程序中绘制图像。这效果很好,直到我稍微快一点地滚动文件列表。这会导致水印图像出现一些难看的“残留”。事实证明,列表控件在滚动时并不总是完全重绘其背景,这实际上对性能有利,但对我来说当然不好,而且这也不是我想要做的。
顺便说一下:CDRF_NOTIFYPOSTERASE 在列表控件中没有使用。
但一定有办法,因为微软在资源管理器中就是这样做的,当然假设他们没有使用他们喜欢保密的某些未公开的功能。
有时阅读 SDK 中的头文件很有用。在文件 commctrl.h 中,我找到了以下用于 LVBKIMAGE 的定义。
但这三个定义中,只有第一个有文档记录。好吧,不完全是。在 MSDN 中搜索 LVBKIF_TYPE_WATERMARK
显示了 此页面。在这里,这些定义有文档记录。太棒了!或者至少我以为是这样。
不,也不行。也许我使用的位图没有真正的 alpha 通道?删除 LVBKIF_FLAG_ALPHABLEND
标志也没有帮助。出于绝望,我尝试了以下方法
这有效!难以置信。即使文档说明 LVBKIMAGE
结构的 hbm
成员“当前未使用”,但它显然被使用(并且必须使用)如果设置了 LVBKIF_TYPE_WATERMARK
标志。图像显示在右下角,即使滚动文件列表,它也保持在那里,没有任何 UI 故障。但是(总有一个“但是”)图像没有显示其 alpha 通道。它应该透明的地方,它被绘制成黑色。但这正是 LVBKIF_FLAG_ALPHABLEND
标志的作用。
至少我是这么想的。添加了LVBKIF_FLAG_ALPHABLEND
标志后,位图消失了。我尝试了不同的位图,使用不同的图像编辑器创建带有 alpha 通道的位图,但都没有效果。我甚至从资源管理器使用的 shell.dll 中提取了位图。即使这些也不起作用!
但要放弃如此接近目标的事情?我可不会!:)
最简单的解决方案是简单地使用具有白色背景的位图。这在大多数用户没有更改默认系统颜色的系统上看起来不错。但有些用户确实会更改它们,甚至有些人使用红色或其他颜色的背景。在这些系统上,背景图像看起来会非常难看。所以这不是真正的解决方案。
我最终想出的办法是将图像 alpha 混合到一个空位图中,该位图的背景设置为用户设置的系统背景。
就这样我让它工作了。还剩下一个问题:当项目被选中时,水印图像被覆盖,第一列也不透明,也覆盖了水印。
事实证明,这是因为我为控件设置了LVS_EX_FULLROWSELECT
样式。删除该样式最终使水印图像的行为与资源管理器中的行为完全相同。
现在(请敲鼓):添加和提交对话框的屏幕截图
如果有人知道如何使用LVBKIF_FLAG_ALPHABLEND
标志,请告诉我!