您的位置:首页 > 其它

VC创建不规则窗口

2014-06-20 23:38 337 查看
创建不规则窗口的三种方法:通过区域相关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;
}


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






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

另外,切记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调用失败。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: