渐变效果在文章《GDI实现水平彩色渐变和垂直彩色渐变(单色渐变双色渐变和多色渐变)的代码》中已经讲过了。渐变是基础,在这个基础上,我们在应用于其他场景,可以产生意向不到的效果。
我们这里实现的是矩形立体渐变和矩形放射渐变效果,GDI实现效果图:
1.矩形立体渐变效果
立体渐变的原理,在于由外到内的深色到浅色(亮色)的变化。或者从内到外看,往外颜色收缩,凝结在一个点。从而产一个立体效果。这个效果和相框很像,可以是内部凸起,也可以是内部凹陷。通过不同颜色的渐变,会有很多意外的效果。
2.矩形放射渐变效果
放射渐变的原理在于外部是浅色(亮色),内部是深色,亮度由内向外发散,形成手电筒一样的效果。一般放射效果要和背景融合,放射最外层的颜色要和背景色一致。
3.矩形平面放射渐变
将放射的长度由外到内,以至于填充了矩形内部的所有区域,就会出现这样的效果。可以看成金字塔效果,也可以看成是深邃的走道的效果。你可以更换颜色来让这两种效果更加明显。
通过按相反方向渐变看到的效果,更加明显:
如果调节的好,就可以产生全面积的立体效果。而这些效果的实现,也是一个函数就搞定了。
实现代码需要注意的地方,就是内存DC的问题。因为我们用了内存缓冲来绘制,然后一次性贴到pDC里。所以,我们开始设置了一个和传入的矩形区一样大小的区域,用于作画。既然是整体作画,那么最后贴图的时候,即bitblt时要从(0,0)开始贴,贴到前四个指定的矩形大小里。
下面是函数的声明:
void GradientLinearOutline(CDC* pDC,CRect rt,COLORREF clr1,COLORREF clr2,int len,bool swap);
前面两个参数就不说了,第三第四个是两个颜色值。从内到外,由clr1渐变到clr2,渐变的长度由len决定。如果不想修改clr1和clr2就像对调颜色,设置swap为true即可。第一个图和第二个图就是对调之后的两种效果哦。
函数使用示例:
CDC *pDC = GetDC();
CRect rtClient(50,50,400,400);
GradientLinearOutline(pDC,rtClient,RGB(255,255,10),RGB(0,0,255),250,false);
函数使用很简单。下面是期待的实现代码了。
void Ctmp_shadowDlg::GradientLinearOutline(CDC* pDC,CRect rt,COLORREF clr1,COLORREF clr2,int len,bool swap)
{
//使用内存DC来加速绘制,防止闪烁
CDC dcMem;
dcMem.CreateCompatibleDC(pDC);
CBitmap bmp;
bmp.CreateCompatibleBitmap(pDC,rt.Width(),rt.Height());
dcMem.SelectObject(&bmp);
//开始内存绘制
if (swap)
{
COLORREF clrTmp = clr1;
clr1 = clr2;
clr2 = clrTmp;
}
//rtTmp用于绘制,rt用于画布
CRect rtTmp(0,0,rt.Width(),rt.Height());//这里要注意,左上角点是0,0,不要直接赋值成rt的左上角的值,绘制的坐标开始就是内存里的(0,0)。在这里今天的花了一些时间整清楚这个问题。如果设置的不对,绘制的内容位置不对。
rtTmp.left += len;
rtTmp.top += len;
rtTmp.right -= len;
rtTmp.bottom -= len;
int width = rtTmp.Width();
int height = rtTmp.Height();
int r1 = GetRValue(clr1);
int r2 = GetRValue(clr2);
int g1 = GetGValue(clr1);
int g2 = GetGValue(clr2);
int b1 = GetBValue(clr1);
int b2 = GetBValue(clr2);
int rSpan = r2 - r1;
int gSpan = g2 - g1;
int bSpan = b2 - b1;
int len_clr=0;
//输出文字这个是可选的代码
CFont font;
font.CreatePointFont(100,_T("微软雅黑"));
dcMem.SelectObject(&font);
dcMem.SetBkMode(TRANSPARENT);
dcMem.SetTextColor(RGB(255,255,255));
dcMem.DrawText(_T("欢迎来到C++技术网。\r\n网址:www.cjjjs.com\r\n一起来探索奇妙的编程世界吧!\r\n放下作业,放下背诵,自由的舞动代码吧。\r\n关注微信公众号:cpp_coder"),&rtTmp,DT_LEFT);
for (int i=0;i<len;i++)
{
COLORREF clr = RGB(r1+(i*rSpan)/len,g1+(i*gSpan)/len,b1+(i*bSpan)/len);
CBrush brush(clr);
rtTmp.InflateRect(1,1,1,1);
dcMem.FrameRect(&rtTmp,&brush);
}
//将内存的数据一次性贴到设备DC中
pDC->BitBlt(rt.left,rt.top,rt.Width(),rt.Height(),&dcMem,0,0,SRCCOPY);
bmp.DeleteObject();
dcMem.DeleteDC();
}