目标
不规则窗体也称为异型窗体,像迅雷的飞鸟型窗体就是啦。这篇文章就是要实现这样的窗体。
计划&方案
根据上一篇文章继续扩展。我们有几种方案实现不规则窗体。迅雷就是用一张图片作为窗体的形状,那
么图片的类型我们也要考虑进来。现在是png图片的天下,自带背景透明;对于bmp图片,需要程序处理
一下。
对于常规图形如圆形,只需要SetWindowRgn就可以搞定。对于复杂图形,需要用一点技巧来做。下面用
例子来演示圆形和复杂图形的不规则窗体。
关于SetWindowRgn,参见官方文档。
实践
一、 圆形窗体
这里还要借助另一个类CRgn,它作为SetWindowRgn的主要参数,通过CreateEllipticRgn方法初始化
出圆形区域。具体代码如:
CRgn rgn; rgn. CreateEllipticRgn(0,0,96,96); SetWindowRgn(rgn,TRUE);
接下来封装一个方法来加载png图片:
void ShowPicture() { CImage img; HRESULT result = img.Load(_T("prime.png")); //加强透明化 for(int i = 0; i < img.GetWidth(); i++) { for(int j = 0; j < img.GetHeight(); j++) { unsigned char* pucColor = reinterpret_cast<unsigned char *> (img.GetPixelAddress(i , j)); pucColor[0] = pucColor[0] * pucColor[3] / 255; pucColor[1] = pucColor[1] * pucColor[3] / 255; pucColor[2] = pucColor[2] * pucColor[3] / 255; } } CDC *pDC = GetWindowDC(); int nX = img.GetWidth(); int nY = img.GetHeight(); img.Draw( pDC->m_hDC,0,0); ReleaseDC( pDC ); }
二、 复杂图形窗体
引用vckbase的文章《Windows 中不规则窗体的编程实现》中“根据图像创建region”一节。
技巧:选一种图片中没有的颜色作为背景色(文章中用蓝色),程序将扫描图片的每一个像素,如果不是
背景色,那么就在此位置创建此像素的region,然后把所有这样的region合并起来构成图片,就好像
去掉了背景色一样,成为背景透明。
这里又用到一个合并region的api CombineRgn:
int CombineRgn( CRgn* pRgn1, CRgn* pRgn2, int nCombineMode );
合并的模式我们选择完全合并:
RGN_OR Combines both regions in their entirety (union).
例子如下:
void CAfoatWindowMessageDlg::SetupRegion( CDC *pDC, //DC of this window CBitmap &cBitmap, COLORREF TransColor //the color need remove ) { CDC memDC; //temporary DC memDC.CreateCompatibleDC(pDC); CBitmap *pOldMemBmp=NULL; //Load bmp file pOldMemBmp=memDC.SelectObject(&cBitmap); CRgn wndRgn; // window region //window region init wndRgn.CreateRectRgn(0,0,0,0); BITMAP bit; cBitmap.GetBitmap (&bit);//get the value of bmp file int y; for(y=0;y<=bit.bmHeight ;y++) { CRgn rgnTemp; //temporary region int iX = 0; do { //skip TransColor while (iX <= bit.bmWidth && memDC.GetPixel(iX, y) == TransColor) iX++; //record this point int iLeftX = iX; //Skip none transColor while (iX <= bit.bmWidth && memDC.GetPixel(iX, y) != TransColor) ++iX; //create temporary “region” rgnTemp.CreateRectRgn(iLeftX, y, iX, y+1); //combine "region". wndRgn.CombineRgn(&wndRgn, &rgnTemp, RGN_OR); //delete temporary "region" rgnTemp.DeleteObject(); }while(iX <bit.bmWidth ); iX = 0; } if(pOldMemBmp) memDC.SelectObject(pOldMemBmp); CWnd * pWnd = pDC->GetWindow(); pWnd->SetWindowRgn(wndRgn,TRUE); pWnd->SetForegroundWindow(); }
源码在此!
通过对比,用常规方法都会产生锯齿,如何消除锯齿?引出我的下文,用GDI+实现完美不规则窗体。