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() );
 
 
  • 1
  • 2

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

QgsDiagram* diagram = new QgsHistogramDiagram();
 
 
  • 1

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

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

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

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

 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

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

QgsLinearlyInterpolatedDiagramRenderer* dr = new QgsLinearlyInterpolatedDiagramRenderer();
dr->setLowerValue( 0.0 );
...
...
 
 
  • 1
  • 2
  • 3
  • 4

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

dr->setDiagram( diagram );
dr->setDiagramSettings( ds );
layer->setDiagramRenderer( dr );
layer->setDiagramLayerSettings( dls );
layer->triggerRepaint();
mapCanvas->refresh();
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

示例代码

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

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

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
}
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112

若文中有错误,请不吝指正,谢谢!

  • 5
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值