开发环境:Win10 + VS2010 + Qt 4.8.6 + QGis 2.14.4
其实本文实现的功能类似于QGis中“添加文本数据图层”的一个简化版,本文不会涉及到对话框的使用,不通过与用户互交的方式创建要素,而是直接通过代码方式添加点要素,起到一个抛砖引玉的作用。
(一)先将整个流程大概梳理下:
1、首先创建一个临时(memory)矢量图层 ;
2、将创建的图层添加到地图画布中 ;
3、创建几何要素 ;
4、将几何要素添加到矢量图层中 ;
5、更新图层范围并刷新画布 .
(二)程序代码:
1 // 测试代码 2 3 /* "Point?crs=EPSG:4326&field=id:integer& 4 * field=name:string(50)&index=yes& 5 * memoryid={63152c31-9f38-4410-9983-fc9abe84973f}" 6 */ 7 QString layerProperties = "Point?"; // 几何类型 8 layerProperties.append(QString( "crs=EPSG:4326&" )); // 参照坐标系 9 layerProperties.append(QString( "field=id:integer&field=name:string(50)&" )); // 添加字段 10 layerProperties.append(QString( "index=yes&" )); // 创建索引 11 layerProperties.append(QString( // 临时编码 12 "memoryid=%1" ).arg( QUuid::createUuid().toString() )); 13 14 QgsVectorLayer* newLayer = new QgsVectorLayer( 15 layerProperties, QString( "临时点层" ), QString( "memory" ) ); 16 17 if (!newLayer->isValid()) 18 { 19 return false; 20 } 21 22 // 添加到地图 23 QgsMapLayerRegistry::instance()->addMapLayer(newLayer); 24 25 QgsVectorDataProvider* dateProvider = newLayer->dataProvider(); 26 27 // 创建点 28 QgsFeature MyFeature; 29 MyFeature.setGeometry( QgsGeometry::fromPoint(QgsPoint(102.4443, 32.2123)) ); 30 MyFeature.setAttributes(QgsAttributes() << QVariant(1) << QVariant("test")); 31 32 QgsFeature MyFeature1; 33 MyFeature1.setGeometry( QgsGeometry::fromPoint(QgsPoint(102.4643, 32.2133)) ); 34 MyFeature1.setAttributes(QgsAttributes() << QVariant(2) << QVariant("test1")); 35 36 // 开始编辑 37 newLayer->startEditing(); 38 39 // 添加要素 40 dateProvider->addFeatures(QgsFeatureList() << MyFeature << MyFeature1); 41 42 // 保存 43 newLayer->commitChanges(); 44 45 // 更新范围 46 newLayer->updateExtents(); 47 mMapCanvas->refresh(); 48 return true;
(三)代码分析:
创建临时图层
第3-11行,这段代码可能是我与网上其他的教程中比较不一样的地方,这里通过构造一种URL形式的字符串,通过上面的注释大家应该都大概明白这个字符串的意思了,通过这种形式很简洁方便的使我们将要创建的图层具备了多个条件,特别是简化对于图层字段的添加:
第7行 QString layerProperties = "Point?" 定义了我们创建图层的几何类型,可以是"Point"、"LineString"、"Polygon"、"MultiPoint"、"MultiLineString"、"MultiPolygon"其中之一;
第8行 QString( "crs=EPSG:4326&" ) 是图层的参照坐标系,定义一个正确的坐标系是一个良好的习惯,如果需要一定灵活性可以参照QGis的方式通过对话框选取,或是根据自己的需求来实现,需要改变的仅仅是"EPSG:4326" 而已;
第8行 QString( "field=id:integer&field=name:string(50)&" ) 是定义的图层字段,这也是我觉得很方便的一个地方,多个字段用"&" 进行连接,完整形式为 field=name:type(length,precision) ,从参数看不仅可以定义长度还可以定义其精度;
第10行 QString( "index=yes&" ) 是定义空间索引,对于数据量较大的图层很有用;
第11行 QString( "memoryid=%1" ).arg( QUuid::createUuid().toString() ) 比较有趣,它通过QUuid创建了一个全局唯一标识符(UUID),Qt中解释主要是用于分布式计算环境中的实体标识,而此处是用于当我们多次创建临时图层时的唯一标识符;
第3-5行就是一个URL形式字符串的完整展示,包含上述的所有内容,最后{}中一串数字就是通过QUuid自动创建的标识。虽然我没有尝试过,但是应该除了几何类型必须要定义以外,其他的都是可选项,当然如果我们采用这种方式肯定不仅仅是定义一个图层的几何类型而已。
上面准备工作说了很多,第13行才真正创建临时图层:
QgsVectorLayer* newLayer = new QgsVectorLayer( layerProperties, QString( "临时点层" ), QString( "memory" ) );
QgsVectorLayer类有3个参数,第1个参数就是URL形式的字符串layerProperties,另外经常用的一种很简单的方式就是直接定义其图层的几何类型即可,如"Point";第2个参数是图层的名称;第3个参数是创建图层的类型,这里传入的"memory"代表创建的是一个临时图层。
将图层添加到地图画布中
第21、23行将才创建的图层添加到地图画布中,并且获得一个QgsVectorDataProvider指针,该指针在后面会用到。
创建几何要素
第25-32行创建了两个点要素来展示结果,网上的很多例子为了让大家更清楚,是分开写的,我这个比较省事:
MyFeature.setGeometry( QgsGeometry::fromPoint(QgsPoint(102.4443, 32.2123)) );
使用setGeometry()设置了要素的几何体后,就继续用setAttributes()写入属性,属性类型、顺序与上面我们创建的是一致的,setAttributes()的参数是QgsAttributes对象,而QgsAttributes其实就是QVector<QVariant>,所用我下面代码中是添加的QVariant对象。
MyFeature.setAttributes(QgsAttributes() << QVariant(1) << QVariant("test"));
通过上面的两行代码就成功创建了几何要素并设置了它的属性。
添加几何要素到矢量图层中
第34-41行我们利用上面获得的QgsVectorDataProvider指针将几何要素添加到了矢量图层中,我们先使用startEditing()来使图层可编辑,然后使用commitChanges()来提交改变结果。
刷新
最后更新图层范围,并刷新画布就OK了。
在这里多说一句,如果你按照此方法运行后,在地图画布上不能正常显示,检查下画布是否没有解冻,就是:mapCanvas()->freeze( false ) ,我之前在这吃了亏,由于才接触QGis开发不久,我在程序的其他地方将画布冻结了,导致图层不能正常显示,自己捣鼓了很多次才发现。
(四)效果图:
QGis开发只是本人业余爱好,尽量将自己的一点学习心得与大家分享,如在上述内容中有不正确的地方,或有可以改进的地方欢迎大家指正。