Shapefiles are one of the most common formats used for storing vector GIS data such as points, lines, and polygons. When building a desktop GIS application using Qt, developers often need to load shapefiles, visualize them, and allow interactive editing of their features directly on the map.
In this article, we’ll explore how to edit shapefile features (for example, moving roads or town points) using ArcGIS Maps SDK for Qt — a powerful library for embedding GIS functionality into C++ and QML applications.
🔍 Use Cases
Editing shapefile data inside a Qt application can be useful in various geospatial workflows:
- Urban Planning: Move or update building or road features interactively.
- Defense and Mission Systems: Adjust operational areas or update sensor/troop positions in a local shapefile.
- Survey Data Correction: Correct field-captured GPS data directly within your application.
- Custom GIS Tools: Enable lightweight, offline editing without needing a full GIS desktop tool like ArcGIS Pro or QGIS.
⚙️ Tools and SDKs Used
To build this functionality, we use:
- Qt 6 / Qt Quick for cross-platform GUI.
- ArcGIS Maps SDK for Qt (C++ API) to display and interact with GIS data.
- ShapefileFeatureTable and FeatureLayer classes to load and edit shapefile features.
✅ The SDK provides high-performance 2D and 3D mapping, geometry engine, rendering, and editing capabilities — all available in native C++ or QML.
💻 Example: Editing Shapefile Features in Qt
Below is a simplified and working version of the EditShapeFileFeatures class that enables shapefile feature editing (drag-and-drop geometry movement) using ArcGIS Maps SDK for Qt.
#include "EditShapeFileFeatures.h"
#include <QFutureWatcher>
#include <QDebug>
using namespace Esri::ArcGISRuntime;
EditShapeFileFeatures::EditShapeFileFeatures(QObject* parent)
: QObject(parent)
{
// Load shapefile layers
auto* landTable = new ShapefileFeatureTable("C:/GIS/world.shp", this);
auto* landLayer = new FeatureLayer(landTable, this);
landLayer->setRenderer(new SimpleRenderer(
new SimpleFillSymbol(SimpleFillSymbolStyle::Solid, QColor("white"),
new SimpleLineSymbol(SimpleLineSymbolStyle::Solid, QColor("black"), 0.5, this), this)));
m_editTable = new ShapefileFeatureTable("C:/GIS/towns.shp", this);
m_editLayer = new FeatureLayer(m_editTable, this);
m_editLayer->setRenderer(new SimpleRenderer(
new SimpleMarkerSymbol(SimpleMarkerSymbolStyle::Circle, QColor("green"), 6.0, this), this));
m_map = new Map(BasemapStyle::ArcGISLightGray, this);
m_map->operationalLayers()->append(landLayer);
m_map->operationalLayers()->append(m_editLayer);
}
void EditShapeFileFeatures::setMapView(MapQuickView* mapView)
{
m_mapView = mapView;
m_mapView->setMap(m_map);
connect(m_mapView, &MapQuickView::mousePressed, this, &EditShapeFileFeatures::onMousePressed);
connect(m_mapView, &MapQuickView::mouseMoved, this, &EditShapeFileFeatures::onMouseMoved);
connect(m_mapView, &MapQuickView::mouseReleased, this, &EditShapeFileFeatures::onMouseReleased);
}
void EditShapeFileFeatures::onMousePressed(QMouseEvent& event)
{
QPointF screenPoint = event.position();
QFuture<IdentifyLayerResult*> future =
m_mapView->identifyLayerAsync(m_editLayer, screenPoint, 10.0, false, 1);
auto* watcher = new QFutureWatcher<IdentifyLayerResult*>(this);
connect(watcher, &QFutureWatcher<IdentifyLayerResult*>::finished, this, [this, watcher]() {
auto* result = watcher->result();
watcher->deleteLater();
if (!result || result->geoElements().isEmpty())
return;
m_selectedFeature = dynamic_cast<Feature*>(result->geoElements().first());
if (m_selectedFeature)
m_isDragging = true;
});
watcher->setFuture(future);
}
void EditShapeFileFeatures::onMouseMoved(QMouseEvent& event)
{
if (!m_isDragging || !m_selectedFeature)
return;
Point mapPoint = m_mapView->screenToLocation(event.position().x(), event.position().y());
m_selectedFeature->setGeometry(mapPoint);
}
void EditShapeFileFeatures::onMouseReleased(QMouseEvent&)
{
if (!m_isDragging || !m_selectedFeature)
return;
m_isDragging = false;
auto updateFuture = m_editTable->updateFeatureAsync(m_selectedFeature);
auto* watcher = new QFutureWatcher<void>(this);
connect(watcher, &QFutureWatcher<void>::finished, this, [watcher]() {
watcher->deleteLater();
qDebug() << "✅ Feature updated in shapefile.";
});
watcher->setFuture(updateFuture);
}
This example shows:
- Loading shapefiles as FeatureLayers.
- Identifying and selecting a feature by mouse click.
- Updating its geometry interactively.
- Saving the updated geometry back to the shapefile.
🧩 Key Components Explained
| Component | Purpose |
|---|---|
| ShapefileFeatureTable | Loads a .shp file for read/write access. |
| FeatureLayer | Displays shapefile data on the map. |
| MapQuickView | Provides interactive display and input handling. |
| updateFeatureAsync() | Commits geometry edits back to the shapefile. |
| IdentifyLayerResult | Detects clicked features for editing. |
🚀 Conclusion
ArcGIS Maps SDK for Qt allows developers to create powerful, native GIS applications with full control over data visualization and editing workflows. By using the ShapefileFeatureTable and FeatureLayer classes, you can easily enable feature-level editing, even for local shapefiles — without needing an internet connection.
Whether you’re developing a defense mission system, a real-time situational awareness dashboard, or a custom GIS viewer, this SDK offers a robust foundation for spatial applications.
💼 Contact Us
At Manya Technologies, we specialize in custom GIS application development using Qt, ArcGIS, CesiumJS and QGIS APIs.
If your organization needs offline GIS tools, shapefile editors, or map-based simulators, we can help you design and implement end-to-end solutions.
📩 Contact: info@manyatechnologies.com
🌐 Website: https://manyatechnologies.com

