VC创建不规则窗口

创建不规则窗口的三种方法:通过区域相关API设置窗口的区域SetWindowRgn;通过SetLayeredWindowAttributes来指定特殊的透明颜色,让背景图的部分位置全透从而实现窗口的“不规则”;通过UpdateLayeredWindow来指定特殊颜色透明或者根据图片的ALPHA值来设置窗口全透。

方法一是是真正的异形不规则窗口,而方法二、三则是通过部分区域全透来实现异形。这里只讨论后面两种方法,使用广泛也易于实现。

不管是SetLayeredWindowAttributes还是UpdateLayeredWindow在调用前都需要为窗口加上WS_EX_LAYERED扩展属性,否则API调用失败,详见MSDN;

<span style="color:#999999;">    DWORD dwExStyle=GetWindowLong(m_hWnd, GWL_EXSTYLE);
   ::SetWindowLong(m_hWnd, GWL_EXSTYLE, dwExStyle|WS_EX_LAYERED);</span>

1、使用SetLayeredWindowAttributes来创建不规则窗口

首先需要一张图,需要全透的地方我们用同一种颜色来填充:


需要透明的区域我用的纯白色0XFFFFFF来填充的,那么我们就需要指定SetLayeredWindowAttributes的第二个参数为0XFFFFFF,第三个参数LWA_COLORKEY,即使颜色值为纯白的像素点全透。

接下来要做的就是双缓冲绘图了,这个很基础的了,不细说上代码:

<span style="color:#999999;">case WM_PAINT:
		{
			hdc = BeginPaint(hWnd, &ps);
			// TODO: 在此添加任意绘图代码...
			HDC hMemDC=CreateCompatibleDC(hdc);
			HBITMAP hBkBmp=LoadBitmap(hInst, MAKEINTRESOURCE(IDB_BITMAP1));
			HBITMAP hOldBmp=(HBITMAP)SelectObject(hMemDC, hBkBmp);
			BitBlt(hdc, 0, 0, 224, 114, hMemDC, 0, 0, SRCCOPY);
			SelectObject(hMemDC, hOldBmp);
			DeleteDC(hMemDC);
			DeleteObject(hBkBmp);
			EndPaint(hWnd, &ps);
			break;
		}</span>

最后的效果如图:


完整源码下载地址:点击下载代码

2、使用UpdateLayeredWindow来设置不规则窗口,和SetLayeredWindowAttributes一样,既可以指定透明颜色值,也可以根据图片像素点的实际ALPHA值来设置透明度。指定透明颜色值的话和上面的例子差不多,不再啰嗦。我们可以手动来设置某些像素的ALPHA值为0,使其全透。

CreateDIBSection将位图像素值加载到内存中,通过循环来设置我们需要透明的区域的ALPHA值为0,从而实现不规则窗口:

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);
			UpdateLayeredWindow(hWnd, hdc, &pt, &size, g_hMemDC, &pt1, 0, &bf, ULW_ALPHA);
			EndPaint(hWnd, &ps);
			break;
		}

左上角的原型区域时设置的特殊透明区域,效果图:

VC创建不规则窗口_第1张图片

完整源码下载地址:点击下载源码

另外,切记SetLayeredWindowAttributes和UpdateLayeredWindow 混合使用的时候:

Note that once SetLayeredWindowAttributes has been called for a layered window, subsequent UpdateLayeredWindow calls will fail until the layering style bit is cleared and set again.(MSDN)

使用了SetLayeredWindowAttributes 后调用UpdateLayeredWindow 需要重新设置 

<span style="color:#999999;">WS_EX_LAYERED</span>
<span style="color:#999999;">
</span>

属性,否则API调用失败。

你可能感兴趣的:(VC创建不规则窗口)