zoukankan      html  css  js  c++  java
  • Direct2D教程(八)梯度色画刷

    概述

    单色画刷产生的颜色是单一的,比如一个红色画刷只能输出红色,而渐变画刷则不同,它可以输出多种颜色,这些颜色通常是连续的,从一个颜色平滑过渡到另一个颜色,看起来有渐变的效果。渐变画刷又分为两种,一种是ID2D1LinearGradientBrush(线性渐变画刷),另一种是ID2D1RadialGradientBrush(放射渐变画刷),下图显示了这两种画刷的效果。

    线性渐变画刷

    这种画刷的颜色从一个位置线性渐变到另外一个位置,所以在创建这种画刷之前需要确定以下两个属性

    • 起始位置及颜色
    • 终止位置及颜色

    在Direct2D中,结构体D2D1_GRADIENT_STOP用来表示一个位置及其颜色,其定义如下:

    struct D2D1_GRADIENT_STOP {
      FLOAT        position;
      D2D1_COLOR_F color;
    };

    其中第一个成员position表示位置,这个值得范围必须是[0.0, 1.0]。第二个成员color表示颜色。我们用两个这样的结构体变量就可以表示起始/终止位置及颜色了。

    在创建画刷时,需要指定画刷的会制范围,如果待填充图形的范围大于画刷的会制范围,我们需要告诉D2D如何处填充超出范围的部分。这需要通过颜色的扩展方式来指定,颜色扩展的方式用D2D1_EXTEND_MODE这个枚举类型来表示,它的定义如下:

    typedef enum  { 
      D2D1_EXTEND_MODE_CLAMP   = 0,
      D2D1_EXTEND_MODE_WRAP    = 1,
      D2D1_EXTEND_MODE_MIRROR  = 2
    } D2D1_EXTEND_MODE;

    如果大家了解纹理的话,对这几种方式一定不陌生,他们的含义如下:

    • D2D1_EXTEND_MODE_CLAMP,表示按照边缘的颜色进行扩展
    • D2D1_EXTEND_MODE_WRAP,表示重复画刷的颜色
    • D2D1_EXTEND_MODE_MIRROR,也是重复画刷的颜色,不过是以相反的方向进行,所以像镜面效果一样

    这三种扩展方式的效果图如下,这里,矩形的宽度是画刷绘制范围的2倍,也就是说,颜色的扩展是从矩形的中间开始的。

    D2D1_EXTEND_MODE_CLAMP

    D2D1_EXTEND_MODE_WRAP

    D2D1_EXTEND_MODE_MIRROR

    下面开始具体的创建步骤,首先定义两个梯度点并指定其位置及颜色,这里第一个点位置是0,颜色是黄色,第二个点位置是1,颜色是红色。

    D2D1_GRADIENT_STOP gradientStops[2] ;
    gradientStops[0].color = D2D1::ColorF(D2D1::ColorF::Yellow) ;
    gradientStops[0].position = 0.f ;
    gradientStops[1].color = D2D1::ColorF(D2D1::ColorF::Red) ;
    gradientStops[1].position = 1.f ;

    其次,创建梯度点集合,这个集合将作为参数用来创建梯度色画刷,我们使用函数CreateGradientStopCollection来完成这个任务,它的定义如下:

    virtual HRESULT CreateGradientStopCollection(
      [in]   const D2D1_GRADIENT_STOP *gradientStops,
      UINT gradientStopsCount,
      D2D1_GAMMA colorInterpolationGamma,
      D2D1_EXTEND_MODE extendMode,
      [out]  ID2D1GradientStopCollection **gradientStopCollection
    ) = 0;

    参数说明:

    • gradientStops,梯度点数组,也就是上面刚刚创建的。
    • gradientStopsCount,梯度点个数,这里是两个。
    • colorInterpolationGamma,这个参数用来控制颜色插值的方式,有如下两种:
    typedef enum  { 
      D2D1_GAMMA_2_2  = 0,
      D2D1_GAMMA_1_0  = 1
    } D2D1_GAMMA;

    这两种方式的效果图如下,这里我们使用D2D1_GAMMA_2_2。

    extendMode,指定颜色超出绘制范围时如何扩展。这里我们使用D2D1_EXTEND_MODE_CLAMP,也就是按照边缘色扩展。

    gradientStopCollection,这个参数用来接收创建后的梯度点集合。

    创建梯度点集合的代码如下,所有参数前面均已说明。

    // Create gradient stops collection
    ID2D1GradientStopCollection* pGradientStops = NULL ;
    hr = pRenderTarget->CreateGradientStopCollection(
        gradientStops,
        2, 
        D2D1_GAMMA_2_2,
        D2D1_EXTEND_MODE_CLAMP,
        &pGradientStops
        ) ;
    if (FAILED(hr))
    {
        MessageBox(NULL, "Create gradient stops collection failed!", "Error", 0);
    }

    最后,创建线性梯度色画刷。我们使用函数CreateLinearGradientBrush,看看它的定义:

    virtual HRESULT CreateLinearGradientBrush(
      [in]            const D2D1_LINEAR_GRADIENT_BRUSH_PROPERTIES *linearGradientBrushProperties,
      [in, optional]  const D2D1_BRUSH_PROPERTIES *brushProperties,
      [in]            ID2D1GradientStopCollection *gradientStopCollection,
      [out]           ID2D1LinearGradientBrush **linearGradientBrush
    ) = 0;

    参数说明:

    • linearGradientBrushProperties,用来指定画刷的起始位置和终止位置。
    • brushProperties,这是个可选参数,用来指定画刷的透明度及变换矩阵,这里我们指定其为NULL。
    • gradientStopCollection,梯度点集合,一般我们指定两个即可,分别是起始位置和终止位置。
    • linearGradientBrush,用来接收创建好的画刷。

    具体代码如下,画刷的起始和结束位置分别对应矩形的左上角点和右下角点。

    // Create a linear gradient brush to fill in the rectangle
    hr = pRenderTarget->CreateLinearGradientBrush(
        D2D1::LinearGradientBrushProperties(
        D2D1::Point2F(roundRect.rect.left, roundRect.rect.top),
        D2D1::Point2F(roundRect.rect.right, roundRect.rect.bottom)),
        pGradientStops,
        &pLinearGradientBrush
        ) ;
    
    if (FAILED(hr))
    {
        MessageBox(hWnd, "Create linear gradient brush failed!", "Error", 0) ;
        return ;
    }

    效果图

    放射渐变画刷

    这种画刷的颜色从一个中心点向周围扩散,呈放射状,这可能也是其名字的由来吧。创建这种画刷的步骤和上面一样,先创建梯度点及其集合,然后使用函数CreateRadialGradientBrush创建画刷,关于如何创建梯度点及其集合,前面已经说了,所以这里只看创建画刷的步骤。函数CreateRadialGradientBrush的定义如下:

    HRESULT CreateRadialGradientBrush(
      const D2D1_RADIAL_GRADIENT_BRUSH_PROPERTIES &radialGradientBrushProperties,
      [in]   ID2D1GradientStopCollection *gradientStopCollection,
      [out]  ID2D1RadialGradientBrush **radialGradientBrush
    );

    参数说明:

    • radialGradientBrushProperties,画刷属性,用以下结构体来表示:
    struct D2D1_RADIAL_GRADIENT_BRUSH_PROPERTIES {
      D2D1_POINT_2F center;
      D2D1_POINT_2F gradientOriginOffset;
      FLOAT         radiusX;
      FLOAT         radiusY;
    };
      • center, 梯度中心点,从此点开始向外围放射
      • gradientOriginOffset,起始点偏移,一般设置为(0,0)
      • radiusX,椭圆x轴长度
      • radiusY,椭圆y轴长度
    • gradientStopCollection,梯度点集合
    • radialGradientBrush,用来接收创建后的画刷

    代码如下:

    创建椭圆

    D2D1_ELLIPSE g_Ellipse = D2D1::Ellipse(D2D1::Point2F(300, 300), 200, 150);

    创建画刷,这里我们指定起始颜色为黄色,终止颜色为蓝色,填充图形为椭圆,颜色从椭圆的中心向周围发散。

    // Create a linear gradient brush to fill in the rectangle
    hr = pRenderTarget->CreateRadialGradientBrush(
        D2D1::RadialGradientBrushProperties(
        g_Ellipse.point,
        D2D1::Point2F(0, 0),
        g_Ellipse.radiusX,
        g_Ellipse.radiusY),
        pGradientStops,
        &pRadialGradientBrush
        ) ;
    
    if (FAILED(hr))
    {
        MessageBox(hWnd, "Create linear gradient brush failed!", "Error", 0) ;
        return ;
    }

    效果图

    使用渐变画刷配合椭圆及圆角矩形可以创建出非常漂亮的Button控件,如果你喜欢自定义控件,不妨试一试。

    == Happy Coding ==

    作者:zdd
    出处:http://www.cnblogs.com/graphics/
    本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利.
  • 相关阅读:
    关于APPIUM滑动手机屏幕的操作
    关于robotframework,app,appium的xpath定位问题及常用方法
    测试行业学习的知识体系
    APPIUM环境搭建及APP配合RF自动化的操作步骤
    关于RF在实践WEB UI自动化测试时,碰到的问题
    高并发
    [emerg] could not build server_names_hash, you should increase server_names_hash_bucket_size:32
    Nginx 反向代理与负载均衡详解
    Nginx 服务器安装及配置文件详解
    牛客网多校训练4 A Ternary String(高阶幂次取模)
  • 原文地址:https://www.cnblogs.com/graphics/p/2764876.html
Copyright © 2011-2022 走看看