C++でQML拡張モジュールを書く

この Qt QmlモジュールはC++によるQML拡張のためのAPI群を提供します。独自の QML 型を追加したり、既存の Qt 型を拡張したり、通常の QML コードからはアクセスできない C/C++ 関数を呼び出したりするための拡張モジュールを書くことができます。

このチュートリアルでは、プロパティ、シグナル、バインディングといった QML のコア機能を含む QML 拡張モジュールを C++ で書く方法を紹介します。また、プラグインを使った拡張機能の実装方法についても説明します。

このチュートリアルで扱う多くのトピックについては、「概要 - QMLとC++の統合」とそのドキュメントのサブトピックでさらに詳しく説明しています。特に、「C++クラスの属性をQMLに公開する」、「C++からQMLの型を定義する」というサブトピックに興味があるかもしれません。

チュートリアルのソースを開く

このチュートリアルのコードは Qt のソースの一部として提供されています。Qt をQt Online Installer でインストールした場合は、Qt のインストールディレクトリの Examples/Qt-6.8.2/qml/tutorials/extending-qml/ にソースがあります。

ゼロからプロジェクトを作成する

別の方法として、チュートリアルに沿ってソースをゼロから作成することもできます:各章ごとに、Qt CreatorQt Quick Applicationテンプレートを使って、Qt Creator の指示に従って新しいプロジェクトを作成してください: Qt Quick プロジェクトを作成する。そして、生成されたスケルトン・コードを適応し、拡張することで、チュートリアルに沿って進んでください。

第1章 新しい型の作成

extending-qml/chapter1-basics

QMLを拡張する際によくある作業は、組み込みの Qt Quick types.例えば、特定のデータモデルを実装したり、独自の描画機能を持った型を提供したり、 組み込みのQML機能ではアクセスできないネットワークプログラミングのような システム機能にアクセスしたりすることです。

このチュートリアルでは、Qt Quick モジュールの C++ クラスを使って QML を拡張する方法を紹介します。最終的には、バインディングやシグナルのようなQMLの機能を使って、いくつかのカ スタムQMLタイプを接続し、プラグインを通してQMLランタイムから利用できる ようにすることで、シンプルな円グラフ表示を実現します。

まず始めに、名前と色の2つのプロパティを持つ "PieChart "という新しいQML型を作成しましょう。この型は "Charts "というインポート可能な名前空間で、バージョンは1.0です。

このPieChart 型をQMLからこのように使えるようにしたい:

import Charts

PieChart {
    width: 100; height: 100
    name: "A simple pie chart"
    color: "red"
}

そのためには、このPieChart 型とそのプロパティをカプセル化したC++クラスが必要です。QMLはQtのメタオブジェクトシステムを多用しているので、この新しいクラスは次のようなものでなければなりません:

  • を継承する必要があります。QObject
  • Q_PROPERTY マクロを使ってプロパティを宣言します。

クラスの宣言

以下はpiechart.h で定義されたPieChart クラスです:

#include <QtQuick/QQuickPaintedItem>
#include <QColor>

class PieChart : public QQuickPaintedItem
{
    Q_OBJECT
    Q_PROPERTY(QString name READ name WRITE setName FINAL)
    Q_PROPERTY(QColor color READ color WRITE setColor FINAL)
    QML_ELEMENT

public:
    PieChart(QQuickItem *parent = nullptr);

    QString name() const;
    void setName(const QString &name);

    QColor color() const;
    void setColor(const QColor &color);

    void paint(QPainter *painter) override;

private:
    QString m_name;
    QColor m_color;
};

このクラスがQQuickPaintedItem を継承しているのは、QQuickPaintedItem::paint() をオーバーライドしてQPainter API で描画操作を実行したいからです。このクラスが単にデータ型を表すだけで、実際に表示する必要のある項目でない場合は、QObject を継承するだけでよい。あるいは、既存のQObject ベースのクラスの機能を拡張したい場合は、代わりにそのクラスを継承することもできます。また、QPainter APIで描画操作を行う必要のないビジュアル・アイテムを作成したい場合は、QQuickItem をサブクラス化すればよいでしょう。

PieChart クラスはQ_PROPERTY マクロでnamecolor の 2 つのプロパティを定義し、QQuickPaintedItem::paint() をオーバーライドします。PieChart クラスはQML_ELEMENT マクロを使って登録し、QML から利用できるようにします。クラスを登録しないと、App.qmlPieChart を作成することができません。

qmake セットアップ

登録を有効にするには、プロジェクトファイルのCONFIGqmltypes オプションを追加し、QML_IMPORT_NAMEQML_IMPORT_MAJOR_VERSION を指定します:

CONFIG += qmltypes
QML_IMPORT_NAME = Charts
QML_IMPORT_MAJOR_VERSION = 1

CMakeセットアップ

同様に、CMakeを使用して登録を有効にするには、qt_add_qml_moduleコマンドを使用します:

qt_add_qml_module(chapter1-basics
    URI Charts
    QML_FILES App.qml
    DEPENDENCIES QtQuick
)

クラスの実装

piechart.cpp のクラス実装は、m_namem_color の値を適切に設定し、返すだけです。また、paint() を実装し、単純な円グラフを描画します:

PieChart::PieChart(QQuickItem *parent)
    : QQuickPaintedItem(parent)
{
}
...
void PieChart::paint(QPainter *painter)
{
    QPen pen(m_color, 2);
    painter->setPen(pen);
    painter->setRenderHints(QPainter::Antialiasing, true);
    painter->drawPie(boundingRect().adjusted(1, 1, -1, -1), 90 * 16, 290 * 16);
}

QMLの使い方

さて、PieChart の型を定義したので、QMLから使ってみましょう。App.qml ファイルはPieChart アイテムを作成し、標準的な QMLText アイテムを用いて円グラフの詳細を表示します:

import Charts
import QtQuick

Item {
    width: 300; height: 200

    PieChart {
        id: aPieChart
        anchors.centerIn: parent
        width: 100; height: 100
        name: "A simple pie chart"
        color: "red"
    }

    Text {
        anchors { bottom: parent.bottom; horizontalCenter: parent.horizontalCenter; bottomMargin: 20 }
        text: aPieChart.name
    }
}

QML では色は文字列として指定されますが、PieChartcolor プロパティでは自動的にQColor オブジェクトに変換されることに注意してください。自動変換は他の様々な値型に対しても提供されています。例えば、"640x480 "のような文字列は自動的にQSize

また、QQuickView を使用して、App.qml を実行し表示する C++ アプリケーションも作成します。

以下はそのアプリケーションmain.cpp

#include "piechart.h"
#include <QtQuick/QQuickView>
#include <QGuiApplication>

int main(int argc, char *argv[])
{
    QGuiApplication app(argc, argv);

    QQuickView view;
    view.setResizeMode(QQuickView::SizeRootObjectToView);
    view.loadFromModule("Charts", "App");
    view.show();
    return QGuiApplication::exec();
}

プロジェクトのビルド

プロジェクトをビルドするために、ファイルをインクルードし、ライブラリをリンクし、 QML に公開されるすべての型に対してバージョン 1.0 の "Charts "という名前空間を定義します。

qmakeを使用します:

QT += qml quick

CONFIG += qmltypes
QML_IMPORT_NAME = Charts
QML_IMPORT_MAJOR_VERSION = 1

HEADERS += piechart.h
SOURCES += piechart.cpp \
           main.cpp

RESOURCES += chapter1-basics.qrc

DESTPATH = $$[QT_INSTALL_EXAMPLES]/qml/tutorials/extending-qml/chapter1-basics
target.path = $$DESTPATH
INSTALLS += target

CMakeを使う:

# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause

cmake_minimum_required(VERSION 3.16)
project(chapter1-basics LANGUAGES CXX)

find_package(Qt6 REQUIRED COMPONENTS Core Gui Qml Quick)

qt_standard_project_setup(REQUIRES 6.8)

qt_add_executable(chapter1-basics
    main.cpp
    piechart.cpp piechart.h
)

set_target_properties(chapter1-basics PROPERTIES
    WIN32_EXECUTABLE TRUE
    MACOSX_BUNDLE TRUE
)

target_link_libraries(chapter1-basics PUBLIC
    Qt6::Core
    Qt6::Gui
    Qt6::Qml
    Qt6::Quick
)
qt_add_qml_module(chapter1-basics
    URI Charts
    QML_FILES App.qml
    DEPENDENCIES QtQuick
)
install(TARGETS chapter1-basics
    BUNDLE  DESTINATION .
    RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
    LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
)

qt_generate_deploy_qml_app_script(
    TARGET chapter1-basics
    OUTPUT_SCRIPT deploy_script
    MACOS_BUNDLE_POST_BUILD
    NO_UNSUPPORTED_PLATFORM_ERROR
    DEPLOY_USER_QML_MODULES_ON_UNSUPPORTED_PLATFORM
)
install(SCRIPT ${deploy_script})

これで、アプリケーションのビルドと実行ができるようになりました:

Note: 警告が表示されるかもしれませんExpression ... depends on non-NOTIFYable properties:PieChart::name.これは、書き込み可能なname プロパティにバインディングを追加しているにもかかわらず、それに対するnotifyシグナルを定義していないために起こります。そのため、name の値が変更されても、QMLエンジンはバインディングを更新することができません。これについては次の章で説明します。

第2章 C++メソッドとシグナルの接続

extending-qml/chapter2-methods

PieChart に "clearChart() "メソッドを持たせてチャートを消去し、"chartCleared "シグナルを発するようにしたいとします。App.qml はこのようにclearChart() を呼び出し、chartCleared() シグナルを受け取ることができる:

import Charts
import QtQuick

Item {
    width: 300; height: 200

    PieChart {
        id: aPieChart
        anchors.centerIn: parent
        width: 100; height: 100
        color: "red"

        onChartCleared: console.log("The chart has been cleared")
    }

    MouseArea {
        anchors.fill: parent
        onClicked: aPieChart.clearChart()
    }

    Text {
        anchors { bottom: parent.bottom; horizontalCenter: parent.horizontalCenter; bottomMargin: 20 }
        text: "Click anywhere to clear the chart"
    }
}

そのために、C++クラスにclearChart() メソッドとchartCleared() シグナルを追加する:

class PieChart : public QQuickPaintedItem
{
    ...
public:
    ...
    Q_INVOKABLE void clearChart();

signals:
    void chartCleared();
    ...
};

Q_INVOKABLE を使うことで、clearChart() メソッドが Qt Meta-Object システム、ひいては QML から利用できるようになります。

注: Q_INVOKABLE を使う代わりに、メソッドを Qt スロットとして宣言することもできます。なぜなら、public および protected スロットも QML から呼び出すことができるからです(private スロットは呼び出すことができません)。

clearChart() メソッドは色をQt::transparent に変え、チャートを再描画し、chartCleared() シグナルを発信します:

void PieChart::clearChart()
{
    setColor(QColor(Qt::transparent));
    update();

    emit chartCleared();
}

これでアプリケーションを実行し、ウィンドウをクリックすると、円グラフが消え、 アプリケーションが出力されます:

qml: The chart has been cleared

第3章:プロパティ・バインディングの追加

extending-qml/chapter3-bindings

プロパティ・バインディングはQMLの強力な機能で、異なる型の値を自動的に同期させることができます。プロパティの値が変更されると、シグナルを使って他の型の値を通知し、更新します。

color プロパティのプロパティ・バインディングを有効にしてみましょう。つまり、次のようなコードがあるとする:

import Charts
import QtQuick

Item {
    width: 300; height: 200

    Row {
        anchors.centerIn: parent
        spacing: 20

        PieChart {
            id: chartA
            width: 100; height: 100
            color: "red"
        }

        PieChart {
            id: chartB
            width: 100; height: 100
            color: chartA.color
        }
    }

    MouseArea {
        anchors.fill: parent
        onClicked: { chartA.color = "blue" }
    }

    Text {
        anchors { bottom: parent.bottom; horizontalCenter: parent.horizontalCenter; bottomMargin: 20 }
        text: "Click anywhere to change the chart color"
    }
}

color: chartA.color」ステートメントは、chartBcolor 値をchartAcolor にバインドします。chartAcolor 値が変更されるたびに、chartBcolor 値も同じ値に更新されます。ウィンドウがクリックされると、MouseAreaonClicked ハンドラーがchartA の色を変更し、両方のグラフを青に変更します。

color プロパティのプロパティ・バインディングを有効にするのは簡単です。Q_PROPERTY ()宣言にNOTIFY機能を追加し、値が変更されるたびに "colorChanged "シグナルが発信されることを示す。

class PieChart : public QQuickPaintedItem
{
    ...
    Q_PROPERTY(QColor color READ color WRITE setColor NOTIFY colorChanged FINAL)
public:
    ...
signals:
    void colorChanged();
    ...
};

そして、このシグナルをsetColor()

void PieChart::setColor(const QColor &color)
{
    if (color != m_color) {
        m_color = color;
        update();   // repaint with the new color
        emit colorChanged();
    }
}

colorChanged() を発する前に、setColor() で、色の値が実際に変わったかどうかをチェックすることが重要である。こうすることで、シグナルが不必要に発せられないようにし、また他の型が値の変更に反応する際のループを防ぐことができる。

バインディングの使用はQMLにとって不可欠です。NOTIFYシグナルが実装できるのであれば、プロパティにNOTIFYシグナルを追加し、バインディングで使用できるようにする必要があります。バインディングできないプロパティは自動的に更新することができず、 QMLで柔軟に使用することができません。また、バインディングはQMLを使用する上で非常に頻繁に呼び出され、頼りにされ るものであるため、バインディングが実装されていない場合、カスタムQML型を使用する ユーザは予期せぬ動作をする可能性があります。

第4章 カスタムプロパティ型の使用

extending-qml/chapter4-customPropertyTypes

PieChart 型は現在、文字列型のプロパティと色型のプロパティを持っています。他にも多くのタイプのプロパティを持つことができます。例えば、各チャートの識別子を格納するint型プロパティを持つこともできる:

// C++
class PieChart : public QQuickPaintedItem
{
    Q_PROPERTY(int chartId READ chartId WRITE setChartId NOTIFY chartIdChanged)
    ...

public:
    void setChartId(int chartId);
    int chartId() const;
    ...

signals:
    void chartIdChanged();
};

// QML
PieChart {
    ...
    chartId: 100
}

int 以外にも、様々なプロパティ・タイプを使うことができます。QColor,QSize,QRect のような Qt のデータ型の多くは、QML から自動的にサポートされます。(完全なリストはQMLとC++間のデータ型変換のドキュメントを参照してください)。

QMLがデフォルトでサポートしていない型のプロパティを作成したい場合は、その型をQMLエンジンに登録する必要があります。

例えば、property を "PieSlice "というcolor プロパティを持つ型に置き換えてみましょう。色を代入する代わりに、PieSlice の値を代入します。この値自体にcolor が含まれています:

import Charts
import QtQuick

Item {
    width: 300; height: 200

    PieChart {
        id: chart
        anchors.centerIn: parent
        width: 100; height: 100

        pieSlice: PieSlice {
            anchors.fill: parent
            color: "red"
        }
    }

    Component.onCompleted: console.log("The pie is colored " + chart.pieSlice.color)
}

PieChart のように、この新しいPieSlice タイプはQQuickPaintedItem を継承し、Q_PROPERTY() でプロパティを宣言します:

class PieSlice : public QQuickPaintedItem
{
    Q_OBJECT
    Q_PROPERTY(QColor color READ color WRITE setColor FINAL)
    QML_ELEMENT

public:
    PieSlice(QQuickItem *parent = nullptr);

    QColor color() const;
    void setColor(const QColor &color);

    void paint(QPainter *painter) override;

private:
    QColor m_color;
};

これをPieChart で使用するには、color のプロパティ宣言と関連するメソッドのシグネチャを修正する:

class PieChart : public QQuickItem
{
    Q_OBJECT
    Q_PROPERTY(PieSlice* pieSlice READ pieSlice WRITE setPieSlice FINAL)
    ...
public:
    ...
    PieSlice *pieSlice() const;
    void setPieSlice(PieSlice *pieSlice);
    ...
};

setPieSlice() を実装する際に注意しなければならないことがあります。PieSlice はビジュアル・アイテムなので、QQuickItem::setParentItem() を使ってPieChart の子アイテムとして設定し、PieChart がこの子アイテムの内容を描画するときにペイントすることを認識できるようにする必要があります:

void PieChart::setPieSlice(PieSlice *pieSlice)
{
    m_pieSlice = pieSlice;
    pieSlice->setParentItem(this);
}

PieChart 型と同様に、PieSlice 型もQML_ELEMENT を使って QML にエクスポストする必要があります。

class PieSlice : public QQuickPaintedItem
{
    Q_OBJECT
    Q_PROPERTY(QColor color READ color WRITE setColor FINAL)
    QML_ELEMENT

public:
    PieSlice(QQuickItem *parent = nullptr);

    QColor color() const;
    void setColor(const QColor &color);

    void paint(QPainter *painter) override;

private:
    QColor m_color;
};
    ...

PieChart と同様に、ビルドファイルに "Charts "型名前空間(バージョン1.0)を追加します:

qmakeを使用します:

QT += qml quick

CONFIG += qmltypes
QML_IMPORT_NAME = Charts
QML_IMPORT_MAJOR_VERSION = 1

HEADERS += piechart.h \
           pieslice.h
SOURCES += piechart.cpp \
           pieslice.cpp \
           main.cpp

RESOURCES += chapter4-customPropertyTypes.qrc

DESTPATH = $$[QT_INSTALL_EXAMPLES]/qml/tutorials/extending-qml/chapter4-customPropertyTypes
target.path = $$DESTPATH
INSTALLS += target

CMakeを使う

    ...
qt_add_executable(chapter4-customPropertyTypes
    main.cpp
    piechart.cpp piechart.h
    pieslice.cpp pieslice.h
)
qt_add_qml_module(chapter4-customPropertyTypes
    URI Charts
    QML_FILES App.qml
    DEPENDENCIES QtQuick
)
    ...

第5章 リストのプロパティタイプを使う

extending-qml/chapter5-listproperties

今のところ、PieChartPieSlice を1つだけ持つことができます。理想的には、チャートは複数のスライスを持ち、色やサイズが異なるものであるべきです。これを実現するために、PieSlice アイテムのリストを受け付けるslices プロパティを用意することができます:

import Charts
import QtQuick

Item {
    width: 300; height: 200

    PieChart {
        anchors.centerIn: parent
        width: 100; height: 100

        slices: [
            PieSlice {
                anchors.fill: parent
                color: "red"
                fromAngle: 0; angleSpan: 110
            },
            PieSlice {
                anchors.fill: parent
                color: "black"
                fromAngle: 110; angleSpan: 50
            },
            PieSlice {
                anchors.fill: parent
                color: "blue"
                fromAngle: 160; angleSpan: 100
            }
        ]
    }
}

そのためには、PieChartpieSlice プロパティをslices プロパティに置き換え、QQmlListProperty タイプとして宣言します。QQmlListProperty クラスは、QML拡張でリストプロパティの作成を可能にします。また、pieSlice() 関数をスライスのリストを返すslices() 関数に置き換え、内部関数としてappend_slice() 関数(後述)を追加します。また、QList を使って、m_slices としてスライスの内部リストを保存します:

class PieChart : public QQuickItem
{
    Q_OBJECT
    Q_PROPERTY(QQmlListProperty<PieSlice> slices READ slices FINAL)
    ...
public:
    ...
    QQmlListProperty<PieSlice> slices();

private:
    static void append_slice(QQmlListProperty<PieSlice> *list, PieSlice *slice);

    QString m_name;
    QList<PieSlice *> m_slices;
};

slices プロパティには関連するWRITE 関数がありませんが、QQmlListProperty の仕組み上、変更可能です。PieChart の実装では、QQmlListProperty の値を返すようにPieChart::slices() を実装し、QML からリストに項目を追加する要求があるたびに内部のPieChart::append_slice() 関数が呼び出されるようにしています:

QQmlListProperty<PieSlice> PieChart::slices()
{
    return QQmlListProperty<PieSlice>(this, nullptr, &PieChart::append_slice, nullptr,
                                      nullptr, nullptr, nullptr, nullptr);
}

void PieChart::append_slice(QQmlListProperty<PieSlice> *list, PieSlice *slice)
{
    PieChart *chart = qobject_cast<PieChart *>(list->object);
    if (chart) {
        slice->setParentItem(chart);
        chart->m_slices.append(slice);
    }
}

append_slice() 関数は単純に親アイテムを設定し、新しいアイテムをm_slices リストに追加します。ご覧のように、QQmlListProperty の append 関数は、リストプロパティと追加されるアイテムの2つの引数で呼び出されます。

また、PieSlice クラスは、fromAngleangleSpan プロパティを含み、これらの値に従ってスライスを描画するように変更されています。このチュートリアルの前のページを読んでいれば、これは簡単な修正なので、コードはここでは示しません。

第6章 拡張プラグインの記述

extending-qml/chapter6-plugins

現在、PieChartPieSlice の型は、App.qml によって使用され、C++ アプリケーションでは、QQuickView を使って表示されます。QMLの拡張機能を利用する別の方法として、プラグインライブラリを作成し、 QMLエンジンが新しいQMLインポートモジュールとして利用できるようにする方法があります。これにより、PieChartPieSlice の型が、1つのアプリケーションでのみ使用されるように制限される代わりに、どのQMLアプリケーションでもインポート可能な型名前空間に登録されるようになります。

プラグインを作成する手順はC++プラグインの作成にあります。まず、ChartsPlugin というプラグインクラスを作成します。このクラスはQQmlEngineExtensionPlugin をサブクラスとし、Q_PLUGIN_METADATA() マクロを使用して Qt メタオブジェクトシステムにプラグインを登録します。

以下はchartsplugin.hChartsPlugin の定義です:

#include <QQmlEngineExtensionPlugin>

class ChartsPlugin : public QQmlEngineExtensionPlugin
{
    Q_OBJECT
    Q_PLUGIN_METADATA(IID QQmlEngineExtensionInterface_iid)
};

次に、プロジェクトをプラグインライブラリとして定義するために、ビルドファイルを設定します。

qmakeを使う:

TEMPLATE = lib
CONFIG += plugin qmltypes
QT += qml quick

QML_IMPORT_NAME = Charts
QML_IMPORT_MAJOR_VERSION = 1

TARGET = $$qtLibraryTarget(chartsplugin)

HEADERS += piechart.h \
           pieslice.h \
           chartsplugin.h

SOURCES += piechart.cpp \
           pieslice.cpp

DESTPATH=$$[QT_INSTALL_EXAMPLES]/qml/tutorials/extending-qml/chapter6-plugins/$$QML_IMPORT_NAME

target.path=$$DESTPATH
qmldir.files=$$PWD/qmldir
qmldir.path=$$DESTPATH
INSTALLS += target qmldir

CONFIG += install_ok  # Do not cargo-cult this!

OTHER_FILES += qmldir

# Copy the qmldir file to the same folder as the plugin binary
cpqmldir.files = qmldir
cpqmldir.path = .
COPIES += cpqmldir

CMakeを使う:

# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause

qt6_policy(SET QTP0001 NEW)
qt6_add_qml_module(chartsplugin
    URI "Charts"
    PLUGIN_TARGET chartsplugin
    DEPENDENCIES QtQuick
)

target_sources(chartsplugin PRIVATE
    piechart.cpp piechart.h
    pieslice.cpp pieslice.h
)

target_link_libraries(chartsplugin PRIVATE
    Qt6::Core
    Qt6::Gui
    Qt6::Qml
    Qt6::Quick
)

install(TARGETS chartsplugin
    RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}/Charts"
    LIBRARY DESTINATION "${CMAKE_INSTALL_BINDIR}/Charts"
)
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/qmldir
    DESTINATION "${CMAKE_INSTALL_BINDIR}/Charts"
)

この例をWindowsやLinuxでビルドする場合、Charts ディレクトリは、新しいimportモジュールを使用するアプリケーションと同じレベルに配置されます。このようにすることで、QMLエンジンはQMLインポートのデフォルトの検索パスにアプリケーションの実行ディレクトリが含まれるため、私たちのモジュールを見つけることができます。macOSでは、プラグインのバイナリはアプリケーションバンドル内のContents/PlugIns 。qmakeでは、このパスはchapter6-plugins/app.pro に設定されます:

macos:!qtConfig(static) {
    charts.files = $$OUT_PWD/Charts
    charts.path = Contents/PlugIns
    QMAKE_BUNDLE_DATA += charts
}

このため、main.cppQMLのインポートパスとしてこの場所を追加する必要があります:

    QQuickView view;
#ifdef Q_OS_MACOS
    view.engine()->addImportPath(app.applicationDirPath() + "/../PlugIns");
#endif
    ...

カスタムインポートパスの定義は、同じQMLインポートを使用するアプリケーションが複数ある場合にも便利です。

また、.pro ファイルには、モジュール定義 qmldir ファイルが常にプラグインバイナリと同じ場所にコピーされるようにするためのマジックが追加されています。

qmldir ファイルはモジュール名とそのモジュールで利用できるプラグインを宣言しています:

module Charts
optional plugin chartsplugin
typeinfo plugins.qmltypes
depends QtQuick
prefer :/qt/qml/Charts/

これで、QMLエンジンがモジュールの場所を知っていれば、どのアプリケーションにもインポートできるQMLモジュールができました。この例では、App.qml をロードする実行ファイルが含まれており、import Charts 1.0 ステートメントを使用しています。あるいは、qmlツールを使ってQMLファイルを読み込み、インポートパスをカレントディレク トリに設定し、qmldir ファイルが見つかるようにすることもできます:

qml -I . App.qml

モジュール "Charts "はQMLエンジンによってロードされ、そのモジュールが提供する型は、そのモジュールをインポートするすべてのQML文書で使用できるようになります。

第7章: まとめ

このチュートリアルでは、QML拡張モジュールを作成するための基本的な手順を示 しました:

  • QObject をサブクラス化し、QML_ELEMENT あるいはQML_NAMED_ELEMENT() を用いて新しい QML 型を定義する。
  • Q_INVOKABLE や Qt スロットを使って呼び出し可能なメソッドを追加し、onSignal 構文を使って Qt シグナルに接続する。
  • NOTIFYシグナルを定義して、プロパティ・バインディングを追加する。
  • 組み込みのプロパティ型では不十分な場合は、カスタムプロパティ型を定義します。
  • を使用して、リスト・プロパティ・タイプを定義します。QQmlListProperty
  • Qt プラグインを定義し、qmldirファイルを記述することで、プラグインライブラリを作成する。

QML and C++ Integration overviewdocumentationでは、QML拡張モジュールに追加できるその他の便利な機能を紹介しています。例えば、slices プロパティを使わずにスライスを追加できるように、デフォルトのプロパティを使うことができます:

PieChart {
    PieSlice { ... }
    PieSlice { ... }
    PieSlice { ... }
}

また、プロパティ値のソースを使用して、スライスをランダムに追加したり削除したりすることもできます:

PieChart {
    PieSliceRandomizer on slices {}
}

Note: QML拡張モジュールとその機能についてさらに学びたい方は、チュートリアル「Writing advanced QML Extensions with C++」をご覧ください。

© 2025 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.