前段时间有讲过如何用vc实现桌面歌词的效果,其实我原本是想实现WndShadow的一个渐变的阴影窗口的,桌面歌词只是顺路捡起来的而已。既然我们已经知道利用UpdateLayeredWindow来实现一个不规则窗口,或者说是窗口不需要部分被透明化的方法,那么我们思考同一个窗口能不能有不同的透明值呢,如果窗口的透明值是渐变的,就实现了一个模糊渐变的磨砂样效果了。

我们回去再看看UpdateLayeredWindow这个函数的原型:
 BOOL UpdateLayeredWindow(
  HWND hwnd,
  HDC hdcDst,
  POINT *pptDst,
  SIZE *psize,
  HDC hdcSrc,
  POINT *pptSrc,
  COLORREF crKey,
  BLENDFUNCTION *pblend,
  DWORD dwFlags
  );
当dwFlags的值为ULW_ALPHA的时候,我们就可以根据位图的alpha值来确定这个像素点所在窗口的透明值。除此之外,我们要需要了解的一个东西就是BLENDFUNCTION,在百度找到的资料的第五点提示如下:

5、如果源位图既有SourceConstantAlpha值(也就是它的值不是255),每个像素又有透明度值,那么源位图的每一个像素将首先乘以SourceConstantAlpha的值,然后根据每个像素的透明度值混合,如下表中所示。同样,SourceConstantAlpha除以了255,因为它的范围是从0到255.
  Src.Red = Src.Red * SourceConstantAlpha / 255.0;
  Src.Green = Src.Green * SourceConstantAlpha / 255.0;
  Src.Blue = Src.Blue * SourceConstantAlpha / 255.0;
  Src.Alpha = Src.Alpha * SourceConstantAlpha / 255.0;

搞清楚了这些我们就可以动手来实现这样的效果了,先看看吵吵我做出来的效果吧:

ChaoShadow

    红色部分即是一个透明渐变的窗口,接下来我们看看实现的方法:
1、用vc建立一个内存位图,当然,这个位图一定是32位的,为什么,因为32位的位图才会有alpha通道,一个像素点包括四个字节,即RGB分量和透明值。

m_Width=200;
	m_Height=200;

	BITMAPINFO bmi;        // bitmap header

	ZeroMemory(&bmi, sizeof(BITMAPINFO));
	bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
	bmi.bmiHeader.biWidth = 200;
	bmi.bmiHeader.biHeight = 200;
	bmi.bmiHeader.biPlanes = 1;
	bmi.bmiHeader.biBitCount = 32;         // four 8-bit components
	bmi.bmiHeader.biCompression = BI_RGB;
	bmi.bmiHeader.biSizeImage = 200 * 200 * 4;

	BYTE *pvBits;          // pointer to DIB section
	HBITMAP hbitmap = CreateDIBSection(NULL, &bmi, DIB_RGB_COLORS, (void **)&pvBits, NULL, 0);

	ZeroMemory(pvBits, bmi.bmiHeader.biSizeImage);

2、填充位图数据,这点算是最难的了,我们需要靠算法来创建我们的位图,当然,你也可以用ps来绘制一个32位带alpha通道的位图,不过貌似更改alpha值不是那么容易做到了。在位图的那一块数据中,我们需要明白数据排列顺序和四个字节的顺序,通过我的验证结果是这样子的,位图的数据是从从左下至右上的排列顺序,其中每四个字节的顺序是B-G-R-alpha。于是根据水平和垂直坐标定位像素点的函数如下:

void ChaoShadow::setPosColor(BYTE * P,int X,int Y,unsigned char R, unsigned char G,unsigned char B,unsigned char A)
{
	int num=(m_Height-1-Y)*m_Width*4+X*4;
	P[num]=B*A/255;//为什么要乘以这个东西上面有说明哦
	P[num+1]=G*A/255;
	P[num+2]=R*A/255;
	P[num+3]=A*A/255;
}

3、填充颜色和alpha渐变通道值来实现一个渐变窗口:

for(int i=100;i<200;i++)
	{

	
	for(int j=0;j<200;j++)
	{
		setPosColor(pvBits,j,i,255,0,0,i);//设置像素点的颜色和透明值
	}
	}
	HDC hMemDC = CreateCompatibleDC(NULL);
	HBITMAP hOriBmp = (HBITMAP)SelectObject(hMemDC, hbitmap);

	POINT *pDst;
	pDst=new POINT;
	pDst->x=0;
	pDst->y=0;
	POINT *PSrc;
	PSrc=new POINT;
	PSrc->x=0;
	PSrc->y=0;
	SIZE *mySize;
	mySize=new SIZE;
	mySize->cx=200;
	mySize->cy=200;
	BLENDFUNCTION blendPixelFunction= { AC_SRC_OVER, 0, 255, AC_SRC_ALPHA};
	UpdateLayeredWindow(hDc,pDst, mySize,hMemDC,PSrc,0,&blendPixelFunction,ULW_ALPHA);

好了,至此我们就已经完成了窗口的渐变颜色功能了,接下来要做的事情是,改善算法,使得我们创造出一个围绕窗口的渐变的阴影,当然,这是下次再做的事情了,先洗澡去了。

吵吵微信朋友圈,请付款实名加入:

吵吵 吵吵

2条回应:“vc实现窗口透明渐变即同一个窗口有不同透明值”

  1. 这个还真看不懂啊

  2. 上海做网站说道:

    谢谢分享,写的不错

发表评论

电子邮件地址不会被公开。 必填项已用*标注