当前位置:C++技术网 > 精选软件 > GDI渐变:6 矩形立体渐变、矩形放射渐变和矩形平面放射渐变原理以及代码实现

GDI渐变:6 矩形立体渐变、矩形放射渐变和矩形平面放射渐变原理以及代码实现

更新时间:2016-11-07 20:45:47浏览次数:1+次

    渐变效果在文章《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(); 
}