QGIS基本功|5 QGIS图层进阶(二)- 连接属性表

本文介绍如何在QGIS中将统计年鉴等纯属性数据与地理空间数据进行连接,通过预处理、属性表连接、可视化和保存等步骤,实现属性数据的空间可视化分析。利用QGIS的【按字段值连接属性】工具,将统计年鉴数据与省级行政区划图层关联,通过颜色渐变展示年末总人口的分布差异。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

GIS界流行一句话:人类活动80%的信息与地理位置有关。然而,我们得到的数据中有很大一部分却没有地理几何图形,而是一张张文字和数字组成的表格,例如,统计局每年发布的统计年鉴。如何将这些表格定位到地图上,并使用表格数据做空间可视化分析,是GISer需要掌握的基本技能。

本文以全国省级行政区划为地理空间底图,以统计年鉴为属性表来源,从数据预处理、表连接、属性表的使用、表持久化四个方面,演示空间数据与纯属性数据结合并进行分析的过程。        

 

01  获取示范数据

 

• 全国2015年省级行政区划来自资源环境科学与数据中心,该图层为免费公开的数据,输入网址:http://www.resdc.cn/Default.aspx,注册后即可免费下载。

• 统计年鉴来自国家统计局官网,网址为:http://www.stats.gov.cn/,无需注册即可下载。

为了方便大家,以上数据已经打包上传到网盘,连接如下:

链接:https://pan.baidu.com/s/18vKpBMjOGfT9nHcNo31bFw 提取码:hkyi

 

02 预处理

 

打开下载到的统计年鉴数据,本文选择“分地区人口的城乡构成和出生率、死亡率、自然增长率”为例进行操作演示。可以看到,该电子表格并不适合直接导入到QGIS中,在空间数据挂接之前,需要对数据做预处理。

 

 

  • 处理多重表头

 

统计年鉴的表头一般由标题和指标名称构成,指标名称可能包含多个层级,需要逐层合并,才能得到某列数据的完整列名,这种复杂的表头样式俗称多重表头。例如上图中第三列的指标名称应为:城镇人口数;第四列指标名称为:城镇人口比重(%)。为了便于计算机处理,在数据整理时一般将复杂的指标名称与数据列名做出对照表,以元数据形式随内容分发。

 

本文采用的处理步骤为:删除表格标题,用英文代替中文指标名称,保留中英文指标名称之间的对应关系。处理结果如下:

 

 

  • 删除全国数据和空行

 

表格中的“全国”或者“合计”行,与其他数据不在同一行政级别上,应删除。为了阅读方便而增加的空行也应去掉。

 

  • 处理省名中的空格

 

统计年鉴中为了提高阅读舒适度和纸质出版物的美观,在省名称中加入空格以达到对齐效果。由于空格对计算机来说也是字符串的内容,在字符串匹配时,空格常常导致匹配失败,因此,省名称中的空格应提前删除。

 

<think>我们正在讨论QGIS次开发中矢量图层属性表的显示与修改问题。用户之前遇到了在QTableView中修改单元格值后自动恢复的问题,我们已经提供了解决方案。现在用户的新问题是:“如何正确显示和修改矢量图层属性表”,结合之前的引用和解决方案,我们需要提供完整的指导。 解决方案思路: 1. 显示属性表:使用QTableView和QgsAttributeTableModel。 2. 修改属性表:确保图层处于编辑模式,正确使用代理(Delegate)提交修改,并处理事务。 具体步骤: 一、显示矢量图层属性表 1. 获取当前矢量图层。 2. 创建属性表模型(QgsAttributeTableModel)并图层数据。 3. 将模型设置到QTableView中。 、修改属性表数据 1. 确保在修改前启动编辑模式。 2. 使用代理处理特定类型的编辑(如整数、字符串等)。 3. 提交修改到模型和图层。 4. 保存修改(提交事务)或回滚。 三、注意事项 1. 模型和视图的设置顺序:先设置模型,再设置代理。 2. 事务管理:及时提交或回滚修改。 3. 性能优化:对于大型图层,考虑缓存和批量提交。 下面给出详细代码和说明。 步骤1:显示属性表 ```cpp // 假设已经有一个QTableView对象指针 m_tableView // 获取当前矢量图层(例如从QgsLayerTreeView中获取) QgsMapLayer* layer = m_layerTreeView->currentLayer(); if (!layer || layer->type() != QgsMapLayerType::VectorLayer) { QMessageBox::warning(this, tr("错误"), tr("请选择一个矢量图层!")); return; } QgsVectorLayer* vectorLayer = qobject_cast<QgsVectorLayer*>(layer); // 创建属性表模型 QgsAttributeTableModel* model = new QgsAttributeTableModel(vectorLayer, this); model->loadLayer(); // 图层数据 // 设置模型到视图 m_tableView->setModel(model); // 可选:设置列宽、隐藏某些列等 m_tableView->setColumnWidth(0, 100); // 设置第一列宽度 ``` 步骤2:修改属性表数据(通过代理) 这里以整数类型的列为例,自定义一个代理类: ```cpp class IntegerDelegate : public QStyledItemDelegate { public: IntegerDelegate(QObject* parent = nullptr) : QStyledItemDelegate(parent) {} QWidget* createEditor(QWidget* parent, const QStyleOptionViewItem& option, const QModelIndex& index) const override { QSpinBox* editor = new QSpinBox(parent); editor->setFrame(false); editor->setMinimum(0); editor->setMaximum(10000); return editor; } void setEditorData(QWidget* editor, const QModelIndex& index) const override { int value = index.model()->data(index, Qt::EditRole).toInt(); QSpinBox* spinBox = static_cast<QSpinBox*>(editor); spinBox->setValue(value); } void setModelData(QWidget* editor, QAbstractItemModel* model, const QModelIndex& index) const override { QSpinBox* spinBox = static_cast<QSpinBox*>(editor); spinBox->interpretText(); int value = spinBox->value(); model->setData(index, value, Qt::EditRole); } void updateEditorGeometry(QWidget* editor, const QStyleOptionViewItem& option, const QModelIndex& index) const override { editor->setGeometry(option.rect); } }; ``` 在视图上应用代理: ```cpp // 假设第列是整数类型 IntegerDelegate* delegate = new IntegerDelegate(this); m_tableView->setItemDelegateForColumn(1, delegate); ``` 步骤3:编辑和保存 在修改单元格前,确保图层处于编辑模式: ```cpp // 开始编辑 if (!vectorLayer->isEditable()) { if (!vectorLayer->startEditing()) { QMessageBox::warning(this, tr("错误"), tr("无法启动编辑会话!")); return; } } // 当用户完成编辑(例如点击保存按钮)时,提交修改 void MainWindow::on_saveButton_clicked() { if (vectorLayer->isEditable()) { if (vectorLayer->commitChanges()) { QMessageBox::information(this, tr("成功"), tr("修改已保存!")); // 重新载模型以刷新视图 model->reload(); } else { QMessageBox::critical(this, tr("错误"), tr("保存失败: %1").arg(vectorLayer->commitErrors().join(", "))); // 回滚 vectorLayer->rollBack(); } } } ``` 步骤4:处理编辑过程中的错误 在代理的setModelData中,如果设置数据失败,可以显示错误信息。 四、性能优化 对于大型矢量图层,可以: 1. 设置模型缓存:`model->setFeatureCacheSize(1000);`(缓存1000个要素) 2. 批量提交:使用`vectorLayer->beginEditCommand()`和`vectorLayer->endEditCommand()`组合多个操作为一个命令。 五、完整示例 结合之前的引用[1]和[2],我们还可以获取图层的样式信息(如颜色)来增强显示,但属性表主要关注属性数据。 注意事项: - 确保在设置代理之前设置模型。 - 注意图层的字段类型和代理的匹配。 通过以上步骤,可以正确显示和修改矢量图层属性表。 引用说明: [^1]:介绍了QGIS图层的类型和常用方法,包括矢量图层(QgsVectorLayer)的基本操作。 [^2]:展示了如何获取矢量图层的颜色,虽然与属性表修改不直接相关,但体现了对矢量图层样式的操作,可类比到属性数据的操作。 相关问题: 1. 如何实现属性表单元格的验证(例如,确保输入值在特定范围内)? 2. 如何在属性表中显示和编辑几何信息(如点的坐标)? 3. 如何实现属性表与地图视图的联动(如选择要素时在地图上高亮)? 4. 如何处理属性表的分页或懒载以提高大图层的性能?</think>### QGIS次开发中矢量图层属性表的显示与修改 在QGIS次开发中,正确显示和修改矢量图层属性表需要理解QGIS的数据模型架构和Qt的模型-视图框架。以下是完整解决方案: #### 一、属性表显示实现步骤 1. **获取矢量图层对象** ```cpp // 从图层树视图获取当前图层 QgsMapLayer* layer = m_layerTreeView->currentLayer(); if (!layer || layer->type() != QgsMapLayerType::VectorLayer) return; QgsVectorLayer* vectorLayer = qobject_cast<QgsVectorLayer*>(layer); ``` 2. **创建属性表模型** ```cpp // 创建属性表模型并载数据 QgsAttributeTableModel* attributeModel = new QgsAttributeTableModel(vectorLayer); attributeModel->loadLayer(); // 图层数据到模型 // 设置编辑模式(可选) attributeModel->setMode(QgsAttributeTableModel::EditOnCurrentFeature); ``` 3. **配置表格视图** ```cpp QTableView* tableView = new QTableView(); tableView->setModel(attributeModel); // 绑定模型 // 设置列宽和隐藏系统字段 tableView->setColumnWidth(0, 150); tableView->setColumnHidden(0, true); // 隐藏FID字段 // 启用排序和选择功能 tableView->setSortingEnabled(true); tableView->setSelectionMode(QAbstractItemView::SingleSelection); ``` #### 属性修改关键实现 1. **启动图层编辑模式** ```cpp void startEditing(QgsVectorLayer* layer) { if (!layer->isEditable()) { if (!layer->startEditing()) { qDebug() << "启动编辑失败:" << layer->error().message(); } } } ``` 2. **实现自定义代理(Delegate)** ```cpp class AttributeDelegate : public QStyledItemDelegate { public: QWidget* createEditor(QWidget* parent, const QStyleOptionViewItem& option, const QModelIndex& index) const override { // 根据字段类型创建不同编辑器 QgsField field = index.model()->headerData( index.column(), Qt::Horizontal, QgsAttributeTableModel::FieldRole).value<QgsField>(); if (field.type() == QVariant::Int) { return new QSpinBox(parent); } return QStyledItemDelegate::createEditor(parent, option, index); } }; // 应用代理到视图 tableView->setItemDelegate(new AttributeDelegate()); ``` 3. **数据提交与保存** ```cpp void saveChanges(QgsVectorLayer* layer) { if (layer->isModified()) { if (!layer->commitChanges()) { qDebug() << "提交失败:" << layer->commitErrors().join("; "); layer->rollBack(); } } } ``` #### 三、高级功能实现 1. **字段类型映射表** | 字段类型 | Qt编辑器 | 特殊处理 | |----------|----------|----------| | Integer | QSpinBox | 设置范围`setRange(min, max)` | | Double | QDoubleSpinBox | 设置精度`setDecimals(2)` | | String | QLineEdit | 输入验证`setValidator()` | | DateTime | QDateTimeEdit | 设置格式`setDisplayFormat()` | 2. **联动地图选择** ```cpp // 表格选择变化时高亮对应要素 connect(tableView->selectionModel(), &QItemSelectionModel::selectionChanged, [=](const QItemSelection& selected){ QgsFeatureIds ids; for (const auto& index : selected.indexes()) { ids.insert(index.sibling(index.row(), 0).data().toInt()); // 获取FID } vectorLayer->selectByIds(ids); }); ``` 3. **批量编辑优化** ```cpp // 开启批量操作模式 vectorLayer->beginEditCommand("批量更新"); // 执行多个编辑操作... for (int i = 0; i < rowCount; ++i) { QModelIndex index = attributeModel->index(i, column); attributeModel->setData(index, newValue); } // 提交批处理 vectorLayer->endEditCommand(); ``` #### 四、性能优化技巧 1. **数据载优化** ```cpp // 仅载可见字段 QStringList fields = {"name", "population", "area"}; attributeModel->setRequestedAttributes(fields); // 设置缓存大小 attributeModel->setFeatureCacheSize(1000); ``` 2. **分页载实现** ```cpp QSqlTableModel* pagedModel = new QSqlTableModel(); pagedModel->setTable("features"); pagedModel->setFilter("fid >= " + QString::number(start) + " AND fid <= " + QString::number(end)); ``` 3. **异步载机制** ```cpp QFuture<void> future = QtConcurrent::run([=]{ attributeModel->loadLayer(); }); ``` #### 五、错误处理与调试 ```cpp // 检查字段可编辑性 bool isEditable(int column) { return vectorLayer->editFormConfig()->widgetType(column) != "Hidden"; } // 调试输出 qDebug() << "字段信息:" << vectorLayer->fields().at(column).name() << "类型:" << vectorLayer->fields().at(column).typeName(); ``` #### 六、完整工作流程 ```mermaid graph TD A[获取矢量图层] --> B[创建属性表模型] B --> C[配置QTableView] C --> D{用户交互} D -->|修改单元格| E[启动编辑模式] E --> F[通过代理验证数据] F --> G[提交到模型] G --> H[更新底层数据源] H --> I{是否保存} I -->|| J[提交事务] I -->|| K[回滚修改] ``` 通过以上方法,可实现矢量图层属性表的高效显示和可靠编辑。实际开发中需注意: 1. 始终在修改前检查图层编辑状态 2. 根据字段类型使用合适的输入控件 3. 大型数据集需采用分页或异步载 4. 事务管理要匹配业务逻辑(即时提交/批量提交) [^1][^2]
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值