最近工作比较闲,可以写点技术文章了。鄙人不才,可能会有所疏漏,只希望可以起到抛砖引入的作用。
前面写过一篇用透明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上传的步骤实在是太麻烦了!