このページでは

C

Qt Quick Ultraliteマップの例

Qt Quick Ultralite で、Map アイテムを使用して地図を表示する方法を示します。

概要

このサンプルでは、Map アイテムを使用して、Qt Quick Ultraliteアプリケーションに地図を表示する方法を示します。

最小限のマップモード

このモードでは、4つのズームレベル(0~3)に対応したマップタイルが用意されています。ズームインするには「さらに 」ボタンを、ズームアウトするには「マイナス 」ボタンを選択してください。どのズームレベルでも、マップを時計回りに回転させるには「右に回転 」ボタンを、反時計回りに回転させるには「左に回転 」ボタンを選択してください。 また、地図をドラッグして画面内を移動することもできます。

フィンランドのオウル市を表示した地図ビューの例。ズームや回転の操作ボタンが含まれています。

ユーザー位置デモモード

デモモードでは、あらかじめ定義されたルートに沿って、地図上のユーザーの現在位置の変化をシミュレートします。デモモードを開始するには、「履歴書の冒頭 」ボタンを選択してください。デモモードでは、「一時停止 」ボタンと「停止 」ボタン以外のすべてのボタンが非表示になります。

ナビゲーション矢印と位置マーカー、および一時停止・停止の操作ボタンが表示された地図の例。

デモは、地図がズームレベル17まで拡大された状態から開始されます。ユーザーの現在位置を表す「ナビゲーション矢印 」アイコンと、注目地点を表す「位置マーカー 」アイコンが地図上に表示されます。 デモを一時停止するには、「一時停止 」ボタンを選択してください。ボタンが「履歴書の冒頭 」ボタンに変わります。デモが一時停止している間は、地図をドラッグして画面を移動させることができます。デモを再開するには、「履歴書の冒頭 」を選択してください。デモを停止して最小限の地図モードに戻すには、「停止 」ボタンを選択してください。

このサンプルでは、ファイルシステムからマップタイルを取得するためにQul::MapTileFetcher を実装しています。ファイルシステムの実装は、fileloadingサンプルから提供されています。マップタイルはJPEG 形式で保存されており、JPEG デコーダが必要です。JPEGデコーダの実装は、imagedecoderサンプルから提供されています。詳細については、「マップタイルの取得」を参照してください。

このサンプルでは、Qul::GeoPositionSource を実装し、ダミーの位置情報ソースから位置情報を取得しています。詳細については、「位置情報の取得」を参照してください。

対象プラットフォーム

デスクトップでのサンプル実行

このサンプルでは、Qt を使用して画像をデコードする「imagedecoder」サンプルの JPEG デコーダ実装を使用しています。そのため、ヘッダーファイルを提供するために、プロジェクトのビルドには開発用 Qt が必要です。

cmake examples/map -DCMAKE_PREFIX_PATH=$HOME/Qt/6.2.4/gcc_64 -DQUL_PLATFORM=Qt -DQul_ROOT=${QUL_ROOT}
cmake examples\map -DCMAKE_PREFIX_PATH=C:\Qt\6.2.4\msvc2022_64 -DQUL_COMPILER_NAME=msvc -DQUL_PLATFORM=Qt -DQul_ROOT=%QUL_ROOT%

プラットフォームバックエンドがリンクされているQtのバージョンに関するリンクの問題を回避するには、両者のバージョンを一致させる必要があります。カスタムビルドのプラットフォームの場合は、デスクトッププラットフォームバックエンドのビルドに使用したのと同じQtを使用してください。あらかじめビルド済みのプラットフォームライブラリの場合は、Qt 6.2.4を使用する必要があります。

注: MinGWを使用する場合は 、コンパイラ名として「gnu 」を、CMAKE_PREFIX_PATH として「C:\Qt\6.2.4\mingw_64」を指定してください。

注: Linuxでは 、Qt は OpenGL に依存しています。例のコンフィギュレーション中に OpenGL が見つからないというエラーが発生した場合は、次のコマンドを使用してインストールできます。

sudo apt install libgl1-mesa-dev

デバイス上でサンプルを実行する

ターゲットプラットフォームでサンプルを実行するには、FAT32 形式でフォーマットされたSD カードが必要です。サンプルディレクトリ内のoffline_tiles_provider/ にあるtiles/ ディレクトリを、SD カードのルートディレクトリにコピーしてください。

ハードウェア要件

優れたパフォーマンス、高いフレームレート、スムーズなユーザー体験を実現するには、画像の高速デコードおよび高速回転をサポートするデバイスが不可欠です。

RAM の要件は、マップのサイズによって異なります。 画面サイズが 800 x 480 のSTM32F769iデバイスでフルスクリーン表示を行う場合、heap およびstack メモリを 32 KB 消費します。同じ画面サイズの場合、マップタイル画像のキャッシュ用に 3840 KB のSDRAM メモリが必要です。詳細については、「画像のキャッシュ」を参照してください。

マップタイル

このサンプルには、Web Mercator投影法による世界地図のタイルが 5 つのズームレベル分含まれています。各タイルは、JPEG 形式の 256 × 256 ピクセルの画像です。各ズームレベルにおけるタイルの数は、2zoomlevel×2zoomlevel の計算式を用いて算出されます。

地図タイルは、サンプルディレクトリ内のoffline_tiles_provider/tiles/ ディレクトリにあります。

地図タイルの取得(テクノロジープレビュー)

このサンプルでは、オフラインの外部ストレージからマップタイルを取得します。

OfflineTileFetcher クラス

OfflineTileFetcher クラスは、Qul::MapTileFetcher クラスのリファレンス実装です。実装内容は、offline_tile_provider/offlinetilefetcher.h およびoffline_tile_provider/offlinetilefetcher.cpp ファイルに記載されています。

Qul::MapTileFetcher クラスには、実装が必須のQul::MapTileFetcher::getTileImage 関数があります。OfflineTileFetcher クラスでは、これを次のように実装しています:

bool OfflineTileFetcher::getTileImage(const Qul::Private::TileSpec &spec, Qul::Private::TileImage &tileImage)
{
    // user has to configure url to point to tiles images root dir.
    QulString url = generateTileUrl(TILES_BASE_DIR, spec);
    if (url.empty()) {
        url = PLACEHOLDER_TILE;
        Qul::PlatformInterface::log("warning: tile url is empty. using placeholder tile at '%s'.\n", PLACEHOLDER_TILE);
    }

    const TileCacheMap::iterator it = tileCache.find(url);
    if (it != tileCache.end()) {
        tileImage.image = it->second;
        return true;
    }

    if (tileCache.size() >= maxCacheSize)
        removeOldestImage();

    Qul::SharedImage newTileImage = findImage(url.c_str());
    if (!newTileImage && url != PLACEHOLDER_TILE) {
#ifndef NDEBUG
        Qul::PlatformInterface::log("warning: could not fetch a tile with url '%s'. using placeholder tile.\n",
                                    url.c_str());
#endif

        newTileImage = findImage(PLACEHOLDER_TILE);

        if (!newTileImage) {
            Qul::PlatformInterface::log("error: could not fetch a placeholder tile from '%s'.\n", PLACEHOLDER_TILE);
            return false;
        }
    } else if (!newTileImage) {
        Qul::PlatformInterface::log("error: could not fetch a placeholder tile from '%s'.\n", PLACEHOLDER_TILE);
        return false;
    }

    tileImage.image = newTileImage;
    tileCache[url] = newTileImage;
    cacheOrder.push_back(url);

    return true;
}

OfflineTileFetcher クラスは、メンバー関数generateTileUrl を実装し、spec パラメータと、例のCMakeLists.txt ファイルで定義されたTILES_BASE_DIR を使用して、マップタイルのURI を構成します。

static int printTileSpec(char *buffer, int size, const char *baseDir, const Qul::Private::TileSpec &spec)
{
    return std::snprintf(buffer, size, "%s%u/%u/%u.jpeg", baseDir, spec.zoom, spec.x, spec.y);
}

OfflineTileFetcher::QulString OfflineTileFetcher::generateTileUrl(const char *baseDir,
                                                                  const Qul::Private::TileSpec &spec) const
{
    const int size = printTileSpec(nullptr, 0, baseDir, spec);
    if (size <= 0) {
        Qul::PlatformInterface::log("error: failed to calculate the required buffer size for the tile url.");
        return QulString();
    }

    QulString url;
    url.resize(size + 1);

    // The generated string has a length of at most n-1, leaving space for the
    // additional terminating null character.
    printTileSpec(&url[0], url.size(), baseDir, spec);
    url.resize(size);

    return url;
}

OfflineTileFetcher クラスは、FileCache::get を使用して、マップタイル画像にアクセスし、デコードを行い、デコード済みの画像をRAMにキャッシュします。FileCache::get は、Qul::SharedImage オブジェクトを返します。

Qul::SharedImage OfflineTileFetcher::findImage(const char *url)
{
    if (m_fileCache)
        return m_fileCache->get(url);

    return Qul::Private::findImageForString(url);
}

OfflineTileFetcher すでにアクセス済みのマップタイルを格納するためのキャッシュ機能を実装しています。


...
tileCache[url] = newTileImage;
...

アクセス済みのマップタイルをキャッシュする際、Qul::SharedImage への参照を保持し、RAMキャッシュ内にそのタイルが見つかった場合は、すでにデコード済みのタイル画像を返します。


...
const TileCacheMap::iterator it = tileCache.find(url);
if (it != tileCache.end()) {
    tileImage.image = it->second;
    return true;
}
...

OfflineTileFetcher CMakeLists.txt で定義されている を使用して を設定し、その後、最も古いキャッシュエントリが削除されます。MAX_CACHE_SIZE maxCacheSize

OfflineTileFetcher::OfflineTileFetcher(bool useFileCache)
    ...
    , maxCacheSize(MAX_CACHE_SIZE)
{}

void OfflineTileFetcher::removeOldestImage()
{
    for (int i = 0; i < MAX_CACHE_SIZE / 5 && !cacheOrder.empty(); ++i) {
        const QulString oldestUrl = cacheOrder.front();
        cacheOrder.pop_front();
        tileCache.erase(oldestUrl);
    }
}

位置情報の取得(テクノロジープレビュー)

この例では、ダミーの位置情報ソースから位置情報を取得する処理をシミュレートしています。

DummyPositionSource クラス

DummyPositionSource クラスは、Qul::GeoPositionSource クラスのリファレンス実装です。この実装は、dummy_position_source/dummypositionsource.h およびdummy_position_source/dummypositionsource.cpp ファイルに記載されています。

Qul::GeoPositionSource クラスには、実装が必須のQul::GeoPositionSource::getCurrentPosition 関数があります。DummyPositionSource クラスでは、これを次のように実装しています:

Qul::Private::PositionSource::SourceError DummyPositionSource::getCurrentPosition(Qul::GeoPositionInfo &positionInfo)
{
    const size_t lastIndex = dataSource.size() - 1;
    IndexManager &indexManager = IndexManager::instance();
    Qul::GeoPositionInfo posInfo = dataSource[indexManager.getIndex()];

    positionInfo.latitude = posInfo.latitude;
    positionInfo.longitude = posInfo.longitude;
    positionInfo.direction = posInfo.direction;
    positionInfo.speed = posInfo.speed;
    positionInfo.timestamp = posInfo.timestamp;

    if (indexManager.getIndex() == lastIndex)
        return Qul::Private::PositionSource::ClosedError;

    indexManager.incrementIndex();

    return Qul::Private::PositionSource::NoError;
}

DummyPositionSource::getCurrentPosition この関数は、dataSource ベクトルからシミュレーションされた位置データにアクセスします。dataSource ベクトルの定義は、dummy_position_source/dummypositiondata.cpp 内にあります。

extern const std::vector<Qul::GeoPositionInfo, Qul::PlatformInterface::Allocator<Qul::GeoPositionInfo> > dataSource
    = {{65.05877, 25.45545, 270, 0.000000, 1754406549865},
       {65.05877, 25.455422549019605, 270, 1.287166, 1754406550864},
       {65.05877, 25.455395098039215, 270, 1.287166, 1754406551866},
        ...

{65.0542974509804, 25.456510980392157, 248.6951536973353, 0.660902, 1754407107864},
{65.05427156862746, 25.45636862745098, 248.6951535146238, 7.269921, 1754407108858},
{65.05427078431373, 25.45636431372549, 248.6951535146238, 0.220301, 1754407109868},
{65.05427, 25.45636, 248.6951535146238, 0.220301, 1754407110869}};

C++およびQMLからdataSource 内のどの位置データエントリにアクセスするかを制御するため、IndexManager クラスはdummy_position_source/indexmanager.h に実装されています。

class IndexManager : public Qul::Singleton<IndexManager>
{
public:
    IndexManager()
        : m_index(0){};

    void setIndex(size_t i) { m_index = i; }
    size_t getIndex() const { return m_index; }
    void incrementIndex() { m_index++; }

private:
    size_t m_index;
};

DummyPositionSource::getCurrentPosition この関数は、現在の位置の更新を停止するために最後の位置データエントリに到達した際に、CloseError を返します。それ以外の場合は、PositionSource から呼び出された際に、updateInterval プロパティの値に従って現在の位置の更新を継続するために、NoError を返します。

プロジェクトの構造

CMakeプロジェクトファイル

CMakeLists.txt には、デスクトップおよびSTM32F769iプラットフォームの両方に対する設定が含まれています。

CMakeのコンパイル定義
  • TILES_BASE_DIR これは、マップタイルが格納されているルートディレクトリを指しています。
  • PLACEHOLDER_TILE ユーザーが生成されたマップ領域の外側にパンした場合に表示されるプレースホルダー画像を指します。
  • MAX_CACHE_SIZE 古いキャッシュエントリが削除されるまでの期間を設定します。
デスクトップの設定

デスクトップの設定は、マップタイルの画像にアクセスするためのファイル読み込みサンプルにおけるPOSIX ファイルシステムの実装と、マップタイルの画像をデコードするための画像デコーダサンプルにおけるJPEG 画像デコーダの実装に依存します。

target_sources(map PRIVATE
...
                      ../imagedecoder/desktop/desktopimagedecoder.cpp
                      ../fileloading/posix/posixfilesystem.cpp
                  )
STM32F769iの設定

プラットフォームの設定は、SD カード内のマップタイルの画像にアクセスするためのfileloadingサンプルのFATFS ファイルシステム実装と、マップタイルの画像をデコードするためのimagedecoderサンプルのハードウェアJPEG イメージデコーダに依存します。

# file system sources
target_sources(map PRIVATE
        ../fileloading/3rdparty/FatFs/src/diskio.c
        ../fileloading/3rdparty/FatFs/src/ff.c
        ../fileloading/3rdparty/FatFs/src/ff_gen_drv.c
        ../fileloading/3rdparty/FatFs/src/sd_diskio.c
        ../fileloading/3rdparty/FatFs/src/option/unicode.c
        ${QUL_BOARD_SDK_DIR}/Drivers/STM32F7xx_HAL_Driver/Src/stm32f7xx_ll_sdmmc.c
        ${QUL_BOARD_SDK_DIR}/Drivers/STM32F7xx_HAL_Driver/Src/stm32f7xx_hal_sd.c
        ${QUL_BOARD_SDK_DIR}/Drivers/BSP/STM32F769I-Discovery/stm32f769i_discovery_sd.c
    )
# jpeg decoder sources
target_sources(map PRIVATE
        ${QUL_BOARD_SDK_DIR}/Drivers/STM32F7xx_HAL_Driver/Src/stm32f7xx_hal_jpeg.c
        ../imagedecoder/stm/${STM32XX}/stm32f7xx_hal_msp.c
        ../imagedecoder/stm/${STM32XX}/buffer_config.cpp
        ../imagedecoder/stm/stmimagedecoder.cpp
        ../imagedecoder/common/jpeg.cpp
        ../imagedecoder/3rdparty/stm/Utilities/JPEG/jpeg_utils.c
    )
QmlProjectファイル

サンプル QmlProject ファイルには、必要な QML ファイル、画像ファイル、インターフェースファイル、およびQt Quick Ultralite モジュールが記載されています。また、MCU.Config.maxResourceCacheSize を、ターゲットプラットフォームで動作する値に設定しています。

// Copyright (C) 2026 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial

import QmlProject

Project {
    mainFile: "map.qml"

    QmlFiles {
        files: [
            "MapButton.qml",
            "MapContainer.qml",
            "MapParameters.qml",
            "MapMarker.qml",
            "CopyrightText.qml"
        ]
    }

    ModuleFiles {
        MCU.qulModules: ["Positioning", "Location"]
    }

    InterfaceFiles {
        files: [
            "dummy_position_source/indexmanager.h"
        ]
    }

    MCU.Config {
        maxResourceCacheSize: 4000000
    }

    ImageFiles {
        MCU.base: "icons/24px"
        files: [
            "icons/24px/plus.png",
            "icons/24px/minus.png",
            "icons/24px/rotate-right.png",
            "icons/24px/rotate-left.png",
            "icons/24px/nav-arrow.png",
            "icons/24px/location-marker.png",
            "icons/24px/start-resume.png",
            "icons/24px/pause.png",
            "icons/24px/stop.png"
        ]
    }
}
MapContainer.qml

メインのQMLファイルでは、Map アイテムを使用し、マップのcenter をフィンランドのオウル市に設定しています。また、マップの初期zoomLevel を3、minimumZoomLevel を0、maximumZoomLevel を3に設定しています。

    Map {
        id: map
        property bool panning: false

        anchors.fill: parent
        center: mapParameters.startPosition
        bearing: mapParameters.bearing
        zoomLevel: root.zoomLevel
        minimumZoomLevel: mapParameters.minimumZoomLevel
        maximumZoomLevel: mapParameters.maximumZoomLevel
...

これは、pan 関数のdeltaX およびdeltaY パラメータの計算を担当するMouseArea を定義します。

        MouseArea {
            id: mapPan

            anchors.fill: parent

            property real pressPointX: 0
            property real pressPointY: 0
            property real translationX: 0
            property real translationY: 0

            onPressed: {
                map.panning = true
                pressPointX = mouse.x
                pressPointY = mouse.y
                translationX = 0
                translationY = 0
            }
            onReleased: {
                map.panning = false
            }
            onPositionChanged: {
                var x = mouse.x - pressPointX
                var y = mouse.y - pressPointY

                var deltaX = x - translationX
                var deltaY = y - translationY
                translationX = x
                translationY = y

                map.pan(-deltaX, -deltaY)
            }
        }
MapParameters.qml

Map 項目のデフォルトパラメータを定義します。


...
    readonly property real zoomLevel: 3
    readonly property real minimumZoomLevel: 0
    readonly property real maximumZoomLevel: 3
    readonly property real bearing: 0
    readonly property geoCoordinate startPosition: QtPositioning.coordinate(65.05877, 25.45545)
...
MapMarker.qml

MapMarker.qml これはカスタムQML型です。地図上の注目地点マーカーを表すMapQuickItem アイテムをラップしています。

// Copyright (C) 2025 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial
import QtQuick
import QtLocation
import QtPositioning

MapQuickItem {
    id: root

    property alias markerText: markerText.text
    property alias imageSource: markerImage.source

    sourceItem: Image {
        id: markerImage
        source: ""

        Text {
            id: markerText
            text: ""
            font.pointSize: 7
            font.bold: true
            anchors.bottom: parent.top
            anchors.horizontalCenter: parent.horizontalCenter
        }
    }

    coordinate: QtPositioning.coordinate(0, 0)

    anchorPoint: Qt.point(sourceItem.width / 2, sourceItem.height / 2)
}

ファイル:

画像:

特定の Qt ライセンスの下で利用可能です。
詳細はこちら。