例子:我们要把这个十字准星叠到一个BUTTON控件上,BUTTON位于一个非纯色的背景的窗口上。显示时,紫红色(RGB 0xFF00FF)区域要被挖去,而显示底下的背景。资源图片如下图
实现:
1、按照以前的经验,如果这个Button由我们自己CreateWindowEx建立起来的话,只要在RegisterClass的WNDCLASS结构体里,把HBRUSH设置成GetStockObject(NULL_BRUSH),并且在WM_PAINT消息里首先做SetBkMode(TRANSPARENT)就可以了。但由于现在走了GWES和eVC里RESOURCE文件结合的方法提高开发速度,所以我们不能回到自己CreateWindow的原始时代了。应该考虑在MS制定的GWES游戏规则里跳舞。
2、首先实现图片的去色。实际上很容易,从网上的资料看,以前还得做个单色“掩色”hdc, 然后怎么怎么处理。而WINCE已经把这个功能做好了,提供函数TransparentBlt。
现在我画上去的按钮成这样了:
问题很明显,图像本身是达到去色的目的了,但是按钮的背景仍然是灰色刷子刷出来的,必须把按钮背景变成透明的。
2、首先我想到在WM_DRAWITEM消息里做SekBkMode,没有效果。然后非常想把已注册的WNDCLASS改掉,于是找到函数SetClassLong和GetClassLong,并且INDEX参数给出了GCL_HBRBACKGROUND类型。一切看起来都很美好。于是我写了这样的代码
HBRUSH hbr = GetStockObject(NULL_BRUSH);
int nReturn = SetWindowLong(hWnd, GCL_HBRBACKGROUND, (int)hbr);
结果编译不让过,说没有GCL_HBRBACKGROUND这个东东。我查了下STANDARDSDK_500给出的头文件,里面的确没有GCL_HBRBACKGROUND的定义。于是干脆翻出VS2005在XP下的SDK,硬是找到了GCL_HBRBACKGROUND = (-10). 好,我就强制
SetWindowLong(hWnd, -10, (int)hbr)
结果编译过去了,运行起来nReturn = 0. 伤心啊。再试一把,
HBRUSH hbr = GetWindowLong(hwnd, -10)
运行结果hbr = NULL. 伤心啊,拔凉拔凉的啊。仔细看WINCE产品文档,虽然对用表格列出了一大堆nIndex,但是下面小字Remarks写了“The only values supported for the nIndex parameter are GCL_HICON and GCL_STYLE”,最多再加个GCL_HCURSOR,其他的参数类型WINCE都不支持。我日,浪费感情。
3、在父窗口的PROC里抓住WM_CTLCOLORBTN消息,在里面搞点鬼
case WM_CTLCOLORBTN: { HBRUSH hbr = (HBRUSH)GetStockObject(NULL_BRUSH); SetBkMode( HDC(wParam), TRANSPARENT ); return (int)hbr; }
4、吃过饭,灵光了,想到个很容易的方法。昨天经理刚批评我不踏实做事,喜欢找捷径。嘿嘿这次又被我抄个小捷径了:我先前在代码里已经保留了父窗口背景的hdcOffScreen,现在把子窗口区域的部分拿过来,先画到子窗口上,然后再把子窗口的十字准星叠加上去。实际上,前面一直想的是如何去除背景色,这篇文章的标题也这样写,而实际上背景色根本没被去掉,只是上面又覆盖了一层父窗口的背景图而已,逆向思维。
case WM_DRAWITEM: { LPDRAWITEMSTRUCT lpDIS = (LPDRAWITEMSTRUCT)lParam; if( lpDIS->CtlID = IDC_CROSS ) { BitBlt( lpDIS->hDC, //这个是BUTTON窗口的hdc device,而不是background的,所以我们从{0,0}画起 0, 0, button.nWidth, //CROSS图片的宽和高 button.nHeight, BackGround.hdcOffScreen, //父窗口上背景图的OffScreen hdc, 也就是画在内存里的那份 button.x, //CROSS按钮在背景图上的左上角坐标。我们把背景图上那个区域的内容先画到BUTTON的hdcDevice上面,作为BUTTON窗口的背景。 button.y, SRCCOPY ); TransparentBlt( lpDIS->hDC, 0, 0, button.nWidth, button.nHeight, button.hdcOffScreen, //这次就把CROSS图片在画在内存里的那份hdcOffScreen拿出来,画到hdcDevice上 0, 0, button.nWidth, button.nHeight, 0x00FF00FF); break; } }
最终效果如图
5、用这个方法同样可以实现静态文本控件的“透明”显示, 不过这就不是在WM_DRAWITEM消息里做响应了,而是在WM_CTLCOLORSTATIC消息里,参考代码如下:
case WM_CTLCOLORSTATIC: hdc = (HDC)wParam; if((HWND)lParam == g_hStatic) //如果只想给某个控件设置背景,则可这样过滤 { SetTextColor(hdc, FontColor); //设置文本颜色 SetBkMode(hdc, TRANSPARENT); //文本背景透明 return (LRESULT)GetStockObject(NULL_BRUSH); //控件背景透明 } return DefWindowProc(hWnd, message, wParam, lParam);