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

【QGIS二次开发】地图显示与交互-03

系列目录:

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

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


3. 地图符号与色表

3.1 矢量图层符号设置

任务要求:双击图层树节点,实现图层中图元的符号的设置并更新地图显示。图层可以是点、线、面图层中的任何一种。

完成的逻辑是在QgsLayerTreeViewMenuProvider的实例类中添加一个openSymbologyDialog方法,实现矢量图层符号化功能。

代码逻辑如下:

首先,检查是否有当前选中的图层,如果没有则直接返回。接下来,尝试将该图层转换为矢量图层。如果转换成功,获取当前图层的渲染器和默认样式。然后,使用QgsSingleSymbolRendererWidget类创建一个新的符号化设置窗口。创建一个对话框,并将其布局设置为垂直布局。将符号化设置窗口添加到布局中。创建一个按钮框,其中包含“应用”、“确定”、“取消”和“保存样式”按钮,并将其添加到布局中。连接“应用”按钮的clicked信号到一个槽函数。在槽函数中,获取符号化设置窗口的渲染器,并将其设置到矢量图层中。然后,触发图层的重绘。最后,显示对话框并等待用户的操作。如果用户点击了“确定”按钮,执行与“应用”按钮相同的操作。这样,整个操作将图层转换为矢量图层,并提供用户在符号化设置窗口中进行样式调整的选项。

实现的效果是,在图层管理器中图层的右键菜单中添加图层符号化菜单选项,点击图层符号化菜单选项打开对话框,由于直接调用了QGIS的QgsSingleSymbolRendererWidget类,因此界面逻辑和QGIS中修改矢量图层符号化相似。

核心代码如下:

void MenuProvider::openSymbologyDialog()  
{  // 获取当前选中的图层  QModelIndex index = mView->currentIndex();  // 获取图层树模型  QgsLayerTreeModel* layerTreeModel = mView->layerTreeModel();  // 将当前选中的索引转换为一个图层树节点  QgsLayerTreeNode* node = layerTreeModel->index2node(index);  // 将节点转换为一个地图图层  QgsMapLayer* layer = QgsLayerTree::toLayer(node)->layer();  // 如果获取的图层为空,则返回  if (!layer)  return;  // 尝试将图层转换为矢量图层  QgsVectorLayer* vLayer = qobject_cast<QgsVectorLayer*>(layer);  // 尝试将图层转换为栅格图层  QgsRasterLayer* rLayer = qobject_cast<QgsRasterLayer*>(layer);  if (vLayer) {  // 获取当前图层的渲染器  QgsFeatureRenderer* renderer = vLayer->renderer();  // 获取默认的样式  QgsStyle* style = QgsStyle::defaultStyle();  // 创建一个新的符号化设置窗口  QgsSingleSymbolRendererWidget* rendererWidget = new QgsSingleSymbolRendererWidget(vLayer, style, renderer->clone());  // 创建一个对话框  QDialog* dialog = new QDialog();  // 创建一个垂直布局,并将其设置到对话框中  QVBoxLayout* layout = new QVBoxLayout(dialog);  // 将符号化设置窗口添加到布局中  layout->addWidget(rendererWidget);  dialog->resize(600, 800);  // 创建一个包含“应用”、“确定”、“取消”和“保存样式”按钮的按钮框,并将其添加到布局中  QDialogButtonBox* buttonBox = new QDialogButtonBox(QDialogButtonBox::Apply | QDialogButtonBox::Ok | QDialogButtonBox::Cancel, dialog);  QPushButton* saveStyleButton = new QPushButton("保存样式");  buttonBox->addButton(saveStyleButton, QDialogButtonBox::ActionRole);  layout->addWidget(buttonBox);  layout->addWidget(buttonBox);  // 获取应用按钮并连接其clicked信号到一个自定义的槽  QPushButton* applyButton = buttonBox->button(QDialogButtonBox::Apply);  QObject::connect(applyButton, &QPushButton::clicked, [=]() {  // 这个槽执行和“确定”按钮一样的操作,但是不关闭对话框  vLayer->setRenderer(rendererWidget->renderer());  vLayer->triggerRepaint();  });  // 连接按钮框的“应用”、“确定”和“取消”信号到对话框的“接受”和“拒绝”槽  QObject::connect(buttonBox, &QDialogButtonBox::accepted, dialog, &QDialog::accept);  QObject::connect(buttonBox, &QDialogButtonBox::rejected, dialog, &QDialog::reject);  // 显示对话框,并等待用户的操作  if (dialog->exec() == QDialog::Accepted)  {  
 // 如果用户点击了“确定”按钮,就获取符号化设置窗口的渲染器,并将其设置到矢量图层中  vLayer->setRenderer(rendererWidget->renderer());  // 触发图层的重绘,以更新图层的显示  vLayer->triggerRepaint();  }  }  else if (rLayer) {  // 获取当前图层的渲染器  QgsRasterRenderer* renderer = rLayer->renderer();  // 创建一个新的符号化设置窗口  QgsSingleBandPseudoColorRendererWidget* rendererWidget = new QgsSingleBandPseudoColorRendererWidget(rLayer, rLayer->extent());  // 创建一个对话框  QDialog* dialog = new QDialog();  // 创建一个垂直布局,并将其设置到对话框中  QVBoxLayout* layout = new QVBoxLayout(dialog);  // 将符号化设置窗口添加到布局中  layout->addWidget(rendererWidget);  // 创建一个包含“应用”、“确定”和“取消”按钮的按钮框,并将其添加到布局中  QDialogButtonBox* buttonBox = new QDialogButtonBox(QDialogButtonBox::Apply | QDialogButtonBox::Ok | QDialogButtonBox::Cancel, dialog);  layout->addWidget(buttonBox);  // 获取应用按钮并连接其clicked信号到一个自定义的槽  QPushButton* applyButton = buttonBox->button(QDialogButtonBox::Apply);  QObject::connect(applyButton, &QPushButton::clicked, [=]() {  // 这个槽执行和“确定”按钮一样的操作,但是不关闭对话框  rLayer->setRenderer(rendererWidget->renderer());  rLayer->triggerRepaint();  });  // 连接按钮框的“应用”、“确定”和“取消”信号到对话框的“接受”和“拒绝”槽  QObject::connect(buttonBox, &QDialogButtonBox::accepted, dialog, &QDialog::accept);  QObject::connect(buttonBox, &QDialogButtonBox::rejected, dialog, &QDialog::reject);  // 显示对话框,并等待用户的操作  if (dialog->exec() == QDialog::Accepted)  {  // 如果用户点击了“确定”按钮,就获取符号化设置窗口的渲染器,并将其设置到栅格图层中  rLayer->setRenderer(rendererWidget->renderer());  // 触发图层的重绘,以更新图层的显示  rLayer->triggerRepaint();  }  }  
}  

    实现的效果如下:

    图 20 示例数据

    图 21 修改符号设置

    3.2 分层赋色

    任务要求: 对一个栅格图层,选择一个色表,根据图层的像元值的范围,对图层进行分层设色,并在视图中进行显示。

    完成的逻辑是在QgsLayerTreeViewMenuProvider的实例类中添加一个openSymbologyDialog方法,实现栅格图层分层设色功能。

    代码逻辑如下:

    首先,进行检查以确保当前选中的图层是栅格图层,如果是栅格图层则继续执行,否则直接返回。接着,获取当前栅格图层的渲染器。随后,创建一个新的符号化设置窗口,用于显示和编辑栅格图层的符号设置。创建一个对话框,并将其布局设置为垂直布局。将符号化设置窗口添加到对话框的布局中。创建一个按钮框,其中包含“应用”、“确定”和“取消”按钮,并将其添加到对话框的布局中。连接“应用”按钮的clicked信号到一个槽函数。在槽函数中,获取符号化设置窗口的渲染器,并将其设置到栅格图层中。然后,触发图层的重绘。最后,显示对话框并等待用户的操作。如果用户点击了“确定”按钮,执行与“应用”按钮相同的操作。这一系列步骤允许用户在符号化设置窗口中调整栅格图层的样式,并在确认或应用后将更改应用到图层中。

    实现的效果是,在图层管理器中图层的右键菜单中添加图层符号化菜单选项,点击图层符号化菜单选项打开对话框,由于直接调用了QGIS的QgsSingleBandPseudoColorRendererWidget类,因此界面逻辑和QGIS中实现栅格图层分层设色相似。

    代码如下:

    void MenuProvider::openSymbologyDialog()  
    {  // 获取当前选中的图层  QModelIndex index = mView->currentIndex();  // 获取图层树模型  QgsLayerTreeModel* layerTreeModel = mView->layerTreeModel();  // 将当前选中的索引转换为一个图层树节点  QgsLayerTreeNode* node = layerTreeModel->index2node(index);  // 将节点转换为一个地图图层  QgsMapLayer* layer = QgsLayerTree::toLayer(node)->layer();  // 如果获取的图层为空,则返回  if (!layer)  return;  // 尝试将图层转换为矢量图层  QgsVectorLayer* vLayer = qobject_cast<QgsVectorLayer*>(layer);  // 尝试将图层转换为栅格图层  QgsRasterLayer* rLayer = qobject_cast<QgsRasterLayer*>(layer);  if (vLayer) {  // 获取当前图层的渲染器  QgsFeatureRenderer* renderer = vLayer->renderer();  // 获取默认的样式  QgsStyle* style = QgsStyle::defaultStyle();  // 创建一个新的符号化设置窗口  QgsSingleSymbolRendererWidget* rendererWidget = new QgsSingleSymbolRendererWidget(vLayer, style, renderer->clone());  // 创建一个对话框  QDialog* dialog = new QDialog();  // 创建一个垂直布局,并将其设置到对话框中  QVBoxLayout* layout = new QVBoxLayout(dialog);  // 将符号化设置窗口添加到布局中  layout->addWidget(rendererWidget);  dialog->resize(600, 800);  // 创建一个包含“应用”、“确定”、“取消”和“保存样式”按钮的按钮框,并将其添加到布局中  QDialogButtonBox* buttonBox = new QDialogButtonBox(QDialogButtonBox::Apply | QDialogButtonBox::Ok | QDialogButtonBox::Cancel, dialog);  QPushButton* saveStyleButton = new QPushButton("保存样式");  buttonBox->addButton(saveStyleButton, QDialogButtonBox::ActionRole);  layout->addWidget(buttonBox);  layout->addWidget(buttonBox);  // 获取应用按钮并连接其clicked信号到一个自定义的槽  QPushButton* applyButton = buttonBox->button(QDialogButtonBox::Apply);  QObject::connect(applyButton, &QPushButton::clicked, [=]() {  // 这个槽执行和“确定”按钮一样的操作,但是不关闭对话框  vLayer->setRenderer(rendererWidget->renderer());  vLayer->triggerRepaint();  });  // 连接按钮框的“应用”、“确定”和“取消”信号到对话框的“接受”和“拒绝”槽  QObject::connect(buttonBox, &QDialogButtonBox::accepted, dialog, &QDialog::accept);  QObject::connect(buttonBox, &QDialogButtonBox::rejected, dialog, &QDialog::reject);  // 显示对话框,并等待用户的操作  if (dialog->exec() == QDialog::Accepted)  {  // 如果用户点击了“确定”按钮,就获取符号化设置窗口的渲染器,并将其设置到矢量图层中  vLayer->setRenderer(rendererWidget->renderer());  // 触发图层的重绘,以更新图层的显示  vLayer->triggerRepaint();  }  }  else if (rLayer) {  // 获取当前图层的渲染器  QgsRasterRenderer* renderer = rLayer->renderer();  // 创建一个新的符号化设置窗口  QgsSingleBandPseudoColorRendererWidget* rendererWidget = new QgsSingleBandPseudoColorRendererWidget(rLayer, rLayer->extent());  // 创建一个对话框  QDialog* dialog = new QDialog();  // 创建一个垂直布局,并将其设置到对话框中  QVBoxLayout* layout = new QVBoxLayout(dialog);  // 将符号化设置窗口添加到布局中  layout->addWidget(rendererWidget);  // 创建一个包含“应用”、“确定”和“取消”按钮的按钮框,并将其添加到布局中  QDialogButtonBox* buttonBox = new QDialogButtonBox(QDialogButtonBox::Apply | QDialogButtonBox::Ok | QDialogButtonBox::Cancel, dialog);  layout->addWidget(buttonBox);  // 获取应用按钮并连接其clicked信号到一个自定义的槽  QPushButton* applyButton = buttonBox->button(QDialogButtonBox::Apply);  QObject::connect(applyButton, &QPushButton::clicked, [=]() {  // 这个槽执行和“确定”按钮一样的操作,但是不关闭对话框  rLayer->setRenderer(rendererWidget->renderer());  rLayer->triggerRepaint();  });  // 连接按钮框的“应用”、“确定”和“取消”信号到对话框的“接受”和“拒绝”槽  QObject::connect(buttonBox, &QDialogButtonBox::accepted, dialog, &QDialog::accept);  QObject::connect(buttonBox, &QDialogButtonBox::rejected, dialog, &QDialog::reject);  // 显示对话框,并等待用户的操作  if (dialog->exec() == QDialog::Accepted)  {  // 如果用户点击了“确定”按钮,就获取符号化设置窗口的渲染器,并将其设置到栅格图层中  rLayer->setRenderer(rendererWidget->renderer());  // 触发图层的重绘,以更新图层的显示  rLayer->triggerRepaint();  }  }  
    }  

    实现的效果:

    图 22 示例数据

    图 23 分层赋色效果

    3.3 符号库导入输出

    符号库通过调用ui文件并进行相关配置实现了符号库的相关功能,能够导入、导出符号库文件等多种功能,实现代码如下,该函数实现了通过文件对话框选择栅格数据文件(支持img、tif、tiff格式),创建对应的QgsRasterLayer对象,并将有效的图层添加到QgsProject中。如果图层无效或文件不存在,将显示相应的提示信息。最后,通过刷新地图画布,确保新添加的图层在界面上可见。

    void DataViewer::on_actionAddRasterData_triggered()    
    {    QStringList layerPathList = QFileDialog::getOpenFileNames(this, QStringLiteral("选择栅格数据"), "", "Image (*.img *.tif *.tiff)");    QList<QgsMapLayer*> layerList;    for each (QString layerPath in layerPathList)    {    QFileInfo fi(layerPath);    if (!fi.exists()) { return; }    QString layerBaseName = fi.baseName(); // 图层名称    QgsRasterLayer* rasterLayer = new QgsRasterLayer(layerPath, layerBaseName);    if (!rasterLayer) { return; }    if (!rasterLayer->isValid())    {    QMessageBox::information(0, "", "layer is invalid");    return;    }    layerList << rasterLayer;    }    QgsProject::instance()->addMapLayers(layerList);    m_mapCanvas->refresh();    
    }    

    通过符号库能够实现符号库的设计、存储与显示,以及实现颜色、点、线、面符号的库的增删查改操作

    图 24 增加点

    图 25 增加线数据

    通过对符号右键能够出现删改符号的选项,操作如下图所示:

    图 26 删除符号

    在右下角的搜索框中输入需要搜索的内容,就能够实现对符号库内容的检索,操作如下图所示:

    图 27 搜索符号

            最后通过在MenuProvider类中添加响应槽函数实现导出图层样式为能够在GeoSever中能够使用的sld文件。操作时点击相应矢量图层或栅格图层右键弹出右键菜单,点击导出图层样式(Sld)弹出保存文件对话框,用户选择恰当的路径就能够实现Sld格式的图层样式的导出,操作流程如下图所示:

    图 28 右键菜单-导出图层样式(Sld)

    图 29 保存Sld文件对话框

            Sld图层样式的导出实现代码实现,通过在MenuProvider类中添加成员函数outputToSld函数实现将当前地图视图中选中的图层的样式保存为Sld文件。通过获取当前图层的指针,打开保存对话框以允许用户选择保存路径和文件名,然后利用saveSldStyle方法将样式保存为用户指定的Sld文件。

    void MenuProvider::outputToSld()    
    {    QgsMapLayer* currentLayer = mView->currentLayer();    if (currentLayer) {    bool error;    QString filename = QFileDialog::getSaveFileName(nullptr, "样式保存为", "", "Sld (*.sld)");    currentLayer->saveSldStyle(filename, error);    }    
    }  
    http://www.xdnf.cn/news/6416.html

    相关文章:

  1. Windows平台OpenManus部署及WebUI远程访问实现
  2. JS中的数据类型
  3. 匿名函数lambda、STL与正则表达式
  4. 3天北京旅游规划
  5. 动态规划问题 -- 多状态模型(删除并获得点数)
  6. 【python】windows实现与k230使用socket通信并传输文件
  7. 第二十四天打卡
  8. AVLTree的模拟实现
  9. 内存分配器ptmalloc2、tcmalloc、jemalloc,结构设计、内存分配过程详解
  10. Cesium.Ray 知识详解,示例代码
  11. 实验六:按键模拟控制实现
  12. Java—— 可变参数、集合工具类、集合嵌套、不可变集合
  13. 十个免费试用的云数据库
  14. Awesome WM自定义菜单实现nas共享目录挂载
  15. K8S Ingress 实现AB测试、蓝绿发布、金丝雀(灰度)发布
  16. 基于大模型预测的全面惊厥性癫痫持续状态技术方案大纲
  17. 力扣-98.验证二叉搜索树
  18. C# winform 日志 NLog
  19. 【vue】脚手架
  20. 瀑布模型VS敏捷模型VS喷泉模型
  21. 【Linux】多路转接epoll、Linux高并发I/O多路复用
  22. SpringAI
  23. 印度尼西亚数据源对接技术指南
  24. YOLOv11融合[CVPR2025]OverLock中的模块
  25. 合并有重叠的时间区间的极简方法
  26. 【证书与信任机制​】​​SSL证书类型全解析:DV、OV、EV的区别与应用场景
  27. 【C#基础】集合.Any() 与 判断集合的长度有啥区别?
  28. atoi函数,sprintf函数,memcmp函数,strchar函数的具体原型,功能,返回值;以及使用方法
  29. 现代计算机图形学Games101入门笔记(六)
  30. 19、云端工业物联网生态组件 - 工厂能效与预测维护 - /数据与物联网组件/cloud-iiot-factory-analysis