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","");

QGis(三)查询矢量图层的要素属性字段值(转载)的更多相关文章

  1. Qt+QGIS二次开发:自定义类实现查询矢量数据的属性字段值(图查属性)

    在GIS领域,有两种重要的查询操作,图查属性和属性查图. 本文主要介绍如何在QGIS中通过从QgsMapToolIdentify中派生自定义类实现查询矢量数据的属性字段值(图查属性). 重点参考资料: ...

  2. OpenLayers在多个矢量图层编辑要素

    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> <html> <head ...

  3. ArcMap10.1修改要素属性字段

    ArcMap10.1修改要素属性字段 问题描述:在ArcMap10.1中编辑要素属性表时,遇到输入字段值的长度超过字段最大长度时,ArcMap会抛出“基础DBMS错误[ORA-12899:value ...

  4. [ArcGIS API for JavaScript 4.8] Sample Code-Popups-1-popupTemplate的概念和popup中属性字段值的多种表现形式

    [官方文档:https://developers.arcgis.com/javascript/latest/sample-code/intro-popuptemplate/index.html] 一. ...

  5. openlayers3 在地图上叠加WFS查询矢量图层

    随着终端设备计算能力的加强,用户在使用地图的时候也须要越来越多的交互效果. 比方如今非常火的室内导航,为了获得好的用户体验,就须要当用户单击某一商店的时候该商店的颜色能对应的变化.这就须要叠加矢量图层 ...

  6. datagridcolumn单元格怎么显示查询到的某个表的字段值(字段值可能为多个)

    例如,在之前做的项目中,查询mhz_xckcr表,select出某个业务的现场勘察人信息,select出的现场勘察人姓名(可能有多个)要在前台datagrid的一个datagridcolmn单元格显示 ...

  7. Dynamics CRM2016 Web API之更新记录的单个属性字段值

    在web api中提供了对单个属性的更新接口,这和查询中查询单个属性类似,对这个接口我个人也是比较喜欢的. var id = "{D1E50347-86EB-E511-9414-ADA183 ...

  8. Arcpy按属性(字段值)不同将shp分割为多个独立shp_适用点线面矢量

    利用代码可以进行批量处理,安装有10.5及以上版本ArcGIS可以使用工具Split by attributes完成上述任务 # -*- coding: utf-8 -*- # Import syst ...

  9. json转化的时候如何忽略某些属性字段值

    一.有时候在将对象或list对象转化为json的时候,我们可能不需要所有的属性值,这就需要我们去过滤掉这些属性了 我下面说两种比较流行的json包如何来忽略某些属性值 二. 使用jaskson包 1. ...

随机推荐

  1. webpy

    url处理 对于一个站点来说,URL 的组织是最重要的一个部分,因为这是用户看得到的部分,而且直接影响到站点是如何工作的,在著名的站点如:del.icio.us ,其URLs 甚至是网页界面的一部分. ...

  2. 改写BlogEngine.NET头像上传实现方式(使用baidu.flash.avatarMaker)

    baidu.flash.avatarMaker 需要资源文件和javascript类库: 1 2 3 4 5 6 7 需要应用的script library: <scriptsrc=" ...

  3. 【转】使IFRAME在iOS设备上支持滚动

    原文链接: Scroll IFRAMEs on iOS原文日期: 2014年07月02日 翻译日期: 2014年07月10日翻译人员: 铁锚 很长时间以来, iOS设备上Safari中超出边界的元素将 ...

  4. 手机电话号码吉凶查询原理及ASP算法源码 转

    随着手机的快速普及,越来越多的人都在使用手机,而号码的挑选也是用户越来越关心的事情.虽然号码只是个代号而已,但几千年的传统积淀仍给号码赋予其各种含义,至于号码的吉凶也是见仁见智的一种个人喜好问题,或许 ...

  5. ie用document.getElementsByName获取不到

    document.getElementsByName('someName') 返回一个节点列表(数组) 注意:在IE下有些节点是没有name 属性的,就是用document.getElementsBy ...

  6. 使用MyEclipse构建MAVEN项目 - 我的漫漫程序之旅 - BlogJava

    body { font-family: Microsoft YaHei UI,"Microsoft YaHei", Georgia,Helvetica,Arial,sans-ser ...

  7. HDU 5531 Rebuild

    2015 ACM/ICPC 长春现场赛 E题 三分. 如果节点个数是奇数,那么直接列方程可以求解,因为,如果第一个圆半径变大,必然导致最后一个圆的半径变大, 所以,节点是奇数的时候,要么无解,要么只有 ...

  8. 网页解析的全过程(输入url到展示页面)

    1.用户输入网址,浏览器发起DNS查询请求 用户访问网页,DNS服务器(域名解析系统)会根据用户提供的域名查找对应的IP地址. 域名解析服务器是基于UDP协议实现的一个应用程序,通常通过监听53端口来 ...

  9. python之路:进阶篇

     > ) {        ;    }    printf(;} print i >>>      >>>  == :    name  ==   ==   ...

  10. iOS之PCH文件

    在Xcode6之前,创建一个新工程xcode会在Supporting files文件夹下面自动创建一个“工程名-Prefix.pch”文件,也是一个头文件,pch头文件的内容能被项目中的其他所有源文件 ...