最近工作比较闲,可以写点技术文章了。鄙人不才,可能会有所疏漏,只希望可以起到抛砖引入的作用。
前面写过一篇用透明Png图片来创建不规则窗体的文章,本文则主要讲述通过代码来在自定义透明。(有的时候需要在窗口的某些位置打个洞,我以前做过这样的需求,哈哈。)
透明窗口当然需要给窗口加上WS_EX_LAYERED样式,在绘制时调用UpdateLayeredWindow来贴图,源DC中所有像素点中alpha值为0则全透了。(补充下,每个像素点占4个字节,分别是:A (透明度alpha)R G B(三原色),在内存中存储时是反的:B G R A)我们要制定某块区域透明,就需要在贴图前,设置区域内像素的alpha值为0(全透),也可以为其他值(部分透明)……设置前,需要用CreateDIBSection获取DC中背景位图的像素值到指定的buffer中,燃火我们遍历这个buffer就可以设置了。
主要看WM_PAINT消息的处理部分代码:
case WM_PAINT:
{
hdc = BeginPaint(hWnd, &ps);
// TODO: 在此添加任意绘图代码...
RECT rcClient;
GetClientRect(g_hWnd, &rcClient);
int nWidth=rcClient.right-rcClient.left;
int nHeight=rcClient.bottom-rcClient.top;
if ( NULL == g_hMemDC )
{
g_hMemDC=CreateCompatibleDC(hdc);
//g_hBitmap=LoadBitmap(hInst, MAKEINTRESOURCE(IDB_BITMAP1));
g_hBitmap=CreateCompatibleBitmap(hdc, nWidth, nHeight);
SelectObject(g_hMemDC, g_hBitmap);
BITMAPINFO bi;
ZeroMemory(&bi, sizeof(BITMAPINFO));
bi.bmiHeader.biSize=sizeof(BITMAPINFOHEADER);
bi.bmiHeader.biWidth=nWidth;
bi.bmiHeader.biHeight=nHeight;
bi.bmiHeader.biPlanes=1;
bi.bmiHeader.biBitCount=32;
bi.bmiHeader.biCompression=BI_RGB;
bi.bmiHeader.biSizeImage=nWidth*nHeight*4;
BYTE* lpData=NULL;
HRGN hRgn=CreateRoundRectRgn(0, 0, 100, 100, 100, 100);
g_hBitmap=CreateDIBSection(g_hMemDC, &bi, DIB_RGB_COLORS, (void**)&lpData, NULL, 0);
for (int i=0; i<nHeight; ++i)
for (int j=0; j<nWidth; ++j)
{
int nPos=( (nHeight-i-1)*nWidth+j)*4;
//lpData[nPos+0]=0xff;
//lpData[nPos+3]=0x00;
if ( !PtInRegion(hRgn, j, i) )
lpData[nPos+3]=0x0f;
else
{
lpData[nPos+0]=0xff;
lpData[nPos+3]=0x00;
}
}
DeleteObject(hRgn);
SelectObject(g_hMemDC, g_hBitmap);
}
POINT pt={300, 300};
POINT pt1={0, 0};
SIZE size={300, 300};
BLENDFUNCTION bf;
ZeroMemory(&bf, sizeof(bf));
bf.SourceConstantAlpha=255;
bf.AlphaFormat=AC_SRC_ALPHA;
LONG lStyle=GetWindowLong(hWnd, GWL_EXSTYLE);
SetWindowLong(hWnd, GWL_EXSTYLE, lStyle|WS_EX_LAYERED);
// RECT rc={0, 0, 50, 50};
// ::SetBkColor(g_hMemDC, 0xffffff);
// ::ExtTextOut(g_hMemDC, 0, 0, ETO_OPAQUE, &rc, NULL, 0, NULL);
UpdateLayeredWindow(hWnd, hdc, &pt, &size, g_hMemDC, &pt1, 0, &bf, ULW_ALPHA);
EndPaint(hWnd, &ps);
break;
}
PtInRegion是来判断这个点是否在你要穿透的区域
这里只是一个很简单的小例,读者可以自行扩展。打算上传代码的,不过CSDN上传的步骤实在是太麻烦了!