当前位置: 首页 > news >正文

【QGIS二次开发】地图编辑-09

  系列目录:

【QGIS二次开发】地图显示与交互-01_qgis二次开发加载地图案例-CSDN博客

【QGIS二次开发】地图显示与交互-02_setlayerlabeling-CSDN博客

【QGIS二次开发】地图符号与色表-03-CSDN博客

【QGIS二次开发】地图编辑-04-CSDN博客

【QGIS二次开发】地图编辑-05-CSDN博客

【QGIS二次开发】地图编辑-06-CSDN博客

【QGIS二次开发】地图编辑-07-CSDN博客

【QGIS二次开发】地图编辑-08-CSDN博客


4.19 属性结构编辑

对树状图的矢量数据,右键点击“查看属性表结构”;

图 79 右键菜单-查看属性表结构

查看结构

图 80 属性表结构

相关代码分析

当viewProperty函数被调用时,它首先确认当前是否有图层被选中,并判断该图层是否为矢量图层。如果条件满足,它接着创建一个QgsSourceFieldsProperties的实例,这个实例用于显示和管理选中矢量图层的属性字段。通过loadRows()方法加载属性字段信息,并通过show()方法显示这些信息。

代码部分如下:

void MenuProvider::viewProperty()    
{    QgsMapLayer* currentLayer = mView->currentLayer();    if (currentLayer)    {    // 判断图层类型    QgsVectorLayer* layer = qobject_cast<QgsVectorLayer*>(currentLayer);    if (layer)    {    //显示属性结构字段    QgsSourceFieldsProperties* pWidget = new QgsSourceFieldsProperties(layer, nullptr);    pWidget->loadRows();    pWidget->show();    }    }    
}    

4.20 属性编辑

点击“查看属性表“

图 81 右键菜单-查看属性表

查看属性表;

图 82 属性表

点击左上角的编辑,然后就可以编辑矢量表数据

图 83 属性表编辑

相关代码思路分析

       使用QgsAttributeTableDialog来显示矢量的属性表;

代码部分如下:

void MenuProvider::viewPropertySheet()    
{    QgsMapLayer* currentLayer = mView->currentLayer();    if (currentLayer)    {    QgsVectorLayer* vectorLayer = qobject_cast<QgsVectorLayer*>(currentLayer);    if (vectorLayer) {    // 创建图层数据缓存    QgsVectorLayerCache* layerCache = new QgsVectorLayerCache(vectorLayer, vectorLayer->featureCount());    // 使用原始图层创建属性表对话框    QgsAttributeTableDialog* attrDialog = new QgsAttributeTableDialog(vectorLayer);    attrDialog->setAttribute(Qt::WA_DeleteOnClose);    attrDialog->show();    }    }    
}    

4.21 表格文件转矢量

点击按钮,跳出相关窗口

图 84 表格文件转矢量

选择csv文件后,再选择输出路径。选择csv文件的坐标的坐标系,再选择目标坐标系,完成后点击确定;

图 85 选择投影

完成后点文件显示在图框中;

图 86 转换结果

相关代码思路分析:

首先,通过使用Qt的界面组件创建对话框,包括文本框、文件选择按钮、坐标系选择按钮和确定按钮,构建了用户交互界面。文件选择逻辑使用QFileDialog实现,允许用户选择输入和输出文件的路径。坐标系选择逻辑通过QgsProjectionSelectionDialog实现,允许用户选择原始文件和目标坐标系,并保存坐标系代码。在用户点击“确定”按钮时,对输入进行验证,确保文件路径和坐标系信息已提供,否则显示警告消息。接着,基于用户选择的坐标系代码创建QgsCoordinateReferenceSystem对象,并设置一个坐标转换对象QgsCoordinateTransform。如果坐标转换设置不正确,显示错误消息。

随后,使用输入文件路径创建QgsVectorLayer表示原始Excel数据,并遍历该图层中的所有要素,使用坐标转换对象转换它们的几何形状到目标坐标系。然后,创建一个新的内存矢量图层,将原始图层的字段复制到新图层,再将转换后的要素添加到新图层中。最后,将转换后的图层保存为Shapefile格式,若保存过程中出现错误则显示错误消息,并将新图层添加到当前QGIS项目中,刷新地图画布以显示新图层。

代码部分如下:

void DataViewer::on_actionExcelToVector_triggered()    
{    QString sourceCrsCode, targetCrsCode;    QDialog dialog;    QVBoxLayout layout(&dialog);    QLabel labelIn("输入文件:");    QLineEdit lineEditIn;    QPushButton fileButtonIn("选择文件");    QLabel labelOut("输出文件:");    QLineEdit lineEditOut;    QPushButton fileButtonOut("选择文件");    // 原文件坐标系选择    QPushButton sourceCrsButton("选择原文件坐标系");    QLabel sourceCrsLabel("原文件坐标系:未选择");    // 目标坐标系选择    QPushButton targetCrsButton("选择目标坐标系");    QLabel targetCrsLabel("目标坐标系:未选择");    QPushButton okButton("确定");    layout.addWidget(&labelIn);    layout.addWidget(&lineEditIn);    layout.addWidget(&fileButtonIn);    layout.addWidget(&labelOut);    layout.addWidget(&lineEditOut);    layout.addWidget(&fileButtonOut);    layout.addWidget(&sourceCrsButton);    layout.addWidget(&sourceCrsLabel);    layout.addWidget(&targetCrsButton);    layout.addWidget(&targetCrsLabel);    layout.addWidget(&okButton);    // 连接文件选择按钮的点击事件到文件选择功能    QObject::connect(&fileButtonIn, &QPushButton::clicked, [&lineEditIn]() {    QString fileName = QFileDialog::getOpenFileName(nullptr, "选择输入文件", QDir::currentPath(), "csv (*.csv)");    if (!fileName.isEmpty()) {    lineEditIn.setText(fileName);    }    });    QObject::connect(&fileButtonOut, &QPushButton::clicked, [&lineEditOut]() {    QString fileName = QFileDialog::getSaveFileName(nullptr, "选择输出文件", QDir::currentPath(), "shp (*.shp)");    if (!fileName.isEmpty()) {    lineEditOut.setText(fileName);    }    });    // 原文件坐标系选择逻辑    QObject::connect(&sourceCrsButton, &QPushButton::clicked, [&]() {    QgsProjectionSelectionDialog crsDialog;    if (crsDialog.exec()) {    QgsCoordinateReferenceSystem crs = crsDialog.crs();    sourceCrsCode = crs.authid();    sourceCrsLabel.setText("原文件坐标系:" + sourceCrsCode);    }    });    // 目标坐标系选择逻辑    QObject::connect(&targetCrsButton, &QPushButton::clicked, [&]() {    QgsProjectionSelectionDialog crsDialog;    if (crsDialog.exec()) {    QgsCoordinateReferenceSystem crs = crsDialog.crs();    targetCrsCode = crs.authid();    targetCrsLabel.setText("目标坐标系:" + targetCrsCode);    }    });    //点击确定之后接受数据    QObject::connect(&okButton, &QPushButton::clicked, &dialog, &QDialog::accept);    //dialog.exec();    if (dialog.exec() != QDialog::Accepted) {    return;    }    QString originFileName = lineEditIn.text();    QString finalFileName = lineEditOut.text();    // 检查输入文件名和坐标系是否已提供    if (originFileName.isEmpty() || finalFileName.isEmpty() || sourceCrsCode.isEmpty() || targetCrsCode.isEmpty()) {    QMessageBox::warning(nullptr, "警告", "请确保所有输入均已正确填写。");    return;    }    // 创建原始坐标系和目标坐标系对象    QgsCoordinateReferenceSystem sourceCrs(sourceCrsCode);    QgsCoordinateReferenceSystem targetCrs(targetCrsCode);    // 创建坐标转换对象    QgsCoordinateTransform transform(sourceCrs, targetCrs, QgsProject::instance()->transformContext());    if (!transform.isValid()) {    QMessageBox::critical(nullptr, "错误", "坐标转换设置不正确。");    return;    }    // 创建矢量图层,使用原始坐标系    QString uri = "file:///" + originFileName + "?delimiter=,&crs=" + sourceCrsCode + "&xField=x&yField=y";    QgsVectorLayer* layer = new QgsVectorLayer(uri, "Layer Name", "delimitedtext");    if (!layer->isValid()) {    QMessageBox::critical(nullptr, "错误", "创建矢量图层失败。");    return;    }    // 转换图层中的要素到目标坐标系    QList<QgsFeature> transformedFeatures;    QgsFeature feature;    QgsFeatureIterator featureIt = layer->getFeatures();    while (featureIt.nextFeature(feature)) {    QgsGeometry geom = feature.geometry();    geom.transform(transform);    feature.setGeometry(geom);    transformedFeatures.append(feature);    }    // 创建新的内存图层以保存转换后的要素    QString memoryLayerUri = "Point?crs=" + targetCrs.authid();    QgsVectorLayer* transformedLayer = new QgsVectorLayer(memoryLayerUri, "转换后图层", "memory");    // 确保新图层有与原图层相同的字段    transformedLayer->dataProvider()->addAttributes(layer->dataProvider()->fields().toList());    transformedLayer->updateFields();    // 开始编辑图层    transformedLayer->startEditing();    // 将转换后的要素添加到新图层    for (auto& transformedFeature : transformedFeatures) {    transformedLayer->dataProvider()->addFeature(transformedFeature);    }    // 提交更改    transformedLayer->commitChanges();    // 保存为 Shapefile    QgsVectorFileWriter writer(finalFileName, "UTF-8", transformedLayer->fields(), transformedLayer->wkbType(), transformedLayer->crs(), "ESRI Shapefile");    // 检查保存过程中是否有错误发生    if (writer.hasError() != QgsVectorFileWriter::NoError) {    QMessageBox::critical(nullptr, "错误", "保存 Shapefile 时出错: " + writer.errorMessage());    return;    }    // 遍历转换后的图层中的每个要素并写入 Shapefile    QgsFeatureIterator transformedFeatureIt = transformedLayer->getFeatures();    QgsFeature transformedFeature;    while (transformedFeatureIt.nextFeature(transformedFeature)) {    writer.addFeature(transformedFeature);    }    // 添加转换后的图层到项目    QgsProject::instance()->addMapLayer(transformedLayer);    m_mapCanvas->refresh();    }    

4.22 撤销与重做

       用户需要撤销或是重做时,点击工具栏中的撤销或重做来对缓存中的内容进行撤销或重做,但是对于已经保存在内存中的内容用户已经不能进行撤销。

       例如,当我对面要素进行删除面边界上的点时,我点击撤销,刚才进行的删除点的操作全部撤销,实现效果如下:

图 87 删除点的要素

图 88 撤销效果

       实现的代码如下,通过在 DataViewer中的添加两个成员函数on_actionUndo_triggered和on_actionRedo_triggered。这两个函数分别处理撤销和重做操作。首先,函数检查当前图层是否为矢量图层,然后获取该图层的撤销堆栈undoStack。通过调用undo和redo函数,这两个函数分别执行当前图层上的撤销和重做操作。最后,刷新地图视图和所有图层,以确保最新的更改在地图中反映出来。这些功能使用户能够在编辑矢量图层时方便地撤销和重做操作。

void DataViewer::on_actionUndo_triggered()    
{    if (currentLayer) {    QgsVectorLayer* vectorLayer = qobject_cast<QgsVectorLayer*>(currentLayer);    if (vectorLayer)    {    // 使用撤销堆栈来撤销或重做操作    QUndoStack* undoStack = vectorLayer->undoStack();    undoStack->undo();  // 撤销操作    m_mapCanvas->refresh();    m_mapCanvas->refreshAllLayers();    }    }    
}    void DataViewer::on_actionRedo_triggered()    
{    if (currentLayer) {    QgsVectorLayer* vectorLayer = qobject_cast<QgsVectorLayer*>(currentLayer);    if (vectorLayer)    {    // 使用撤销堆栈来撤销或重做操作    QUndoStack* undoStack = vectorLayer->undoStack();    undoStack->redo();  // 重做操作    m_mapCanvas->refresh();    m_mapCanvas->refreshAllLayers();    }    }    
}    
http://www.xdnf.cn/news/514747.html

相关文章:

  • python + pip 独家秘籍
  • printf函数参数与入栈顺序
  • 翻到了一段2005年写的关于需求的文字
  • java每日精进 5.18【文件存储】
  • Ubuntu 18.04设置静态IP的方法(图形化操作)
  • 美丽的独处时光
  • 菱形继承原理
  • java集合相关的api-总结
  • 2025年- H27-Lc135- 239.滑动窗口最大值(自定义双端队列)---java版
  • 量子计算在金融科技中的应用前景
  • [Codeforce刷题8]
  • 无废话离线大模型安装
  • 【随机过程】贝叶斯估计
  • 游戏引擎学习第292天:实现蛇
  • es聚合-词条统计
  • 量子计算 | 量子密码学的挑战和机遇
  • LWIP的NETCONN接口
  • APP手机端测试覆盖点
  • 专业漏洞扫描机构如何助力企业保障安全并提升竞争力?
  • 【MySQL】库与表的操作
  • 力扣热题——数组的最小相等和
  • 关于 Web 漏洞原理与利用:1. SQL 注入(SQLi)
  • 基于FPGA的电子万年历系统开发,包含各模块testbench
  • ​Docker 网络
  • 前端三剑客之HTML
  • 深入解析Python中的Vector2d类:从基础实现到特殊方法的应用
  • nginx服务器实验
  • 23种设计模式解释+记忆
  • 虚幻引擎5-Unreal Engine笔记之`GameMode`、`关卡(Level)` 和 `关卡蓝图(Level Blueprint)`的关系
  • 快速上手SElinux