開發環境: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開發只是本人業余愛好,盡量將自己的一點學習心得與大家分享,如在上述內容中有不正確的地方,或有可以改進的地方歡迎大家指正。