半透明窗口中显示标准控件(控件与文字不透明)的实现方案(附源码)
和大家分享一下在半透明窗口中显示标准控件的实现方案。通过层叠窗口可以简单实现半透明与不规则形状窗口的效果,但在其上显示标准控件(控件与文字不透明)却是件比较有挑战的事情,这里会给出一个可行的解决方案。同时实现了一些可重用的窗口类,有相关需求时可以进行引用。先看一下效果图:
一、半透明窗口实现原理
绘制半透明窗口的通常做法是为窗口设置WS_EX_LAYERED属性,通过UpdateLayeredWindow或者SetLayeredWindowAttributes来设置窗口透明度等属性。这两种方法有一些区别、适合的场景也不同。
UpdateLayeredWindow:调用后窗口的绘制被接管,应用负责主动调用这个函数进行绘制,窗口及其控件不再能接收到WM_PAINT消息。可以把带有透明像素的PNG图片直接绘制在窗口上,实现不同程序的透明效果。
SetLayeredWindowAttributes:有两种模式:1. 指定特定像素透明。2. 设置整个窗口统一的透明度(包括控件)。使用这个函数再设置窗口透明,窗口及控件仍可以收到WM_PAINT消息。
需要特别注意的是UpdateLayeredWindow和SetLayeredWindowAttributes的互斥性,在调用SetLayeredWindowAttributes后再调用UpdateLayeredWindow都会失败。
二、实现不规则窗口绘制
不规则的形状由PNG图片通过设置透明区域来实现,程序需要实现全透明区域的鼠标消息也透明。将需要进行透明处理的区域色彩设置为RGB(r,g,b),可以直接设置为RGB(0,0,0),通过SetLayeredWindowAttributes,将COLORREFcrKey参数设为RGB(r,g,b),即可以实现,这个透明效果不只是视觉上的透明,同时也会透过鼠标消息。
三、在半透明背景中实现控件不透明
有时候我们只希望有透明像素的图片来做背景或者希望整个窗口有一定的透明度,但其上的控件不想做透明处理,否则控件上的文字会变得不明显,影响使用。这里提供的是双层窗口的解决方案。前景窗口作为背景窗口的子窗口,两个窗口时刻保持同样尺寸,同时移动,关闭事件关联处理。
前端窗口窗体全透明,并且透过鼠标消息,控件放置在前端窗口,不透明。实现方法是对WM_CTLCOLOR消息进行处理,窗口画刷返回m_crKey(比如RGB(0, 255, 0))颜色的画刷,其它控件默认处理。在窗口初始化的时候使用::SetLayeredWindowAttributes(m_hWnd, m_crKey, 0, LWA_COLORKEY); 设置对这个颜色透明。
HBRUSH CStandardDialog::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor) { if (nCtlColor == CTLCOLOR_DLG) { return CreateSolidBrush(m_crKey); } return CDialog::OnCtlColor(pDC, pWnd, nCtlColor); }
背景窗口使用预设的PNG图片,通过UpdateLayeredWindow绘制,并设置全透明的区域透过鼠标消息。调用UpdateLayeredWindow后窗口内容会被系统缓存,所以在窗口创建初次绘制后,如果没有特殊需要是不需要去重画背景窗口的。
这个方案支持所有标准的控件,同时也支持ActiveX控件,只要继承通用的基类,使用起来十分方便,有兴趣的朋友可以自己玩一下。附件的Demo主窗口展示了不规则形状窗口,镂空效果,控件悬浮效果,及ActiveX控件的使用;控件Demo中罗列了一系列标准控件。在Vista及以后的系统,由于有新API的支持可以实现更简单的半透明窗口(毛玻璃效果),就不用这么费周折了。
四、参考资料
http://www.codeproject.com/Articles/42032/Perfect-Semi-transparent-Shaped-Dialogs-with-Stand
http://www.codeproject.com/Articles/34158/Cool-Semi-transparent-and-Shaped-Dialogs-with-Stan
五、代码下载
http://download.csdn.net/detail/harbinzju/4525285