Learn how to download and display an offline map for a user-defined geographical area of a web map.
Offline maps allow users to continue working when network connectivity is poor or lost. If a web map is enabled for offline use, a user can request that ArcGIS generates an offline map for a specified geographic area of interest.
In this tutorial, you will download an offline map for an area of interest from the web map of the stormwater network within Naperville, IL, USA . You can then use this offline map without a network connection.
Prerequisites
The following are required for this tutorial:
- An ArcGIS account to access API keys. If you don't have an account, sign up for free.
- Your system meets the system requirements.
- The ArcGIS Maps SDK for Qt, version 200.4.0 or later is installed.
- The Qt 6.5.1 software development framework is installed.
Steps
Get the web map item ID
You can use ArcGIS tools to create and view web maps. Use the Map Viewer to identify the web map item ID. This item ID will be used later in the tutorial.
- Go to the Naperville water network in the Map Viewer in ArcGIS Online. This web map displays stormwater network within Naperville, IL, USA .
- Make a note of the item ID at the end of the browser's URL. The item ID should be:
acc027394bc84c2fb04d1ed317aac674
Create a new ArcGIS Maps Qt Creator Project
-
Start Qt Creator.
-
Click File > New File or Project. Under Projects, select ArcGIS.
-
Select the ArcGIS Maps 200.4.0 Qt Quick C++ app project template (or a later version) and click Choose.
You may have several selections for the ArcGIS project type. Be sure to select ArcGIS Maps 200.4.0 Qt Quick C++ app (or a later version).
-
In the Project Location dialog, name your project display_an_offline_map. Click Next.
-
In the Define Build System dialog, select qmake for your build system. Click Next.
-
In the Define Project Details dialog, give this app a description or leave it as is. Leave the rest of this dialog as is.
-
Leave the 3D project box unchecked. At the ArcGIS Online Basemap dropdown menu, select Streets. Then click Next.
-
On the Kit Selection dialog, check the kit(s) you previously set up when you installed the API. You should select a Desktop kit to run this tutorial. Then click Next.
-
At the Project Management dialog, the option to Add as a subproject to root project is only available if you have already created a root project. Ignore this dialog for this tutorial. Click Next.
Set your API key
An API key is required to enable access to services, web maps, and web scenes hosted in ArcGIS Online.
If you haven't already, go to your developer dashboard to get your API key. For these tutorials, use your default API key. It is scoped to include all of the services demonstrated in the tutorials.
Display the web map
You can display a web map using the web map's item ID. Create a map from the web map portal item, and display it in your app.
-
In Projects, double-click Headers > Display_an_offline_map.h to open the file. Add the following classes to the header file.
Display_an_offline_map.hUse dark colors for code blocks Add line. Add line. namespace Esri::ArcGISRuntime { class Map; class MapQuickView; class PortalItem; class OfflineMapTask;
-
Add the
generate
function declaration and member variablesM a p By Extent() m_
andportal Item m_
. Save and close the file.offline M a p Task Display_an_offline_map.hUse dark colors for code blocks Add line. Add line. Add line. private: Esri::ArcGISRuntime::MapQuickView* mapView() const; void setMapView(Esri::ArcGISRuntime::MapQuickView* mapView); void generateMapByExtent(); Esri::ArcGISRuntime::Map* m_map = nullptr; Esri::ArcGISRuntime::MapQuickView* m_mapView = nullptr; Esri::ArcGISRuntime::PortalItem* m_portalItem = nullptr; Esri::ArcGISRuntime::OfflineMapTask* m_offlineMapTask = nullptr;
-
In Projects, double-click Sources > Display_an_offline_map.cpp to open the file. Remove the
#include
statement forMap
; the map is provided by the offline map.Types.h Display_an_offline_map.cppUse dark colors for code blocks Remove line #include "Display_an_offline_map.h" #include "Map.h" #include "MapTypes.h" #include "MapQuickView.h"
-
Add the following
#include
statements. These classes are needed for this application.Display_an_offline_map.cppUse dark colors for code blocks Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. #include "Display_an_offline_map.h" #include "Map.h" #include "MapQuickView.h" #include "Envelope.h" #include "EnvelopeBuilder.h" #include "Error.h" #include "GenerateOfflineMapParameters.h" #include "GenerateOfflineMapJob.h" #include "GenerateOfflineMapResult.h" #include "Graphic.h" #include "GraphicListModel.h" #include "GraphicsOverlay.h" #include "GraphicsOverlayListModel.h" #include "OfflineMapTask.h" #include "Portal.h" #include "PortalItem.h" #include "SimpleFillSymbol.h" #include "SimpleLineSymbol.h" #include "SpatialReference.h" #include "SymbolTypes.h" #include "TaskTypes.h" #include <QFuture> #include <QDir> #include <QUuid>
-
Delete the comma after
QObject(parent)
and remove theMap
from the constructor.Display_an_offline_map.cppUse dark colors for code blocks Change line Change line Remove line Display_an_offline_map::Display_an_offline_map(QObject* parent /* = nullptr */): QObject(parent), m_map(new Map(BasemapStyle::ArcGISStreets, this))
-
Instantiate a
Portal
and from that, aPortalItem
using the web map item ID for the Naperville water network. Use that to create a newMap
. Then create a newOfflineMapTask
referencing that portal item.Display_an_offline_map.cppUse dark colors for code blocks Add line. Add line. Add line. Add line. Display_an_offline_map::Display_an_offline_map(QObject* parent /* = nullptr */): QObject(parent) { Portal* portal = new Portal(false, this); m_portalItem = new PortalItem(portal, "acc027394bc84c2fb04d1ed317aac674", this); m_map = new Map(m_portalItem, this); m_offlineMapTask = new OfflineMapTask(m_portalItem, this);
-
Press Ctrl + R to run the app.
You should see a map of the stormwater network within Naperville, IL, USA. Use the mouse to drag, scroll, and double-click the map view to explore the map.
Specify the area of the web map to take offline
-
Add the call to
generate
. (The next step implements this function.)M a p By Extent Display_an_offline_map.cppUse dark colors for code blocks Add line. // Set the view (created in QML) void Display_an_offline_map::setMapView(MapQuickView* mapView) { if (!mapView || mapView == m_mapView) { return; } m_mapView = mapView; m_mapView->setMap(m_map); generateMapByExtent();
-
Begin to implement the
generate
function. UseM a p By Extent() EnvelopeBuilder
to set four parameters and then callt
to create the envelope.o Envelope() Display_an_offline_map.cppUse dark colors for code blocks Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. // Set the view (created in QML) void Display_an_offline_map::setMapView(MapQuickView* mapView) { if (!mapView || mapView == m_mapView) { return; } m_mapView = mapView; m_mapView->setMap(m_map); generateMapByExtent(); emit mapViewChanged(); } void Display_an_offline_map::generateMapByExtent() { // Create envelope to define area of interest EnvelopeBuilder* envelopeBuilder = new EnvelopeBuilder(SpatialReference::wgs84(), this); envelopeBuilder->setXMin(-88.1526); envelopeBuilder->setXMax(-88.1490); envelopeBuilder->setYMin(41.7694); envelopeBuilder->setYMax(41.7714); Envelope offlineArea = envelopeBuilder->toEnvelope(); }
-
Add a graphic to
generate
to show the area you will take offline.M a p By Extent() Create a
Graphic
using the envelope,SimpleFillSymbol
andSimpleLineSymbol
. From this create aGraphicsOverlay
and add it to the mapView.Display_an_offline_map.cppUse dark colors for code blocks Add line. Add line. Add line. Add line. Add line. Add line. void Display_an_offline_map::generateMapByExtent() { // Create envelope to define area of interest EnvelopeBuilder* envelopeBuilder = new EnvelopeBuilder(SpatialReference::wgs84(), this); envelopeBuilder->setXMin(-88.1526); envelopeBuilder->setXMax(-88.1490); envelopeBuilder->setYMin(41.7694); envelopeBuilder->setYMax(41.7714); Envelope offlineArea = envelopeBuilder->toEnvelope(); Graphic* box = new Graphic(offlineArea, new SimpleFillSymbol(SimpleFillSymbolStyle::Solid, Qt::transparent, new SimpleLineSymbol(SimpleLineSymbolStyle::Solid, Qt::red, 3, this), this), this); GraphicsOverlay* boxOverlay = new GraphicsOverlay(this); boxOverlay->graphics()->append(box); // add graphics overlay to the map view m_mapView->graphicsOverlays()->append(boxOverlay);
-
Press Ctrl + R to run the app.
You should see a red outline on the stormwater network within Naperville, IL, USA. This indicates the area of the web map that you are going to take offline.
Download and display the offline map
-
Add the following
create
method that creates aDefault Generate Offline M a p Parameters Async Generate
object. These offline map parameters will serves as the input to create aOffline M a p Parameters GenerateOfflineMapJob
. Store the resulting offline mobile map package (MMPK) at a desired local folder. Don't add a closing brace yet.Display_an_offline_map.cppUse dark colors for code blocks Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Graphic* box = new Graphic(offlineArea, new SimpleFillSymbol(SimpleFillSymbolStyle::Solid, Qt::transparent, new SimpleLineSymbol(SimpleLineSymbolStyle::Solid, Qt::red, 3, this), this), this); GraphicsOverlay* boxOverlay = new GraphicsOverlay(this); boxOverlay->graphics()->append(box); // add graphics overlay to the map view m_mapView->graphicsOverlays()->append(boxOverlay); // generate the offline map parameters m_offlineMapTask->createDefaultGenerateOfflineMapParametersAsync(offlineArea).then(this,[this](const GenerateOfflineMapParameters& params) { // output to generate offline map job after offline map parameters are created. Store the resulting mmpk in the desired path const QString outputPath = QDir::homePath() + "/ArcGIS/Runtime/Data/offlinemap.mmpk"; GenerateOfflineMapJob* generateJob = m_offlineMapTask->generateOfflineMap(params, outputPath); if (!generateJob) return;
-
Add a
connect
that monitors the status of theGenerateOfflineMapJob
and returns changes to status.Display_an_offline_map.cppUse dark colors for code blocks Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. // generate the offline map parameters m_offlineMapTask->createDefaultGenerateOfflineMapParametersAsync(offlineArea).then(this,[this](const GenerateOfflineMapParameters& params) { // output to generate offline map job after offline map parameters are created. Store the resulting mmpk in the desired path const QString outputPath = QDir::homePath() + "/ArcGIS/Runtime/Data/offlinemap.mmpk"; GenerateOfflineMapJob* generateJob = m_offlineMapTask->generateOfflineMap(params, outputPath); if (!generateJob) return; // use connect to monitor job status for changes and return job status connect(generateJob, &GenerateOfflineMapJob::statusChanged, this, [this, generateJob]() { if (generateJob->jobStatus() == JobStatus::Succeeded) { qDebug() << "generating offline map"; m_mapView->setMap(generateJob->result()->offlineMap(this)); qDebug() << (generateJob->error().isEmpty() ? "No errors" : (generateJob->error().message() + generateJob->error().additionalMessage())); } else if (generateJob->jobStatus() == JobStatus::Failed) { qWarning() << generateJob->error().message() << generateJob->error().additionalMessage(); } });
-
Add another
connect
(optional) that displays progress of theGenerateOfflineMapJob
as the job executes. Add the final codegenerate
and the final closing code (required) to complete the first connect function.Job->start() Display_an_offline_map.cppUse dark colors for code blocks Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. // use connect to monitor job status for changes and return job status connect(generateJob, &GenerateOfflineMapJob::statusChanged, this, [this, generateJob]() { if (generateJob->jobStatus() == JobStatus::Succeeded) { qDebug() << "generating offline map"; m_mapView->setMap(generateJob->result()->offlineMap(this)); qDebug() << (generateJob->error().isEmpty() ? "No errors" : (generateJob->error().message() + generateJob->error().additionalMessage())); } else if (generateJob->jobStatus() == JobStatus::Failed) { qWarning() << generateJob->error().message() << generateJob->error().additionalMessage(); } }); // use connect to monitor job progress changes and return progress return job progress connect(generateJob, &GenerateOfflineMapJob::progressChanged, this, [generateJob]() { qDebug() << "Job status:" << generateJob->progress() << "%"; }); generateJob->start(); });
-
Press Ctrl + R to run the app.
Initially, you should see the map of the stormwater network for Naperville, IL, USA, with a red outline as before. At the Application Output tab in Creator, the Job status
percentage should increment up to 100%, and then you should see the offline map for the specified area of the stormwater network for Naperville, IL, USA. Remove your network connection and you will still be able to use the mouse to drag, scroll, and double-click the map view to explore this offline map.
What's next?
Learn how to use additional API features, ArcGIS location services, and ArcGIS tools in these tutorials: