C++ による QML 拡張の記述

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

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

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

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

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

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

別の方法として、チュートリアルに沿ってソースをゼロから作成することもできます:各章では、Qt CreatorのQt Quick Applicationテンプレートを使って、Qt Creatorの指示に従って新しいプロジェクトを作成してください:Qt Creator:Creating Qt Quick Projects で説明されているように、Qt Creator で Qt Quick Application テンプレートを使って新しいプロジェクトを作成してください。各章では、Qt Creator: Creating Qt Quick Projects で説明されているように、Qt Creator の Qt Quick Application テンプレートを使用して新しいプロジェクトを作成します。

第1章 新しい型の作成

extending-qml/chapter1-basics

QMLを拡張する際の一般的なタスクは、組み込みのQt Quick types で提供され ている以上のカスタム機能をサポートする新しいQML型を提供することです。例えば、特定のデータモデルを実装したり、独自のペイントや描画機能を持った型を提供したり、 ネットワークプログラミングのような組み込みの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 型とその2つのプロパティをカプセル化した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 から利用できるようになります。スロットは QML からも呼び出せるので、Q_INVOKABLE の代わりに Qt スロットとして宣言することもできます。どちらの方法も有効です。

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 エクステンションとその機能について学び続けるには、C++ を使った高度な QML エクステンションの書き方のチュートリアルを参照してください。

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