在文章《GDI斜向渐变(0-90度)实现原理分析》中, 我们已经很清楚斜向渐变的实现原理了。我们采用的是斜线绘制,叠加形成的渐变效果。所以重点就是在于斜线的绘制了。在看本文前,务必看懂原理,虽说原理不难,不看,还是不好看代码的。
这里还是放一个效果图看看:
各种角度的渐变都是通过一个函数实现的,你只需要输入一个角度值即可。函数的声明如下:
void GradientLinearRotate(CDC* pDC,CRect rt,COLORREF clr1,COLORREF clr2,int angle);
第一个为绘图的CDC指针,第二个是渐变的矩形大小,clr1和clr2是起止渐变色。angle为旋转的角度。在原理分析文章中,已经给出了各种角度的效果图,就不在这里给出了。
函数使用示例:
CDC *pDC = GetDC();
CRect rtClient;
GetClientRect(&rtClient);
GradientLinearRotate(pDC,rtClient,RGB(255,255,0),RGB(0,0,255),60);
使用超级简单,有木有?!
当然,大家最关心的就是函数代码了。
下面是完整的函数实现代码:
void GradientLinearRotate(CDC* pDC,CRect rt,COLORREF clr1,COLORREF clr2,int angle)
{
//以左上角为坐标原点,angle为线条的斜度
int width = rt.Width();
int height = rt.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 = 0;
int len_clr=0;
//0度和90度做特殊处理,方便下面循环处理。90度的tan值是无穷大。
if (angle==0)len_clr = len = height;
else if(angle==90)len_clr = len = width;
else len_clr = len = width+ height / tan((double)angle*3.14/180);
//使用内存DC来加速绘制,防止闪烁
CDC dcMem;
dcMem.CreateCompatibleDC(pDC);
CBitmap bmp;
bmp.CreateCompatibleBitmap(pDC,rt.Width(),rt.Height());
dcMem.SelectObject(&bmp);
//开始内存绘制
for (int i=0;i<len;i++)
{
COLORREF clr = RGB(r1+(i*rSpan)/len_clr,g1+(i*gSpan)/len_clr,b1+(i*bSpan)/len_clr);
//COLORREF clrR = RGB(255,0,0);
//COLORREF clrG = RGB(0,255,0);
//COLORREF clrB = RGB(0,0,255);
//CPen penR(PS_SOLID,1,clrR);
//CPen penG(PS_SOLID,1,clrG);
//CPen penB(PS_SOLID,1,clrB);
CPen pen(PS_SOLID,2,clr);
dcMem.SelectObject(&pen);
//根据旋转计算两个坐标点的值
if (angle==0)
{
dcMem.MoveTo(0,i);
dcMem.LineTo(width,i);
}
else
{
dcMem.SelectObject(&pen);
dcMem.MoveTo(i,0);
int y = (int)i*tan((double)angle*3.14/180);
dcMem.LineTo(0,y);
//画背景网格斜线
//if (i%10==0)
//{
// dcMem.SelectObject(&penR);
// dcMem.MoveTo(i,0);
// int y = (int)i*tan((double)angle*3.14/180);
// dcMem.LineTo(0,y);
//}
//else if(i%3==1)
//{
// dcMem.SelectObject(&penG);
// dcMem.MoveTo(i,0);
// int y = (int)i*tan((double)angle*3.14/180);
// dcMem.LineTo(0,y);
//}
//else if(i%3==2)
//{
// dcMem.SelectObject(&penB);
// dcMem.MoveTo(i,0);
// int y = (int)i*tan((double)angle*3.14/180);
// dcMem.LineTo(0,y);
//}
}
}
//将内存的数据一次性贴到设备DC中
pDC->BitBlt(rt.left,rt.top,rt.Width(),rt.Height(),&dcMem,0,0,SRCCOPY);
bmp.DeleteObject();
dcMem.DeleteDC();
}
注释的代码,是绘制红绿蓝三条斜着的网格线,是用于研究斜线出现黑点黑线原因的。这个也是提醒你,斜线的宽度要大于1。代码的逻辑都是按照前面文章的原理来的。就不多解释了。