天気情報

Weather Info の例では、Qt Positioning を使用して、Qt Quick の C++ プラグインで、ユーザーの現在位置を使用して Web サービスからローカルコンテンツを取得する方法を示します。

この例で使用するQt Positioning の主要なクラスです:

例の実行

Qt Creator からサンプルを実行するには、Welcome モードを開き、Examples からサンプルを選択します。詳細については、Building and Running an Example を参照してください。

気象データ・プロバイダー

この例では、いくつかの無関係な気象データ・プロバイダーを使用しています:

使用するプロバイダは実行時に自動的に選択され、選択したプロバイダが利用できない場合は変更できる。ただし、手動で指定することはできません。

注意: すべてのプロバイダーで無料プランが使用され、天気予報のリクエスト量に一定の制限があります。制限を超えると、プロバイダーは一時的に利用できなくなります。すべてのプロバイダーが利用できなくなると、アプリケーションは天気情報を表示できなくなります。この場合、少なくとも1つのプロバイダーが再び利用可能になるまで待つ必要がある。

アプリケーションのデータモデル

この例の重要な部分は、WeatherDataAppModel クラスに含まれるアプリケーションのデータモデルです。WeatherData はHTTPサービスから取得した天気情報を表します。これは単純なデータクラスですが、後でQMLにうまく公開するためにQ_PROPERTY 。また、QML_ANONYMOUS マクロを使っているので、QMLで認識されます。

class WeatherData : public QObject {
    Q_OBJECT
    Q_PROPERTY(QString dayOfWeek
               READ dayOfWeek WRITE setDayOfWeek
               NOTIFY dataChanged)
    Q_PROPERTY(QString weatherIcon
               READ weatherIcon WRITE setWeatherIcon
               NOTIFY dataChanged)
    Q_PROPERTY(QString weatherDescription
               READ weatherDescription WRITE setWeatherDescription
               NOTIFY dataChanged)
    Q_PROPERTY(QString temperature
               READ temperature WRITE setTemperature
               NOTIFY dataChanged)
    QML_ANONYMOUS

public:
    explicit WeatherData(QObject *parent = 0);
    WeatherData(const WeatherData &other);
    WeatherData(const WeatherInfo &other);

    QString dayOfWeek() const;
    QString weatherIcon() const;
    QString weatherDescription() const;
    QString temperature() const;

    void setDayOfWeek(const QString &value);
    void setWeatherIcon(const QString &value);
    void setWeatherDescription(const QString &value);
    void setTemperature(const QString &value);

signals:
    void dataChanged();
};

AppModel はアプリケーション全体の状態をモデル化します。起動時に、 ()を使ってプラットフォームのデフォルトの位置ソースを取得します。QGeoPositionInfoSource::createDefaultSource

AppModel::AppModel(QObject *parent) :
        QObject(parent),
        d(new AppModelPrivate)
{
    d->src = QGeoPositionInfoSource::createDefaultSource(this);

    if (d->src) {
        d->useGps = true;
        connect(d->src, &QGeoPositionInfoSource::positionUpdated,
                this, &AppModel::positionUpdated);
        connect(d->src, &QGeoPositionInfoSource::errorOccurred,
                this, &AppModel::positionError);
#if QT_CONFIG(permissions)
        QLocationPermission permission;
        permission.setAccuracy(QLocationPermission::Precise);
        permission.setAvailability(QLocationPermission::WhenInUse);

        switch (qApp->checkPermission(permission)) {
        case Qt::PermissionStatus::Undetermined:
            qApp->requestPermission(permission, [this] (const QPermission& permission) {
                if (permission.status() == Qt::PermissionStatus::Granted)
                    d->src->startUpdates();
                else
                    positionError(QGeoPositionInfoSource::AccessError);
            });
            break;
        case Qt::PermissionStatus::Denied:
            qWarning("Location permission is denied");
            positionError(QGeoPositionInfoSource::AccessError);
            break;
        case Qt::PermissionStatus::Granted:
            d->src->startUpdates();
            break;
        }
#else
        d->src->startUpdates();
#endif
    } else {
        d->useGps = false;
        d->city = "Brisbane";
        emit cityChanged();
        requestWeatherByCity();
    }

    QTimer *refreshTimer = new QTimer(this);
    connect(refreshTimer, &QTimer::timeout, this, &AppModel::refreshWeather);
    using namespace std::chrono;
    refreshTimer->start(60s);
}

デフォルトのソースがない場合は、静的な位置を取得し、そのためのウェザーを取得します。しかし、位置ソースがある場合は、そのpositionUpdated() シグナルをAppModel のスロットに接続し、startUpdates() を呼び出します。これにより、デバイスの位置の定期的な更新が開始されます。

位置の更新を受信すると、返された座標の経度と緯度を使用して、指定された場所の気象データを取得します。

void AppModel::positionUpdated(QGeoPositionInfo gpsPos)
{
    d->coord = gpsPos.coordinate();

    if (!d->useGps)
        return;

    requestWeatherByCoordinates();
}

このプロセスをUIに通知するために、新しい都市が使用されるときはcityChanged() 、天候の更新が発生するときはweatherChanged() 、シグナルが発信される。

また、このモデルはQML_ELEMENT マクロを使用しており、QMLで利用できるようになっています。

class AppModel : public QObject
{
    Q_OBJECT
    Q_PROPERTY(bool ready
               READ ready
               NOTIFY readyChanged)
    Q_PROPERTY(bool hasSource
               READ hasSource
               NOTIFY readyChanged)
    Q_PROPERTY(bool hasValidCity
               READ hasValidCity
               NOTIFY cityChanged)
    Q_PROPERTY(bool hasValidWeather
               READ hasValidWeather
               NOTIFY weatherChanged)
    Q_PROPERTY(bool useGps
               READ useGps WRITE setUseGps
               NOTIFY useGpsChanged)
    Q_PROPERTY(QString city
               READ city WRITE setCity
               NOTIFY cityChanged)
    Q_PROPERTY(WeatherData *weather
               READ weather
               NOTIFY weatherChanged)
    Q_PROPERTY(QQmlListProperty<WeatherData> forecast
               READ forecast
               NOTIFY weatherChanged)
    QML_ELEMENT

public:
    explicit AppModel(QObject *parent = 0);
    ~AppModel();

    bool ready() const;
    bool hasSource() const;
    bool useGps() const;
    bool hasValidCity() const;
    bool hasValidWeather() const;
    void setUseGps(bool value);

    QString city() const;
    void setCity(const QString &value);

    WeatherData *weather() const;
    QQmlListProperty<WeatherData> forecast() const;

public slots:
    Q_INVOKABLE void refreshWeather();

signals:
    void readyChanged();
    void useGpsChanged();
    void cityChanged();
    void weatherChanged();
};

天気予報情報にはQQmlListProperty を使用しています。この情報には、今後数日間の天気予報が含まれています(日数はプロバイダによって異なります)。これにより、QMLから天気予報に簡単にアクセスできるようになります。

カスタムモデルをQMLに公開する

モデルをQMLのUIレイヤーに公開するために、QML_ELEMENTQML_ANONYMOUS マクロを使います。これらのマクロの詳細については、QQmlEngine クラスの説明を参照してください。

QMLで型を利用できるようにするためには、それに合わせてビルドを更新する必要があります。

CMakeビルド

CMakeベースのビルドを行うには、CMakeLists.txt

qt_add_qml_module(weatherinfo
    URI Weather
    VERSION 1.0
    SOURCES
        appmodel.cpp appmodel.h
        openmeteobackend.cpp openmeteobackend.h
        openweathermapbackend.cpp openweathermapbackend.h
        providerbackend.cpp providerbackend.h
        weatherapibackend.cpp weatherapibackend.h
    QML_FILES
        BigForecastIcon.qml
        ForecastIcon.qml
        WeatherIcon.qml
        WeatherInfo.qml
    RESOURCES
        icons/weather-few-clouds.svg
        icons/weather-fog.svg
        icons/weather-haze.svg
        icons/weather-icy.svg
        icons/weather-overcast.svg
        icons/weather-showers.svg
        icons/weather-sleet.svg
        icons/weather-snow.svg
        icons/weather-storm.svg
        icons/weather-sunny-very-few-clouds.svg
        icons/weather-sunny.svg
        icons/weather-thundershower.svg
        icons/weather-showers-scattered.svg
        icons/waypoint.svg
)
qmakeビルド

qmakeビルドの場合、weatherinfo.pro

CONFIG += qmltypes
QML_IMPORT_NAME = Weather
QML_IMPORT_MAJOR_VERSION = 1

qml_resources.files = \
    qmldir \
    BigForecastIcon.qml \
    ForecastIcon.qml \
    WeatherIcon.qml \
    WeatherInfo.qml \
    icons/weather-few-clouds.svg \
    icons/weather-fog.svg \
    icons/weather-haze.svg \
    icons/weather-icy.svg \
    icons/weather-overcast.svg \
    icons/weather-showers.svg \
    icons/weather-showers-scattered.svg \
    icons/weather-sleet.svg \
    icons/weather-snow.svg \
    icons/weather-storm.svg \
    icons/weather-sunny-very-few-clouds.svg \
    icons/weather-sunny.svg \
    icons/weather-thundershower.svg \
    icons/waypoint.svg

qml_resources.prefix = /qt/qml/Weather

RESOURCES += qml_resources

QMLでモデルをインスタンス化する

最後に、実際のQMLの中で、AppModel をインスタンス化します:

Window {
    id: window
    AppModel {
        id: appModel
        onReadyChanged: {
            if (appModel.ready)
                statesItem.state = "ready"
            else
                statesItem.state = "loading"
        }
    }
}

このようにモデルがインスタンス化されると、QMLドキュメントの他の場所でそのプロパティを使うことができます:

    BigForecastIcon {
        id: current
        Layout.fillWidth: true
        Layout.fillHeight: true

        weatherIcon: (appModel.hasValidWeather
                      ? appModel.weather.weatherIcon
                      : "sunny")
    }

プロジェクトの例 @ code.qt.io

例プロジェクト @ code.qt.io©2024 The Qt Company Ltd. 本書に含まれる文書の著作権は、それぞれの所有者に帰属します。 本書で提供されるドキュメントは、Free Software Foundation が発行したGNU Free Documentation License version 1.3に基づいてライセンスされています。 Qtおよびそれぞれのロゴは、フィンランドおよびその他の国におけるThe Qt Company Ltd.の 商標です。その他すべての商標は、それぞれの所有者に帰属します。