QGis(三)查询矢量图层的要素属性字段值
https://github.com/gwaldron/osgearth/issues/489
当加载一个矢量图层后,如果要查看要素的属性字段值,则需要实现identity的功能。可以和前面的缩放一样,添加一个工具栏按钮:
(1)在MainWindow添加一个变量,并在Qt设计师里添加Action:
QgsMapToolSelect *mpIdentifyTool; ///<查询要素
这里QgsMapToolSelect类继承自QgsMapTool,后面再列出详细内容。
(2)然后在初始化函数里添加:
mpMapToolBar->addAction(ui.mpActionIdentify); mpIdentifyTool = new QgsMapToolSelect(mainMapCanvas); mpIdentifyTool->setAction(ui.mpActionIdentify);
(3)添加信号槽函数连接:
connect(ui.mpActionIdentify, SIGNAL(triggered()), this, SLOT(identifyFeature()));
(4)槽函数实现:
void MainWindow::identifyFeature() { mpIdentifyTool->SetEnable(true); mainMapCanvas->setMapTool(mpIdentifyTool); ui.mpActionIdentify->setCheckable(true); ui.mpActionIdentify->setChecked(true); )->type() == QgsMapLayer::RasterLayer) { return; } QgsVectorLayer *pLayer=(QgsVectorLayer *)mainMapCanvas->layer(); mpIdentifyTool->SetSelectLayer(pLayer); if ( ui.mpActionIdentify->isChecked()) { pLayer->removeSelection(true); } }
可以看到,基本步骤就跟前面的缩放工具栏一模一样。但是QgsMapToolSelect不是 QgsMapTool自带的类,需要自定义,QgsMapToolSelect类的定义如下:
class QgsMapToolSelect : public QgsMapTool { Q_OBJECT; public: QgsMapToolSelect(QgsMapCanvas *); ~QgsMapToolSelect(void); public: //设置当前被选择(活动)的图层 void SetSelectLayer(QgsVectorLayer *); <span style="white-space:pre"> </span>//重载鼠标释放事件函数 virtual void canvasReleaseEvent(QMouseEvent * e); //设定工具状态 void SetEnable(bool); //得到所有的属性和属性值,<属性1,属性值1>是QMap的一对值 QList<QMap<QString, QString>> GetAttributeValue(QgsVectorLayer *layer, QgsFeatureIds selectedFIds); void setShowFlag(bool flag); IdentifyResultDlg *ResultDlg(); private: QgsVectorLayer* pLayer; QgsFeatureIds layerSelectedFeatures; bool StatusFlag; QList<QMap<QString, QString>> list; //存储选择后的要素 bool isShowFlag; ///< 是否在主界面上勾选了shp图层 IdentifyResultDlg *mIdentifyResultDlg; private: <span style="white-space:pre"> </span>//提取鼠标位置一定范围作为选择区域 void ExpandSelectRangle(QRect &Rect,QPoint Point); //将指定的设备坐标区域转换成地图坐标区域 void SetRubberBand(QRect &selectRect,QgsRubberBand *); //选择图层特征 void SetSelectFeatures(QgsGeometry *,bool,bool,bool); void SetSelectFeatures(QgsGeometry *,bool); };
具体函数实现:
#include "qgsmaptoolselect.h" //构造和析构函数 QgsMapToolSelect::QgsMapToolSelect(QgsMapCanvas *Mapcanvas):QgsMapTool(Mapcanvas) { pLayer=NULL; mCursor=Qt::ArrowCursor; mCanvas=Mapcanvas; StatusFlag=true; isShowFlag = true; mIdentifyResultDlg = NULL; } QgsMapToolSelect::~QgsMapToolSelect(void) { } //设置当前被选择(活动)的图层 void QgsMapToolSelect::SetSelectLayer(QgsVectorLayer *Layer) { pLayer=Layer; } //鼠标按钮释放时,选择包含鼠标位置的图元 void QgsMapToolSelect::canvasReleaseEvent(QMouseEvent * e ) { if(mCanvas==NULL){ return; } if(pLayer==NULL){ QMessageBox::about(mCanvas,QString::fromLocal8Bit("警告"),QString::fromLocal8Bit("请选择图层")); return; } if(StatusFlag==false){ return; } //得到产生事件的按钮信息 Qt::MouseButton mButton=e->button(); //如果不是左按钮返回 if(mButton!=Qt::MouseButton::LeftButton){ return; } //得到鼠标指针的位置 QPoint pos=e->pos(); //定义QgsRubberBand对象 QgsRubberBand rubberBand(mCanvas,true); QRect selectRect(,,,); //设置鼠标位置区域 ExpandSelectRangle(selectRect,pos); //将鼠标位置区域转换成地图坐标 SetRubberBand(selectRect,&rubberBand ); //将QgsRubberBand对象转换为几何对象,根据该几何对象在图层中选择特征 QgsGeometry* selectGeom=rubberBand.asGeometry(); if(!selectGeom){ return; } //确定是否按下ctrl键 bool doDifference=e->modifiers()&Qt::ControlModifier ? true:false; //在图层中选择最靠近几何对象的特征 SetSelectFeatures(selectGeom,false,doDifference,true); //SetSelectFeatures(selectGeom,doDifference); //设定选择的特征 pLayer->setSelectedFeatures(layerSelectedFeatures); list = GetAttributeValue(pLayer, layerSelectedFeatures); if (isShowFlag) { ResultDlg()->InitialData(list); ResultDlg()->show(); } else { QMessageBox::information(NULL, tr("警告"), tr("请选择矢量图层"), QMessageBox::Ok); } delete selectGeom; rubberBand.reset(true); } //提取鼠标位置一定范围作为选择区域 void QgsMapToolSelect::ExpandSelectRangle(QRect &Rect,QPoint Point) { ; //如果图层不是面图元类型 if(pLayer->geometryType()!=QGis::Polygon){ boxSize=; } else{ boxSize=; } //设置选择区域 Rect.setLeft(Point.x()-boxSize); Rect.setRight(Point.x()+boxSize); Rect.setTop(Point.y()-boxSize); Rect.setBottom(Point.y()+boxSize); } //将指定的设备坐标区域转换成地图坐标区域 void QgsMapToolSelect::SetRubberBand(QRect &selectRect,QgsRubberBand *pRubber) { //得到当前坐标变换对象 const QgsMapToPixel* transform=mCanvas->getCoordinateTransform(); //将区域设备坐标转换成地图坐标 QgsPoint ll=transform->toMapCoordinates(selectRect.left(),selectRect.bottom()); QgsPoint ur = transform->toMapCoordinates(selectRect.right(),selectRect.top()); pRubber->reset(true ); //将区域的4个角点添加到QgsRubberBand对象中 pRubber->addPoint(ll,false ); pRubber->addPoint(QgsPoint(ur.x(), ll.y()),false ); pRubber->addPoint(ur,false ); pRubber->addPoint(QgsPoint( ll.x(), ur.y() ),true ); } //选择几何特征 //selectGeometry:选择特征的选择几何体 //doContains:选择的特征是否包含在选择几何体内部 //singleSelect:仅仅选择和选择几何体最靠近的特征 void QgsMapToolSelect::SetSelectFeatures(QgsGeometry *selectGeometry,bool doContains, bool doDifference,bool singleSelect) { //如果选择几何体不是多边形 if(selectGeometry->type()!=QGis::Polygon){ return; } QgsGeometry selectGeomTrans(*selectGeometry); //设定选择几何体的坐标系和图层的坐标系一致 if(mCanvas->mapRenderer()->hasCrsTransformEnabled()){ try{ //将地图绘板坐标系变换到图层坐标系 QgsCoordinateTransform ct(mCanvas->mapRenderer()->destinationSrs(),pLayer->crs()); //设定几何体的坐标系和图层坐标系一致 selectGeomTrans.transform(ct); } //对于异常点抛出异常 catch(QgsCsException &cse){ Q_UNUSED(cse); //catch exception for 'invalid' point and leave existing selection unchanged QMessageBox::warning(mCanvas, QObject::tr("CRS Exception"), QObject::tr( "Selection extends beyond layer's coordinate system." ) ); return; } } //设置光标 //QApplication::setOverrideCursor(Qt::WaitCursor); //选择和选择几何体相交或在几何体内部的特征 pLayer->select(QgsAttributeList(),selectGeomTrans.boundingBox(),true,true); int nh=pLayer->selectedFeatureCount(); QgsFeatureIds newSelectedFeatures; QgsFeature f; ; bool foundSingleFeature=false; double closestFeatureDist=std::numeric_limits<double>::max(); //得到当前选择的特征 while(pLayer->nextFeature(f)){ QgsGeometry* g=f.geometry(); //g是否包含在selectGeomTrans几何体内部 if(doContains && !selectGeomTrans.contains(g)){ continue; } if(singleSelect){ //选择和几何体最靠近的特征 foundSingleFeature=true; //计算两个几何体之间的距离 double distance=g->distance(selectGeomTrans); if(distance<=closestFeatureDist){ closestFeatureDist=distance; //计算出最靠近选择几何体特征的id closestFeatureId=f.id(); } } else{ //存储符合要求的特征id newSelectedFeatures.insert(f.id()); } } //确定和选择几何体最靠近特征的id if(singleSelect && foundSingleFeature){ newSelectedFeatures.insert(closestFeatureId); } //如果按下ctrl键,选择多个特征 if(doDifference){ //得到所有选择特征的id layerSelectedFeatures=pLayer->selectedFeaturesIds(); QgsFeatureIds::const_iterator i=newSelectedFeatures.constEnd(); while(i!=newSelectedFeatures.constBegin()){ --i; if(layerSelectedFeatures.contains(*i)){ layerSelectedFeatures.remove( *i ); } else{ layerSelectedFeatures.insert( *i ); } } } else{ layerSelectedFeatures=newSelectedFeatures; } //QApplication::restoreOverrideCursor(); } //选择几何特征,用于选择面状几何特征 //selectGeometry:选择几何体 void QgsMapToolSelect::SetSelectFeatures(QgsGeometry *selectGeometry,bool doDifference) { //如果选择几何体不是多边形 if(selectGeometry->type()!=QGis::Polygon){ return; } QgsGeometry selectGeomTrans(*selectGeometry); //设定选择几何体的坐标系和图层的坐标系一致 if(mCanvas->mapRenderer()->hasCrsTransformEnabled()){ try{ //将地图绘板坐标系变换到图层坐标系 QgsCoordinateTransform ct(mCanvas->mapRenderer()->destinationSrs(),pLayer->crs()); //设定几何体的坐标系和图层坐标系一致 selectGeomTrans.transform(ct); } //对于异常点抛出异常 catch(QgsCsException &cse){ Q_UNUSED(cse); //catch exception for 'invalid' point and leave existing selection unchanged QMessageBox::warning(mCanvas, QObject::tr("CRS Exception"), QObject::tr( "Selection extends beyond layer's coordinate system." ) ); return; } } //设置光标 //QApplication::setOverrideCursor(Qt::WaitCursor); //选择和选择几何体相交或在几何体内部的特征 pLayer->select(QgsAttributeList(),selectGeomTrans.boundingBox(),true,true); int nh=pLayer->selectedFeatureCount(); QgsFeatureIds newSelectedFeatures; QgsFeature f; ; //得到当前选择的特征 while(pLayer->nextFeature(f)){ p++; QgsGeometry* g=f.geometry(); //选择的特征是否包含在选择几何体的内部 //如果g包含selectGeomTrans,返回true if(!g->contains(&selectGeomTrans)){ continue; } //存储符合条件图层特征id newSelectedFeatures.insert(f.id()); } QgsFeatureIds layerSelectedFeatures; //如果按下ctrl键,可以选择多个特征 if(doDifference){ layerSelectedFeatures=pLayer->selectedFeaturesIds(); QgsFeatureIds::const_iterator i = newSelectedFeatures.constEnd(); while( i != newSelectedFeatures.constBegin()){ --i; if( layerSelectedFeatures.contains( *i ) ) { layerSelectedFeatures.remove( *i ); } else { layerSelectedFeatures.insert( *i ); } } } else{ layerSelectedFeatures=newSelectedFeatures; } //设定选择的特征 pLayer->setSelectedFeatures(layerSelectedFeatures); //QApplication::restoreOverrideCursor(); } //设定工具状态 void QgsMapToolSelect::SetEnable(bool flag) { StatusFlag=flag; if(StatusFlag){ mCursor=Qt::CrossCursor; } else{ mCursor=Qt::ArrowCursor; } } IdentifyResultDlg * QgsMapToolSelect::ResultDlg() { if (mIdentifyResultDlg == NULL) { mIdentifyResultDlg = new IdentifyResultDlg; } return mIdentifyResultDlg; } //得到选择的要素的属性信息 QList<QMap<QString, QString>> QgsMapToolSelect::GetAttributeValue( QgsVectorLayer *layer, QgsFeatureIds selectedFIds ) { // QStringList strAttribute; QMap<QString, QString> featureValue; QList<QMap<QString, QString>> featureValues; , nFeatureCount = , nFieldsCount = ; if (layer == NULL) { return featureValues; } QgsFeatureList featurelist = layer->selectedFeatures(); nFeatureCount = featurelist.size(); QgsFeature feature; QString fieldName, fieldValue; // vector<QgsField> myFields = layer->fields(); ; i < nFeatureCount; i++) { feature = featurelist.at(i); const QgsAttributeMap &attributes = feature.attributeMap(); nFieldsCount = attributes.count(); const QgsFieldMap &fields = layer->pendingFields();//从图层得到字段信息 QgsField field; ; j < nFieldsCount; j++) { field = fields[j]; fieldName = field.name(); fieldValue = attributes[j].toString(); featureValue.insert(fieldName, fieldValue); } featureValues.push_back(featureValue); } return featureValues; } void QgsMapToolSelect::setShowFlag( bool flag ) { isShowFlag = flag; }
查询得到的数据显示在对话框:
IdentifyResultDlg对话框是为了显示查询得到的结果。它的定义:
class IdentifyResultDlg : public QDialog { Q_OBJECT public: IdentifyResultDlg(QWidget *parent = ); ~IdentifyResultDlg(); void InitialDlg(); void InitialData(QList<QMap<QString, QString>>); private: Ui::IdentifyResultDlg ui; QStandardItemModel *fieldmodel; };
IdentifyResultDlg具体实现:
#include "identifyresultdlg.h" IdentifyResultDlg::IdentifyResultDlg(QWidget *parent) : QDialog(parent) { ui.setupUi(this); QStringList lists; InitialDlg(); } IdentifyResultDlg::~IdentifyResultDlg() { } void IdentifyResultDlg::InitialDlg() { this->setWindowTitle(tr("查询要素属性信息")); fieldmodel = new QStandardItemModel(); fieldmodel->setColumnCount(); ui.tableView->setModel(fieldmodel); ui.tableView->setEditTriggers(QAbstractItemView::NoEditTriggers);//设置表格不可编辑 ui.tableView->verticalHeader()->hide(); //列头不显示 ui.tableView->setSelectionBehavior(QAbstractItemView::SelectRows);//选择整行高亮 setWindowFlags(Qt::WindowStaysOnTopHint);//使窗口置顶 , ); } //将数据显示在表格中 void IdentifyResultDlg::InitialData( QList<QMap<QString, QString>> datas) { fieldmodel->clear();//注意:在clear之后,表头名称也被清除了,需再设置表头 fieldmodel->setHorizontalHeaderItem(, new QStandardItem(QObject::tr("属性名称"))); fieldmodel->setHorizontalHeaderItem(, new QStandardItem(QObject::tr("属性值"))); QString name, value; QMap<QString,QString>::iterator it; ; ; i < datas.count(); i ++) { QMap<QString,QString> data = datas.at(i); ; ; it != data.end(), j < data.count(); ++it, ++j) { int index = i * data.count() +j; fieldmodel->setItem(index, , new QStandardItem(it.key())); if (it.value() == NULL) { it.value() = "; } fieldmodel->setItem(index, , new QStandardItem(it.value())); fieldmodel->item(index, )->setTextAlignment(Qt::AlignCenter); fieldmodel->item(index, )->setTextAlignment(Qt::AlignCenter); ) { fieldmodel->item(index, )->setBackground(QBrush(QColor(, , ))); fieldmodel->item(index, )->setBackground(QBrush(QColor(, , ))); } } } }
查询一个要素和多个要素的结果如下图所示:
注意:可能中文字段显示乱码,解决方法:
在操作shp之前,添加这句就可以了:
CPLSetConfigOption("SHAPE_ENCODING","");