1. 程式人生 > >QGis(四)shp向量圖層新增新欄位

QGis(四)shp向量圖層新增新欄位

新增一個新的欄位到shp檔案中,並且從Excel裡匯入資料到該欄位。原shp檔案裡的欄位ID應該與Excel裡的欄位ID一一對應才能正確的匯入。下圖分別是shp的欄位和Excel的欄位

將class欄位新增到shp中去:

(1)從Excel中讀取資料(為了讀取方便,存為.csv或者txt檔案)

QStringList readFromCSV(QString mfilename)
{
	QStringList readlist;
 	if (mfilename !="")
	{
		QFileInfo csvFI(mfilename);
		QString ext = csvFI.suffix();
		if ( ext == "csv" || ext == "txt")
		{
			QFile *importFile = new QFile(mfilename);
			if ( !importFile->open(QIODevice::ReadOnly | QIODevice::Text))
			{
				QMessageBox::information(NULL, "error", "Cannot open import file !", QMessageBox::Yes | QMessageBox::No);
				return readlist;
			}
			readlist.clear();
			QTextStream readIn(importFile);//讀入檔案
			while ( !readIn.atEnd()) //讀取每一行
			{
				readlist.push_back(readIn.readLine());
			}

			importFile->close();
		}
	}
	return readlist;
}
返回的readlist是所有行的資料,下面要根據Id來將每一行後面的class欄位插入shp檔案

(2)插入class欄位及值到shp

首先要建立新欄位名,然後再插入值

bool ImportLandInfo::insertInfo(QString mShpfile)
{

	QgsVectorLayer * newLayer;

	newLayer = new QgsVectorLayer(mShpfile, fileinfo.baseName(), "ogr");
	if ( newLayer != NULL)
	{
		qDebug("newLayer is valid");
	}
	else
	{
		return false;
	}
	QStringList readlist = readFromCSV(“F:\\data.csv”);//Excel檔案

	//建立新欄位
	QList<QgsField> newFieldList;
	QStringList fields = readlist.at(0).split(",", QString::SkipEmptyParts);  //得到Excel的欄位名
	for (int i = 0; i < fields.count(); ++i)
	{
		QString fieldname;
		if ( fields.at(i) == "Id" )
		{
			continue;
		}
		else
		{
			fieldname = fields.at(i);
		}
		QgsField shpField( fieldname, QVariant::String);
		newFieldList.push_back( shpField );
		
	}
	QgsVectorDataProvider* vectorProvider = newLayer->dataProvider();
	vectorProvider->addAttributes( newFieldList );
	
	//新欄位中插入值
	QMap<int, int> idmap = generateIdIndex(); //由原shp圖層得到QMap<ID, featureId>
	int fieldIndex = -1;  //每個待插入欄位的索引號
	int IdIndex = -1;    // ID欄位的索引號
	for (int j = 0; j < readlist.count(); ++j)
	{
		QString filed; 
		QgsChangedAttributesMap changeMap;
		QgsAttributeMap changeAttributeMap;

		QStringList field = readlist.at( j ).split(",", QString::SkipEmptyParts);
		for ( int k = 0; k < field.count(); ++k)
		{
			if (  field.at(k) == "Id" )
			{	
				IdIndex = k;
				continue;
			}			
			if ( j == 0)  //第一行時是計算欄位在屬性表中的index
			{	
				fieldIndex = vectorProvider->fieldNameIndex( field.at(k) );
				break;
			}
			else  //不是第一行則插入
			{
				changeAttributeMap.insert( fieldIndex + k - 1, QVariant( field.at(k) ) );
			}
		}
		if ( j == 0)
		{
			continue;
		}
 		int ID = field.at(IdIndex).toInt();
		
		QMap<int, int>::iterator i = idmap.find( ID); //找到指定ID對應的要素id(featureId)
		int featureId = i.value();
		changeMap.insert( featureId, changeAttributeMap );
		vectorProvider->changeAttributeValues( changeMap );
	}
	delete vectorProvider;
	return true;
}
generateIdIndex()是為了得到Id對應的FeatureID,因為屬性欄位Id和要素的FeatureID是不一致的。
QMap<int, int> ImportLandInfo::generateIdIndex()
{
	QMap<int, int> idMap;
	QgsVectorLayer * orignalLayer;
	QFileInfo fileinfo(moriginalShpfile);
	orignalLayer = new QgsVectorLayer(moriginalShpfile, fileinfo.baseName(), "ogr");
	if ( orignalLayer != NULL)
	{
		qDebug("newLayer is valid");
	}
	QgsVectorDataProvider* vectorProvider = orignalLayer->dataProvider();
 	QgsFeature feature;

	int idIndex = vectorProvider->fieldNameIndex( "Id" );
	int count = orignalLayer->featureCount();
	for ( int i = 0; i < count; ++i)
	{
		orignalLayer->featureAtId( i, feature);
		const QgsAttributeMap &attributes = feature.attributeMap();
		int id = -1;
		id = attributes[ idIndex].toInt();
		idMap.insert( id, feature.id());
	}	
	return idMap;
}

這樣欄位class的值就新增到shp中去了。結果如圖: