目标
不规则窗体也称为异型窗体,像迅雷的飞鸟型窗体就是啦。这篇文章就是要实现这样的窗体。
计划&方案
根据上一篇文章继续扩展。我们有几种方案实现不规则窗体。迅雷就是用一张图片作为窗体的形状,那
么图片的类型我们也要考虑进来。现在是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
(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 GetWindow();
pWnd->SetWindowRgn(wndRgn,TRUE);
pWnd->SetForegroundWindow();
}
源码在此!
通过对比,用常规方法都会产生锯齿,如何消除锯齿?引出我的下文,用GDI+实现完美不规则窗体。