首先使用透明之前必须设置该窗口为层级窗口,即增加窗口的扩展风格WS_EX_LAYERED,增加的时候最好使用GetWindowlong获取Ex风格,然后加入后在SetWindowLong设置,最好不适用ModifyStyle增加(有时候不好使,我用vs10可以,但08却不行)。
UpdateLayeredWindow使用之后不会再发出WM_PAINT绘制消息,所有的绘制消息都由UpdateLayeredWindow代而处理,所以不要再OnPaint里做任何事,因为是徒劳的(可能在调用Update..之前有用)。
UpdateLayeredWindow是用兼容的dc去更新当前窗口的dc,所有必须要在兼容的dc上绘制好后去更新当前窗口,故而所有操作应该绘制到兼容的dc上,然后用兼容dc去调用UpdateLayeredWindow去透明更新。
UpdateLayeredWindow最后的参数表明透明的方式,第一种是ULW_ALPHA说明是使用图片本身的Alpha通道去透明(鼠标穿透)当前窗口(如果是最新的bmp格式,支持alpha通道,但必须是32四子节的,否则为3字节即24bit,如果使用4字节,最后字节为alpha通道,该通道决定透明度,如果非得填写24bit即3字节,那么默认的一个alpha通道0,也就是说透明度为0是看不见的,切记!!),如果是这样那么BLENDFUNCTION中的SourceConstantAlpha“源常量透明alpha”是没有用的,如果是用ULW_COLORKEY则说明用颜色掩码去透明窗口,也就是说兼容dc中所绘制的画布中如果颜色与掩码色相同则把这部分透明掉(要在兼容dc中绘制透明色);(SourceConstantAlpha不为0则用该值去透明);
SetLayeredWindowAttributes相当于UpdateLayeredWindow的第二种方法及ULW_COLORKEY,SetLayeredWindow不会导致WM_PAINT不发出,也就是可以在OnPaint中绘制你的东西,但是绘制的颜色如果和SetLayeredWindow中指定的一致则透明掉,否则不透明,另外SetLayeredWindow中透明的地方是可以放置其他组建的!!而UpdateLayeredWindow则不可以(鼠标穿透)。
SetLayeredWindowAttributes经测试必须是非child窗口(Overlapend或PoupUp),否则设置无效!!
在6.0上SetLayeredWindowAttributes使用掩码色的时候也就是第二个参数为掩码色,最后参数为LWA_COLORKEY的时候,只要覆盖控件颜色即可,我使用OnctrlColor返回掩码色画刷,可以将整个窗口置为透明,然后再OnPaint里面绘制非掩码色的图形,即可达到只显示绘制部分图形目的,但是,在VS08中使用alpa透明度透明整个窗口可以达到目的,而使用掩码色的时候无论在OnctrlColor返回何种掩码色,参数中设置该掩码色都是透明的(这点在08中为什么不可用还没搞明白),但是如果去掉OnPaint消息函数却可以达到掩码色透明的作用(或者OnPaint中必须调用父类的OnPaint,否则不起作用!)。
SetLayeredWindowAttributes和UpdateLayeredWindow都可以使得透明区域鼠标穿透,但是实际测试的时候vc6.0上SetLayeredWindowAttributes有时候可以有时候不可以(与鼠标移动快慢有关)。
很重要的一个问题就是vc6.0和vs2008中函数指定的调用约定不一致,vc6.0默认是_stdcall 和vs中函数则不是,所以如果在vs中申明User32.dll中的函数的时候必须手动指定调用约定为WINAPI 或CALLBACK或__stdcall类型,否则在GetProcAddr的时候返回类型不一致,在调用UpdateLayeredWindow或SetLayeredWindowAttributes的时候会出现堆栈被破坏错误!!:Run-Time Check Failure ...
UpdateLayeredWindow与SetLayeredWindowAttributes的另一区别是:UpdateLayeredWindow上所有的东西(包括子控件都必须自己绘制上去,自己响应事件)都由个人处理;SetLayeredWindowAttributes则仅仅处理该窗口的掩码色处理成透明色或将整个窗口的透明度设置为LWA_ALPHA 指定的不透明度值,不影响其他子控件的处理;
以下为updatelayeredwindow使用实例:
void CDlgVideoCompressPage::DrawUI(void)
{
if(NULL == m_hWnd)
return ;
CRect rtClient;
GetClientRect(&rtClient);
HDC hDC = ::GetDC(m_hWnd);
HDC hMemDC = ::CreateCompatibleDC(hDC);
BITMAPINFO bitmapinfo;
bitmapinfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
bitmapinfo.bmiHeader.biBitCount = 32;
bitmapinfo.bmiHeader.biHeight = rtClient.Height();
bitmapinfo.bmiHeader.biWidth = rtClient.Width();
bitmapinfo.bmiHeader.biPlanes = 1;
bitmapinfo.bmiHeader.biCompression = BI_RGB;
bitmapinfo.bmiHeader.biXPelsPerMeter = 0;
bitmapinfo.bmiHeader.biYPelsPerMeter = 0;
bitmapinfo.bmiHeader.biClrUsed = 0;
bitmapinfo.bmiHeader.biClrImportant = 0;
bitmapinfo.bmiHeader.biSizeImage = bitmapinfo.bmiHeader.biWidth * bitmapinfo.bmiHeader.biHeight * bitmapinfo.bmiHeader.biBitCount / 8;
HBITMAP hBitmap = ::CreateDIBSection (hMemDC, &bitmapinfo, 0, NULL, 0, 0);
HBITMAP hOldBitmap = (HBITMAP)::SelectObject (hMemDC, hBitmap);
// draw image
CImage img;
if (SUCCEEDED(img.Load(m_strBkImage)))
{
CRect rtClient;
GetClientRect(&rtClient);
img.Draw(hMemDC, rtClient.left, rtClient.top, rtClient.Width(), rtClient.Height(), 0, 0, img.GetWidth(), img.GetHeight());
img.Destroy();
}
CPoint DestPt(0,0);
CSize psize(rtClient.Width(), rtClient.Height());
BLENDFUNCTION blendFunc32bpp;
blendFunc32bpp.AlphaFormat = AC_SRC_ALPHA;
blendFunc32bpp.BlendFlags = 0;
blendFunc32bpp.BlendOp = AC_SRC_OVER;
blendFunc32bpp.SourceConstantAlpha = 255;
::UpdateLayeredWindow(m_hWnd, hDC, NULL, &psize, hMemDC, &DestPt,0,&blendFunc32bpp, ULW_ALPHA);
::SelectObject (hMemDC,hOldBitmap);
::DeleteObject(hBitmap);
::DeleteDC(hMemDC);
::ReleaseDC(m_hWnd,hDC);
}