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

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

系列目录:

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

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

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


4  地图编辑

4.1 添加点要素

功能演示

运行程序后,点击菜单栏中的“数据->添加矢量数据”以导入测试所需的点要素矢量图层。

图 30 导入数据示意图

在图层列表中选中相应的图层,然后单击右侧边栏中的“启动/关闭几何编辑”按钮,以启动编辑模式。接着,点击“添加点”按钮,进入点添加模式。此时,利用鼠标左键在图框内的任意位置进行点击,将弹出一个窗口,用于设置新增点要素的属性值。

图 31 为新要素添加属性示意图

在属性值编辑窗口中,可以根据需要填写新增点要素的属性信息。这些属性值默认为Null,但可以选择全部填入或者部分填入,根据实际情况进行设置,也可以通过点击“Cancel”按钮取消添加。

添加完成后,新的点要素将在图层和属性表中显示出来。

图 32 添加完成后的新要素及其属性展示

从上图可以看到,添加的点要素成功录入并显示在图层和属性表中。

代码展示

定义了一个名为QgsMapToolEditPoint的类,继承自QgsMapTool用来处理地图编辑操作。构造函数接受一个QgsMapCanvas和QgsVectorLayer,分别表示地图画布和当前图层。

在重载的鼠标按下事件函数canvasPressEvent中,首先检查当前图层是否有效,然后获取鼠标点击位置的坐标。然后启动图层编辑模式,通过addFeature方法创建新的点要素,并通过用户界面弹出窗口(QDialog)收集用户输入的属性值。用户可以为每个属性输入相应的数值或文本,并通过OK按钮确认。

用户在点击OK按钮后,程序会将用户输入的属性值与字段进行匹配,并添加新的要素至图层。如果用户点击Cancel按钮,则取消编辑操作,删除刚刚添加的要素。整个过程通过连接信号槽机制实现,其中包括了用户输入校验、属性值转换以及图层刷新等步骤。核心代码如下:

QgsMapToolEditPoint::QgsMapToolEditPoint(QgsMapCanvas* mapcanvas, QgsVectorLayer* currentlayer) : QgsMapTool(mapcanvas), m_mapCanvas(mapcanvas), m_currentLayer(currentlayer)  
{  m_mapCanvas = mapcanvas;  m_currentLayer = currentlayer;  
}  QgsMapToolEditPoint::~QgsMapToolEditPoint() {};  void  QgsMapToolEditPoint::canvasPressEvent(QgsMapMouseEvent* e) {  if (!m_currentLayer)  {  // 处理图层无效的情况  return;  }  // 从函数体内获取点击的点坐标  QgsMapCanvas* canvas = this->canvas();  if (!canvas)  {  // 处理无效的画布  return;  }  QgsPointXY point = canvas->getCoordinateTransform()->toMapCoordinates(canvas->mouseLastXY());  m_currentLayer->startEditing();  QgsFeature feature;  // 创建新要素,传递用户点击的点坐标  feature.setGeometry(QgsGeometry::fromPointXY(point));  QgsFields fields = m_currentLayer->fields();  feature.setFields(fields);  QDialog inputDialog;  QFormLayout formLayout(&inputDialog);  QList<QString> attributeNames;  QList<QVariant> attributeValues;  for (const QgsField& field : fields)  {  QString attributeName = field.name();  QVariant::Type attributeType = field.type();  QString labelText = "输入属性 " + attributeName + " 的属性值:";  QString defaultValue = "";  // Set default value if needed  QLineEdit* inputLineEdit = new QLineEdit(&inputDialog);  inputLineEdit->setText(defaultValue);  formLayout.addRow(labelText, inputLineEdit);  attributeNames.append(attributeName);  }  QPushButton* okButton = new QPushButton("OK", &inputDialog);  QPushButton* cancelButton = new QPushButton("CANCEL", &inputDialog);  formLayout.addRow(okButton);  formLayout.addRow(cancelButton);  QObject::connect(okButton, &QPushButton::clicked, [&]() {  QMap<QString, QVariant> attributeMap;  for (int i = 0; i < attributeNames.size(); ++i)  {  QLineEdit* inputLineEdit = qobject_cast<QLineEdit*>(formLayout.itemAt(i, QFormLayout::FieldRole)->widget());  if (inputLineEdit)  {  QString inputValue = inputLineEdit->text().trimmed();  // Trim leading and trailing whitespaces  if (inputValue == "") continue;  QVariant::Type attributeType = fields[i].type();  QVariant convertedValue;  bool conversionOk;  switch (attributeType)  {  case QVariant::Int:  convertedValue = inputValue.toInt(&conversionOk);  break;  case QVariant::Double:  convertedValue = inputValue.toDouble(&conversionOk);  break;  // 其他类型的转换可以根据需要继续添加  default:  convertedValue = inputValue;  conversionOk = true;  }  if (!conversionOk)  {  // 用户取消输入,中断操作  return;  }  attributeMap[attributeNames[i]] = convertedValue;  }  }  QgsAttributes attributes;  for (const QString& attributeName : attributeNames)  {  QVariant value = attributeMap.value(attributeName, QVariant());  // Get value from map, default to QVariant()  attributes << value;  }  feature.setAttributes(attributes);  m_currentLayer->dataProvider()->addFeature(feature);  m_currentLayer->commitChanges();  m_mapCanvas->refresh();  inputDialog.accept();  // Close the dialog after processing  });  QObject::connect(cancelButton, &QPushButton::clicked, [&]() {  m_currentLayer->removeSelection();  m_currentLayer->dataProvider()->deleteFeatures({ feature.id() });  inputDialog.reject();  // Close the dialog without processing  return;  });  inputDialog.setWindowTitle("输入属性值");  inputDialog.exec();  }  

4.2 添加线要素

运行程序后,点击菜单栏中的“数据->添加矢量数据”以导入测试所需的线要素矢量图层。

图 33 导入数据示意图

在图层列表中选中所需的图层,点击右侧边栏中的“启动/关闭几何编辑”按钮,启用编辑模式。接下来,点击“添加线”按钮,进入线添加模式。在这个模式下,使用鼠标左键在图框内的各个位置点击,以添加线的顶点。当线的形状满足需求后,通过右键停止添加顶点,并弹出窗口,用于设置新增线要素的属性值。

图 34 鼠标左键绘制新要素示意图

图 35 为新要素添加属性示意图

在属性值编辑窗口中,可以根据具体需求填写新增线要素的属性信息。这些属性值默认为Null,可以选择全部填入或者部分填入,具体取决于实际情况。如果想要取消添加,点击“Cancel”按钮即可。

添加操作完成后,新的线要素将在图层和属性表中显示。

图 36 添加完成后的新要素及其属性展示

代码展示

定义了一个名为QgsMapToolAddLine的类,继承自QgsMapTool,用于处理地图编辑操作。构造函数接受一个QgsMapCanvas和QgsVectorLayer,表示地图画布和当前图层。在canvasMoveEvent函数中,实时响应鼠标移动事件,根据用户的交互动作动态绘制线的顶点,对于左键点击,记录线的顶点坐标,并在右键点击时停止绘制,弹出窗口用于设置新增线要素的属性值。用户可以在弹出的属性值编辑窗口中填写相应的属性信息,完成后将新的线要素添加至图层。

整个过程通过QgsRubberBand类实现线的实时绘制,同时通过信号槽机制连接属性值编辑窗口的确认和取消按钮。在完成线要素的添加后刷新地图画布以更新显示。

QgsMapToolAddLine::QgsMapToolAddLine(QgsMapCanvas* canvas, QgsVectorLayer* currentlayer) :QgsMapTool(canvas), pMapCanvas(canvas), m_currentLayer(currentlayer)  
{  pMapCanvas = canvas;  m_currentLayer = currentlayer;  //设置QgsRubberBand对象,绘制折线  pRubBand = new QgsRubberBand(pMapCanvas);  mColor = QColor(255, 0, 0);  LineWidth = 2;  ButtonClickFlag = false;  
}  QgsMapToolAddLine::~QgsMapToolAddLine(void)  
{  /*if(pRubBand){ delete pRubBand ; }*/  
}  
//重载鼠标移动事件  
void QgsMapToolAddLine::canvasMoveEvent(QgsMapMouseEvent* e)  
{  m_currentLayer->startEditing();  int xc, yc;  //如果鼠标左键没有双击  if (!ButtonClickFlag) {  return;  }  pRubBand->setColor(mColor);  pRubBand->setWidth(LineWidth);  xc = e->x();  yc = e->y();  //得到当前坐标变换对象  const QgsMapToPixel* pTransform = pMapCanvas->getCoordinateTransform();  //转换成地图坐标  QgsPoint mPoint(pTransform->toMapCoordinates(xc, yc));  if (pRubBand->numberOfVertices() > 1) {  pRubBand->removeLastPoint();  }  //把当前点添加到QgsRubberBand对象中用于绘制  pRubBand->addPoint(mPoint);  
}  
//重载鼠标单击事件  
void  QgsMapToolAddLine::canvasPressEvent(QgsMapMouseEvent* e)  
{  // 创建要素  QgsFeature feature;  int xc, yc;  pRubBand->setColor(mColor);  pRubBand->setWidth(LineWidth);  //得到当前坐标变换对象  const QgsMapToPixel* pTransform = pMapCanvas->getCoordinateTransform();  //得到产生事件的按钮信息  Qt::MouseButton mButton = e->button();  xc = e->x();  yc = e->y();  QgsPoint  mPoint(pTransform->toMapCoordinates(xc, yc));  //如果是左按钮  if (mButton == Qt::MouseButton::LeftButton) {  ButtonClickFlag = true;  //把当前点添加到QgsRubberBand对象中用于绘制  pRubBand->addPoint(mPoint);  mPointSet.append(mPoint);  }  else if (mButton == Qt::MouseButton::RightButton) {  pRubBand->addPoint(mPoint);  mPointSet.append(mPoint);  ButtonClickFlag = false;  //转化为几何体  QgsGeometry geometry = pRubBand->asGeometry();  feature.setGeometry(geometry);  if (feature.hasGeometry())  {  QgsFields fields = m_currentLayer->fields();  feature.setFields(fields);  QDialog inputDialog;  QFormLayout formLayout(&inputDialog);  QList<QString> attributeNames;  QList<QVariant> attributeValues;  for (const QgsField& field : fields)  {  QString attributeName = field.name();  QVariant::Type attributeType = field.type();  QString labelText = "输入属性 " + attributeName + " 的属性值:";  QString defaultValue = "";  // Set default value if needed  QLineEdit* inputLineEdit = new QLineEdit(&inputDialog);  inputLineEdit->setText(defaultValue);  formLayout.addRow(labelText, inputLineEdit);  attributeNames.append(attributeName);  }  QPushButton* okButton = new QPushButton("OK", &inputDialog);  QPushButton* cancelButton = new QPushButton("CANCEL", &inputDialog);  formLayout.addRow(okButton);  formLayout.addRow(cancelButton);  QObject::connect(okButton, &QPushButton::clicked, [&]() {  QMap<QString, QVariant> attributeMap;  for (int i = 0; i < attributeNames.size(); ++i)  {  QLineEdit* inputLineEdit = qobject_cast<QLineEdit*>(formLayout.itemAt(i, QFormLayout::FieldRole)->widget());  if (inputLineEdit)  {  QString inputValue = inputLineEdit->text().trimmed();  // Trim leading and trailing whitespaces  if (inputValue == "") continue;  QVariant::Type attributeType = fields[i].type();  QVariant convertedValue;  bool conversionOk;  switch (attributeType)  {  case QVariant::Int:  convertedValue = inputValue.toInt(&conversionOk);  break;  case QVariant::Double:  convertedValue = inputValue.toDouble(&conversionOk);  break;  // 其他类型的转换可以根据需要继续添加  default:  convertedValue = inputValue;  conversionOk = true;  }  if (!conversionOk)  {  // 用户取消输入,中断操作  return;  }  attributeMap[attributeNames[i]] = convertedValue;  }  }  QgsAttributes attributes;  for (const QString& attributeName : attributeNames)  {  QVariant value = attributeMap.value(attributeName, QVariant());  // Get value from map, default to QVariant()  attributes << value;  }  feature.setAttributes(attributes);  m_currentLayer->dataProvider()->addFeature(feature);  m_currentLayer->commitChanges();  pMapCanvas->refresh();  inputDialog.accept();  // Close the dialog after processing  });  QObject::connect(cancelButton, &QPushButton::clicked, [&]() {  pRubBand->reset();  mPointSet.clear();  inputDialog.reject();  // Close the dialog without processing  });  inputDialog.setWindowTitle("输入属性值");  inputDialog.exec();  pMapCanvas->refresh();  pRubBand->reset();  mPointSet.clear();  }  }  }  
//设置绘制颜色和线宽  
void QgsMapToolAddLine::SetColorAndWidth(QColor color, int nWidth)  
{  mColor = color;  LineWidth = nWidth;  
}  //返回构成线段的数据点数  
int QgsMapToolAddLine::GetVertexCount()  
{  return mPointSet.size();  
}  
//得到点的坐标  
bool QgsMapToolAddLine::GetCoord(int index, double& x, double& y)  
{  QgsPoint mPoint;  if (index >= mPointSet.size()) {  return true;  }  mPoint = mPointSet.at(index);  x = mPoint.x();  y = mPoint.y();  
}  

4.3 添加面要素

首先添加一个面数据之后,再点击按钮“添加面”

图 37 添加面按键

鼠标左键点击来绘制要素;

图 38 添加面操作

右键之后完成绘制,跳出相关属性的填写框;

图 39 输入属性

填写完之后,点击OK;完成绘制

图 40 添加面成功

相关代码思路分析

首先,它获取当前在图层树视图中选中的图层,并把它转换为一个矢量图层(假设当前层是矢量层)。然后,该代码使该矢量图层进入编辑模式。接着,在地图画布中设置这个矢量图层为当前图层,并创建一个用于添加多边形要素的地图工具QgsMapToolAddFeature,最后将此工具设置为当前地图画布的工具,同时将捕获模式为多边形绘制。

代码部分如下

void DataViewer::on_actionAddPolygons_triggered()    
{    currentLayer = m_layerTreeView->currentLayer();    QgsVectorLayer* layer = qobject_cast<QgsVectorLayer*>(currentLayer);    //面编辑——添加要素    layer->startEditing();    m_mapCanvas->setLayers(QList<QgsMapLayer*>() << layer);    m_mapCanvas->setCurrentLayer(layer);    QgsMapToolAddFeature* addFeaturepolygonTool = new QgsMapToolAddFeature(m_mapCanvas, QgsMapToolCapture::CapturePolygon);    m_mapCanvas->setMapTool(addFeaturepolygonTool);    }   

相关文章:

  • Python数据可视化 - Pyecharts绘图示例
  • 【Linux网络】五种IO模型与阻塞IO
  • 【MYSQL】笔记
  • Go 后端中双 token 的实现模板
  • 几种基于比较的排序
  • 建一个结合双向长短期记忆网络(BiLSTM)和条件随机场(CRF)的模型
  • 【java多线程】线程间通信-利用wait和notify轮流按序打印奇数和偶数
  • 什么是着色器 Shader
  • 正则表达式与文本处理的艺术
  • WPS多级标题编号以及样式控制
  • k6学习k6学习k6学习k6学习k6学习k6学习
  • 【Android】从Choreographer到UI渲染(二)
  • Linux虚拟文件系统(1)
  • Spark,数据提取和保存
  • 数组随机重排与维度转换算法
  • 深入解析Python中的Vector2d类:从基础实现到特殊方法的应用
  • ngx_http_random_index_module 模块概述
  • LoadBarWorks:一款赛博风加载动画生成器的构建旅程
  • linux下的 xargs命令使用详解
  • 墨水屏显示模拟器程序解读
  • 墨西哥海军帆船纽约撞桥事故已致2人死亡19人受伤
  • 家国万里·时光故事会|构筑中国船舰钢筋铁骨,她在焊花里展现工匠风范
  • 《歌手》回归,人均技术流,00后整顿职场
  • 刘强东坐镇京东一线:管理层培训1800人次,最注重用户体验
  • 蚊媒传染病、手足口病……上海疾控发布近期防病提示
  • 杭勇已任常州市政协党组成员,此前任常州市委常委、秘书长