当前位置:C++技术网 > 资讯 > GDI渐变:5 斜向渐变(0-90度)代码实现分析

GDI渐变:5 斜向渐变(0-90度)代码实现分析

更新时间:2016-11-06 16:08:09浏览次数:1+次

    在文章《GDI斜向渐变(0-90度)实现原理分析》中, 我们已经很清楚斜向渐变的实现原理了。我们采用的是斜线绘制,叠加形成的渐变效果。所以重点就是在于斜线的绘制了。在看本文前,务必看懂原理,虽说原理不难,不看,还是不好看代码的。

    这里还是放一个效果图看看:

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。代码的逻辑都是按照前面文章的原理来的。就不多解释了。