半透明窗口中的孤岛

几天前在 CSDN 上有人问及一个问题:如何使得一个半透明窗口上,控件所占据的位置是不透明的?

开始有人提到使用 SetLayeredWindowAttributes() API,但考虑到该 API 会将整个窗口设置为一致的透明度,显然不可能满足问题中的要求。所以老汉认为应该使用 UpdateLayeredWindow() API 来完成这一工作,为了不重复输入,把我当时的回复抄录如下:

真正可以使用的 API 是 UpdateLayeredWindow()。此函数可以根据一幅选入到 DC 中去的 32 位位图的每个像素的 Alpha 通道值设置窗口上对应像素的半透明度。其实现在楼主要做得就是,总是生成一幅和窗口大小一样的 32 位位图,把控件占据的区域的位图像素的 Alpha 通道值全部设置为 255,即不透明,而其余地方的像素则可以根据需要设置为适当的半透明,然后再调用本函数即可。需要注意的是,如果窗口的大小可以改变的话,显然每次都需 要动态生成此位图,并调用本函数对窗口进行更新。

为了验证这一想法,我特意完成了一个类 CWindowUpdater,代码附后。使用者仅需在顶级窗口的 WM_SIZE 消息的响应中调用 CWindowUpdater::Update(hwnd) 即可。

需要说明的是,这种方法虽然在视觉上解决了上述问题,但是带来了另外一个问题。经过 UpdateLayeredWindow() 作用的窗口,其内容会因此而变成一幅静态图像,所以后果会成为,虽然控件是不透明的,但是用户与控件交互(例如鼠标点击,键盘输入等)时原本应该有的视觉 反馈(例如按钮成为下压状态)却全部不可见了,这使得这种方法基本上是鸡肋,并没有真正意义上的实用价值。如果有哪位实现了更完美的解决方案,望不吝赐 教。不过,它至少在技术上演示了如何设置窗口上每个像素的透明度。

发表评论

电子邮件地址不会被公开。 必填项已用*标注