QGis二次开发基础 — 矢量图层属性图表显示

矢量图层属性的图表显示功能,帮助我们以图形化的方式更直观地显示数据当中的信息,使得数据生动起来的同时也变得更美观。QGis当中提供了默认三种图表,分别是饼状图、柱状图以及文本图。下面我们就来看一下在二次开发中如何实现这样的功能。

饼状图
这里写图片描述

文本图
这里写图片描述

柱状图
这里写图片描述

QgsDiagramRendererV2

首先,认识一下控制图表显示的渲染类 QgsDiagramRendererV2。这个类在 QgsVectorLayer 中具有引用指针,通过 QgsVectorLayer 的 setDiagramRenderer() 方法,传入一个 QgsDiagramRendererV2 的实例,当前的矢量图层就会以设置的方法来渲染显示图表。但是 QgsDiagramRendererV2 是一个抽象类,并不能直接实现它的实例,而应该进一步选择实现它的子类。继承关系如下图:

这里写图片描述

其中 QgsLinearlyInterpolatedDiagramRenderer 和 QgsSingleCategoryDiagramRenderer 分别是具体的渲染方法类,具体算法的不同请参阅API文档,这里仅讨论快速让图表显示出来,至于显示的方式,还需要同学们根据需求自己进行设置。

有了渲染类,到底是以饼状图、文本图还是柱状图的方式来显示,还需要通过渲染类的 setDiagram() 方法来设置。下面就来看看具体的图表类。

Diagram类

QGis当中提供的图表类包括三个,QgsPieDiagramQgsTextDiagram 和 QgsHistogramDiagram,它们分别对应于饼状图、文本图和柱状图,都是继承自 QgsDiagram 类,继承关系如下图:

这里写图片描述

图表类并不需要额外的参数,仅初始化就可以了。当然,它们具有一系列的参数可供配置。如果将每个类的参数都封装在类里面,不仅重复代码会增多,而且并不便于管理,况且不论是哪一种图表,它们都具有某些共通的设置参数。于是QGis把这些参数通过其他类进行统一管理。具体来说,有两个,一个是QgsDiagramSettings,用于配置针对图表的参数,另一个是 QgsDiagramLayerSettings,是更高一级的参数,将图表类作为一个图层,配置与矢量要素的显示关系。

QgsDiagramSettings

专门用于图表配置属性的类,这个类的定义是包含在 qgsdiagramrendererV2.h 这个文件中的,由于上文用到了 QgsDiagramRendererV2,想必你应该已经添加了这个头文件的 include 了。

QgsDiagramSettings 类包含的图表属性包括字体、大小、颜色等等,下图来源于 API 文档,可以比较详细的看到可配置的属性:

这里写图片描述

为了方便大家理解上面的这些属性,列表如下,利用这些参数设置,基本就能够满足图表的不同显示方式了。

Name 说明
angleOffset 起始角度(仅饼状图)
backgroundColor 背景颜色
barWidth 柱宽度(仅柱状图)
categoryAttributes \\ categoryColors 用于控制不同属性显示不同颜色
diagramOrientation 图表方向
font 字体(仅文本图
labelPlacementMethod 图表中文本的显示位置(仅文本图),包括Hight和XHight
maxScaleDenominator \\ minScaleDenominator 显示尺度。大于或小于缩放尺度,图表将不再显示
minimumSize 图表显示的最小尺寸。小于这个尺寸的图表会放大到这个尺寸显示
penColor \\ penWidth 控制轮廓的颜色和宽度
scaleByArea 是否根据要素面积进行缩放图表(仅polygon要素)
size 图表大小
sizeType 图表大小的单位,包括 MM 和 MapUnits
transparency 透明度

QgsDiagramLayerSettings

这个类控制图表作为一个图层,具有的显示方式,包括距离要素的长度、显示相对于要素的方式等。同样,从API文档中查看它具有的属性。

这里写图片描述

还是列表进行说明:

Name 说明
ct QgsCoordinateTransform类型常量指针
dist 与要素相隔的距离
fields 指定用于显示图表的要素字段
geometries QgsPalGeometry类型列表,指示当前要素类型
obstacle 是否阻挡要素显示
palLayer 当前图层指针
placement 显示位置,包括AroundPoint\\OverPoint\\Line\\Curved\\Horizontal\\Free
placementFlags 现状要素的显示位置,包括 OnLine\\AboveLine\\BelowLine\\MapOrientation
priority 显示优先级
renderer 指定QgsDiagramRendererV2类型的指针
xform QgsMapToPixel类常量
xPosColumn \\ yPosColumn 由数据定义图表位置

调用方式

通过上文的分析,要实现图表功能就比较清晰了。

首先,要有一个 QgsVectorLayer,指向当前的矢量图层

// 这一句是获取当前图层,修改成你自己获取当前图层的方式
QgsVectorLayer* layer = qobject_cast<QgsVectorLayer*>( activeLayer() );
  •  

然后,需要一个具体的 Diagram,这里以柱状图为例

QgsDiagram* diagram = new QgsHistogramDiagram();
  •  

接着,定义 QgsDiagramSettings类,并设置它的参数

QgsDiagramSettings ds; // diagram的设置项
ds.transparency = 0; // 设置透明度
...
...
  •  

同样,定义 QgsDiagramLayerSettings类,并设置参数

QgsDiagramLayerSettings dls;
dls.dist = 0;
dls.priority = 5;
...
...
  •  

还需要选择渲染类,并设置它的一些属性,这里以 QgsLinearlyInterpolatedDiagramRenderer 类为例。

QgsLinearlyInterpolatedDiagramRenderer* dr = new QgsLinearlyInterpolatedDiagramRenderer();
dr->setLowerValue( 0.0 );
...
...
  •  

最后,层层调用,并刷新一下显示

dr->setDiagram( diagram );
dr->setDiagramSettings( ds );
layer->setDiagramRenderer( dr );
layer->setDiagramLayerSettings( dls );
layer->triggerRepaint();
mapCanvas->refresh();
  •  

示例代码

最后,放上本文的示例代码,供大家参考。

注:这里仅以柱状图为例,其他类型图表类似,只是配置参数略有不同而已

void qgis_dev_layerPropDialog::setDiagramProperty()
{
    // 这一句是获取当前图层,修改成你自己获取当前图层的方式
    QgsVectorLayer* layer = qobject_cast<QgsVectorLayer*>( activeLayer() ); 

    QgsDiagram* diagram = 0;
    QString diagramType = "Hist"; // 这一句修改成获取图表类型的代码
    bool scaleAttributeValueOk = false;

    QgsVectorDataProvider* provider = layer->dataProvider();
    double maxVal = 0;
    int fld = 2;
    if ( fld != -1 )
    {
        bool ok = false;
        double val = provider->maximumValue( fld ).toDouble( &ok ); // 获取该字段的最大值
        if ( ok )
        {
            maxVal = val;
        }
    }
    bool mValueLineEdit = false;

    if ( diagramType == "Text" )
    {
        //diagram = new QgsTextDiagram();
    }
    else if ( diagramType == "Pie" )
    {
        //diagram = new QgsPieDiagram();
    }
    else // if ( diagramType == DIAGRAM_NAME_HISTOGRAM )
    {
        diagram = new QgsHistogramDiagram();
    }

    #pragma region 设置diagram属性

    QgsDiagramSettings ds; // diagram的设置项
    //ds.font = mDiagramFont; // 设置字体
    ds.transparency = 0; // 设置透明度

    QList<QColor> categoryColors; // 颜色
    QList<QString> categoryAttributes; // 属性

    QColor color = QColor( 255, 0, 0 );
    color.setAlpha( 255 - ds.transparency );
    categoryColors.append( color );
    categoryAttributes.append( "ELEV" );

    ds.categoryColors = categoryColors;
    ds.categoryAttributes = categoryAttributes;
    ds.size = QSizeF( 1, 1 );
    ds.sizeType = static_cast<QgsDiagramSettings::SizeType>( 0 );
    ds.labelPlacementMethod = static_cast<QgsDiagramSettings::LabelPlacementMethod>( 1 );
    ds.scaleByArea = true;


    ds.minimumSize = 0;

    ds.backgroundColor = QColor( 0, 0, 0 ); // 背景色
    ds.penColor = QColor( 0, 0, 0 ); // 轮廓颜色
    ds.penWidth = 1; // 轮廓宽度

    ds.minScaleDenominator = -1;
    ds.maxScaleDenominator = -1;

    // Diagram 方向 (histogram)
    ds.angleOffset = 1440;
    ds.diagramOrientation = static_cast<QgsDiagramSettings::DiagramOrientation>( 0 );

    ds.barWidth = 5; // 宽度
    #pragma endregion 设置diagram属性

    QgsLinearlyInterpolatedDiagramRenderer* dr = new QgsLinearlyInterpolatedDiagramRenderer();
    dr->setLowerValue( 0.0 );
    dr->setLowerSize( QSizeF( 0.0, 0.0 ) );
    dr->setUpperValue( 2 );
    dr->setUpperSize( QSizeF( 2, 2 ) );

    bool isExpression = true;
    dr->setClassificationAttributeIsExpression( isExpression );

    dr->setClassificationAttributeExpression( "" );

    dr->setDiagram( diagram );
    dr->setDiagramSettings( ds );
    layer->setDiagramRenderer( dr );

    QgsDiagramLayerSettings dls;
    dls.dist = 0;
    dls.priority = 5;

    dls.xPosColumn = -1;
    dls.yPosColumn = -1;
    dls.placement = static_cast<QgsDiagramLayerSettings::Placement>( 0 );

    dls.placementFlags = 0;
    layer->setDiagramLayerSettings( dls );

    layer->setTitle( "" );

    QgsVectorSimplifyMethod simplifyMethod = m_layer->simplifyMethod();
    simplifyMethod.setSimplifyHints( QgsVectorSimplifyMethod::NoSimplification );
    simplifyMethod.setThreshold( 1 );
    simplifyMethod.setForceLocalOptimization( true );
    simplifyMethod.setMaximumScale( 1 );
    layer->setSimplifyMethod( simplifyMethod );

    layer->triggerRepaint();
    m_mapCanvas->refresh(); // 改成你自己的 map canvas
}
  • 若文中有错误,请不吝指正,谢谢!

© 版权声明
THE END
喜欢就支持一下吧
点赞969 分享