このページでは

QML におけるシングルトン

QMLにおいて、シングルトンとは、engine ごとに最大1回だけ作成されるオブジェクトのことです。このガイドでは、シングルトンの作成方法と 使用方法について 解説します。また、シングルトンを扱う際のベストプラクティスについても紹介します。

QMLでシングルトンはどのように作成できますか?

QMLでシングルトンを作成するには、2つの方法があります。QMLファイル内でシングルトンを定義する方法と、C++から登録する方法です。

QMLでのシングルトンの定義

QMLでシングルトンを定義するには、まず

pragma Singleton

をファイルの先頭に追加する必要があります。さらに、QMLモジュールのqmldirファイルにエントリを追加する必要があります。

qt_add_qml_module の使用(CMake)

CMakeを使用する場合、qmldirはqt_add_qml_moduleによって自動的に作成されます。QMLファイルをシングルトンとして扱うように指定するには、そのファイルに対してQT_QML_SINGLETON_TYPE ファイルプロパティを設定する必要があります:

set_source_files_properties(MySingleton.qml
    PROPERTIES QT_QML_SINGLETON_TYPE TRUE)

set_source_files_properties には、一度に複数のファイルを指定できます:

set(plain_qml_files
    MyItem1.qml
    MyItem2.qml
    FancyButton.qml
)
set(qml_singletons
    MySingleton.qml
    MyOtherSingleton.qml
)
set_source_files_properties(${qml_singletons}
    PROPERTIES QT_QML_SINGLETON_TYPE TRUE)
qt_add_qml_module(myapp
    URI MyModule
    QML_FILES ${plain_qml_files} ${qml_singletons}
)

注: set_source_files_properties は 、以下の処理の前に呼び出す必要がありますqt_add_qml_module

qt_add_qml_module を使用しない場合

qt_add_qml_module を使用しない場合は、手動でqmldir ファイルを作成する必要があります。そのファイル内で、シングルトンを適切にマークする必要があります:

module MyModule
singleton MySingleton 1.0 MySingleton.qml
singleton MyOtherSingleton 1.0 MyOtherSingleton.qml

詳細については、「オブジェクト型の宣言」も参照してください。

C++ でのシングルトンの定義

C++ から QML に対してシングルトンを公開する方法はいくつかあります。主な違いは、QML エンジンが必要としたときにクラスの新しいインスタンスを作成すべきか、あるいは既存のオブジェクトを QML プログラムに公開する必要があるかという点にあります。

シングルトンを提供するクラスの登録

シングルトンを定義する最も簡単な方法は、QObject を継承し、デフォルトコンストラクタを持つクラスを作成し、それをQML_SINGLETONおよびQML_ELEMENT マクロでマークすることです。

class MySingleton : public QObject
{
    Q_OBJECT
    QML_SINGLETON
    QML_ELEMENT
public:
    MySingleton(QObject *parent = nullptr) : QObject(parent) {
        // ...
    }
};

これにより、そのファイルが属するQMLモジュール内で、MySingleton クラスがMySingleton という名前で登録されます。別の名前で公開したい場合は、代わりにQML_NAMED_ELEMENT を使用できます。

クラスをデフォルトコンストラクタで初期化できない場合、またはシングルトンがインスタンス化されるQQmlEngine へのアクセスが必要な場合は、代わりに静的なcreate関数を使用することができます。この関数のシグネチャはMySingleton *create(QQmlEngine *, QJSEngine *) でなければなりません。ここで、MySingleton は登録されるクラスの型です。

class MyNonDefaultConstructibleSingleton : public QObject
{
    Q_OBJECT
    QML_SINGLETON
    QML_NAMED_ELEMENT(MySingleton)
public:
    MyNonDefaultConstructibleSingleton(QJSValue id, QObject *parent = nullptr)
        : QObject(parent)
        , m_symbol(std::move(id))
    {}

    static MyNonDefaultConstructibleSingleton *create(QQmlEngine *qmlEngine, QJSEngine *)
    {
         return new MyNonDefaultConstructibleSingleton(qmlEngine->newSymbol(u"MySingleton"_s));
    }

private:
    QJSValue m_symbol;
};

注:create関数は 、QJSEngine とQQmlEngine の両方のパラメータを受け取ります。これは歴史的な理由によるものです。これらは両方とも、実際にはQQmlEngine である同じオブジェクトを指しています。

C++でインスタンス化されたオブジェクトをシングルトンとして公開する

QQmlEngine にインスタンス化を任せるのではなく、C++側からシングルトンのインスタンス化を制御できると便利な場合があります。このようなシングルトンは、エンジンによってインスタンス化される必要がないため、デフォルトコンストラクタや静的なcreate 関数を省略できます。その場合は、シングルトンの宣言にQML_UNCREATABLE マクロを含める必要があります:

class MyNonDefaultConstructibleSingleton : public QObject
{
    Q_OBJECT
    QML_SINGLETON
    QML_NAMED_ELEMENT(MySingleton)
    QML_UNCREATABLE("Provided by C++")
public:
    MyNonDefaultConstructibleSingleton(BackendObject* backend, QObject *parent = nullptr)
        : QObject(parent)
        , m_backend(backend)
    {}

private:
    class BackendObject* backend;
};

次に、エンジンを起動する前に、エンジンで使用するインスタンスを設定します:

MyNonDefaultConstructibleSingleton singleton(backend);
QQmlApplicationEngine engine;
engine.setExternalSingletonInstance("MyModule", "MySingleton", &singleton);
engine.loadFromModule("MyModule", "Main");

既存のオブジェクトをシングルトンとして公開する

場合によっては、サードパーティのAPIなどを介して作成された既存のオブジェクトが存在することがあります。このような場合、適切な選択は、それらのオブジェクトをプロパティとして公開する単一のシングルトンを用意することです(「関連するデータのグループ化」を参照)。 しかし、例えば公開する必要があるオブジェクトが1つしかない場合など、それが当てはまらない場合は、次のアプローチを使用して、MySingleton 型のインスタンスをエンジンに公開します。まず、Singletonをforeign type として公開します:

struct SingletonForeign
{
    Q_GADGET
    QML_FOREIGN(MySingleton)
    QML_SINGLETON
    QML_NAMED_ELEMENT(MySingleton)
    QML_UNCREATABLE("Provided from C++")
};

次に、MySingletonをインスタンス化し、それをエンジンに設定します:

MySingleton instance = getSingletonInstance();
QQmlApplicationEngine engine;
engine.setExternalSingletonInstance("MyModule", "MySingleton", &instance);
engine.loadFromModule("MyModule", "Main");

注: この場合、単に `qmlRegisterSingletonInstance ` を使用したいという誘惑に駆られがちです 。しかし、次のセクションで挙げる命令型登録の落とし穴には十分注意してください。

命令型による型登録

Qt 5.15 以前では、シングルトンを含むすべての型が `qmlRegisterType ` API を通じて登録されていました。 特にシングルトンは、qmlRegisterSingletonType またはqmlRegisterSingletonInstance のいずれかを介して登録されていました。各型ごとにモジュール名を繰り返し指定しなければならないという些細な煩わしさや、クラス宣言とその登録の強制的な分離に加え、このアプローチの主な問題は、ツールとの親和性が低かったことです: コンパイル時に、モジュールの型に関する必要な情報をすべて静的に抽出することができませんでした。宣言型登録により、この問題は解決されました。

var 注: 命令型qmlRegisterType APIには、まだ 1つのユースケースが残っています 。それは、非QObject 型のシングルトンを、 the QJSValue based qmlRegisterSingletonType overload 。代わりに、その値を(QObject )ベースのシングルトンのプロパティとして公開することを推奨します。そうすることで、型情報が利用可能になります。

シングルトンへのアクセス

シングルトンには、QML からも C++ からもアクセスできます。QML では、そのシングルトンを含むモジュールをインポートする必要があります。その後、名前を指定してシングルトンにアクセスできます。JavaScript コンテキスト内でのプロパティの読み取りや書き込みは、通常のオブジェクトと同様に行われます:

import QtQuick
import MyModule

Item {
    x: MySingleton.posX
    Component.onCompleted: MySingleton.ready = true;
}

シングルトンのプロパティにバインディングを設定することはできませんが、必要な場合は、Binding 要素を使用して同様の結果を得ることができます:

import QtQuick
import MyModule

Item {
    id: root
    Binding {
        target: MySingleton
        property: "posX"
        value: root.x
    }
}

注: シングルトンのプロパティにバインディングを設定する際は注意が必要です 。複数のファイルから設定が行われた場合、結果は未定義となります。

シングルトンの(使用しない)ためのガイドライン

シングルトンを使用すると、複数の場所でアクセスする必要があるデータをエンジンに公開できます。これには、要素間の間隔のようなグローバルに共有される設定や、複数の場所で表示する必要があるデータモデルなどが含まれます。同様のユースケースを解決できるコンテキストプロパティと比較して、シングルトンには型付けされているという利点があり、 QML Language Serverなどのツールによるサポートを受けられる点、また一般的に実行時のパフォーマンスが優れているという利点があります。

1つのモジュールにシングルトンを登録しすぎないことを推奨します。シングルトンは一度作成されると、エンジン自体が破棄されるまで存続し、グローバル状態の一部であるため、状態共有に伴う欠点があります。したがって、アプリケーション内のシングルトンの数を減らすために、以下の手法を検討してください:

公開したいオブジェクトごとにシングルトンを追加すると、かなりの定型コードが発生します。ほとんどの場合、公開したいデータを単一のシングルトンのプロパティとしてまとめてグループ化する方が理にかなっています。例えば、3つのabstract item models (ローカルの書籍用が1つ、リモートソース用が2つ)を公開する必要がある電子書籍リーダーを作成すると仮定しましょう。既存のオブジェクトを公開するための処理を3回繰り返す代わりに、1つのシングルトンを作成し、メインアプリケーションを起動する前に設定することができます:

class GlobalState : QObject
{
    Q_OBJECT
    QML_ELEMENT
    QML_SINGLETON
    Q_PROPERTY(QAbstractItemModel* localBooks MEMBER localBooks)
    Q_PROPERTY(QAbstractItemModel* digitalStoreFront MEMBER digitalStoreFront)
    Q_PROPERTY(QAbstractItemModel* publicLibrary MEMBER publicLibrary)
public:
    QAbstractItemModel* localBooks;
    QAbstractItemModel* digitalStoreFront;
    QAbstractItemModel* publicLibrary
};

int main() {
    QQmlApplicationEngine engine;
    auto globalState = engine.singletonInstance<GlobalState *>("MyModule", "GlobalState");
    globalState->localBooks = getLocalBooks();
    globalState->digitalStoreFront = setupLoalStoreFront();
    globalState->publicLibrary = accessPublicLibrary();
    engine.loadFromModule("MyModule", "Main");
}

オブジェクトインスタンスの使用

前のセクションでは、3つのモデルをシングルトンのメンバとして公開する例を取り上げました。これは、モデルを複数の場所で使用する必要がある場合や、制御できない外部APIによってモデルが提供される場合に役立ちます。 しかし、モデルが1か所だけで必要とされる場合は、インスタンス化可能な型として扱うほうが理にかなっているかもしれません。前の例に戻ると、インスタンス化可能な `RemoteBookModel` クラスを追加し、ブックブラウザのQMLファイル内でインスタンス化することができます:

// remotebookmodel.h
class RemoteBookModel : public QAbstractItemModel
{
    Q_OBJECT
    QML_ELEMENT
    Q_PROPERTY(QUrl url READ url WRITE setUrl NOTIFY urlChanged)
    // ...
};
// bookbrowser.qml
Row {
    ListView {
        model: RemoteBookModel { url: "www.public-lib.example"}
    }
    ListView {
        model: RemoteBookModel { url: "www.store-front.example"}
    }
}

初期状態の受け渡し

シングルトンはQMLに状態を渡すために使用できますが、その状態がアプリケーションの初期設定にのみ必要な場合は非効率的です。そのような場合、QQmlApplicationEngine::setInitialProperties を使用できることがよくあります。例えば、対応するコマンドラインフラグが設定されている場合に、Window::visibility をフルスクリーンに設定したい場合などです:

QQmlApplicationEngine engine;
if (parser.isSet(fullScreenOption)) {
    // assumes root item is ApplicationWindow
    engine.setInitialProperties(
        { "visibility", QVariant::fromValue(QWindow::FullScreen)}
    );
}
engine.loadFromModule("MyModule, "Main");

© 2026 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.