「QMLの基礎 - シングルトン」の版間の差分

提供:MochiuWiki : SUSE, EC, PCB
ナビゲーションに移動 検索に移動
(ページの作成:「== 概要 == オブジェクト指向のプログラム言語のクラスのデザインパターンの1種である。<br> デザインパターンとは、オブジェクト指向の言語で使用される設計のパターンのことであり、設計時に直面する問題とその解決策を整理してまとめたものを指す。<br> <br> シングルトンは、クラスの設計方法の1つであり、クラスのインスタンスを2つ以上生成…」)
 
26行目: 26行目:
これは、そのクラスが<code>Q_OBJECT</code>マクロが記述されており、QMLで利用可能である場合(<code>QML_ELEMENT</code>マクロまたは<code>QML_NAMED_ELEMENT()</code>マクロを持つ場合)にのみ有効である。<br>
これは、そのクラスが<code>Q_OBJECT</code>マクロが記述されており、QMLで利用可能である場合(<code>QML_ELEMENT</code>マクロまたは<code>QML_NAMED_ELEMENT()</code>マクロを持つ場合)にのみ有効である。<br>
<br>
<br>
Qt 5の場合、デフォルトでは、各<code>QQmlEngine</code>クラスは、その型に最初にアクセスした時、その型のデフォルトコンストラクタを使用してシングルトンのインスタンスを生成する。<br>
<u>Qt 5の場合</u>、デフォルトでは、各<code>QQmlEngine</code>クラスは、その型に最初にアクセスした時、その型のデフォルトコンストラクタを使用してシングルトンのインスタンスを生成する。<br>
もし、デフォルトコンストラクタが存在しない場合は、シングルトンは初期状態ではアクセス不能になるため、<br>
もし、デフォルトコンストラクタが存在しない場合は、シングルトンは初期状態ではアクセス不能になるため、<br>
<code>qmlRegisterSingletonType()</code>に特定のファクトリ関数を指定する、または、<br>
<code>qmlRegisterSingletonType</code>関数に特定のファクトリー関数を指定する、または、<br>
<code>qmlRegisterSingletonInstance()</code>に同じクラスで同じ型の名前空間とバージョンの特定のインスタンスを指定して呼び出すことにより、オーバーライドすることができる。<br>
<code>qmlRegisterSingletonInstance</code>関数に同じクラスで同じ型の名前空間とバージョンの特定のインスタンスを指定して呼び出すことにより、オーバーライドすることができる。<br>
<br>
<br>
Qt 6の場合、デフォルトでは、各<code>QQmlEngine</code>クラスは、その型に最初にアクセスした時、その型のデフォルトコンストラクタ、または、<br>
<u>Qt 6の場合</u>、デフォルトでは、各<code>QQmlEngine</code>クラスは、その型に最初にアクセスした時、その型のデフォルトコンストラクタ、または、<br>
<code>T *create(QQmlEngine*, QJSEngine*)</code>というシグネチャを持つ静的ファクトリ関数のどちらかを使用して、シングルトンのインスタンスを生成しようとする。<br>
静的ファクトリー関数(<code>T *create(QQmlEngine*, QJSEngine*)</code>)のいずれかを使用して、シングルトンのインスタンスを生成しようとする。<br>
もし、両方が存在して、かつ、アクセス可能な場合、デフォルトコンストラクタが優先される。<br>
もし、両方が存在して、かつ、アクセス可能な場合、デフォルトコンストラクタが優先される。<br>
<br>
<br>
39行目: 39行目:
デフォルトコンストラクタを持つクラスをシングルトンとして宣言する場合は、<code>QML_SINGLETON</code>マクロを記述するだけである。<br>
デフォルトコンストラクタを持つクラスをシングルトンとして宣言する場合は、<code>QML_SINGLETON</code>マクロを記述するだけである。<br>
<br>
<br>
<syntaxhighlight lang="c++">
<syntaxhighlight lang="c++">
  class MySingleton : public QObject
  class MySingleton : public QObject
  {
  {

2023年1月22日 (日) 10:52時点における版

概要

オブジェクト指向のプログラム言語のクラスのデザインパターンの1種である。
デザインパターンとは、オブジェクト指向の言語で使用される設計のパターンのことであり、設計時に直面する問題とその解決策を整理してまとめたものを指す。

シングルトンは、クラスの設計方法の1つであり、クラスのインスタンスを2つ以上生成できないようにすることで、常に同一のインスタンスが参照されるデザインパターンとなる。
例えば、インスタンスの状態を常に持つ場合やクラス端で共通のデータとしてアクセスする必要がある場合に使用される。


前提条件

QQmlEngineヘッダファイルをインクルードする必要がある。
また、qmakeを使用する場合は、変数QTにqmlを追加する必要がある。

 // cppファイル
 
 #include <QQmlEngine>


# qmakeファイル

QT += qml



QML_SINGLETONマクロ

QMLにおいて、内包する型がシングルトンであることを宣言するには、QObjectクラスを継承したクラスを記述して、QML_SINGLETONマクロを使用する。

これは、そのクラスがQ_OBJECTマクロが記述されており、QMLで利用可能である場合(QML_ELEMENTマクロまたはQML_NAMED_ELEMENT()マクロを持つ場合)にのみ有効である。

Qt 5の場合、デフォルトでは、各QQmlEngineクラスは、その型に最初にアクセスした時、その型のデフォルトコンストラクタを使用してシングルトンのインスタンスを生成する。
もし、デフォルトコンストラクタが存在しない場合は、シングルトンは初期状態ではアクセス不能になるため、
qmlRegisterSingletonType関数に特定のファクトリー関数を指定する、または、
qmlRegisterSingletonInstance関数に同じクラスで同じ型の名前空間とバージョンの特定のインスタンスを指定して呼び出すことにより、オーバーライドすることができる。

Qt 6の場合、デフォルトでは、各QQmlEngineクラスは、その型に最初にアクセスした時、その型のデフォルトコンストラクタ、または、
静的ファクトリー関数(T *create(QQmlEngine*, QJSEngine*))のいずれかを使用して、シングルトンのインスタンスを生成しようとする。
もし、両方が存在して、かつ、アクセス可能な場合、デフォルトコンストラクタが優先される。

デフォルトコンストラクタも静的ファクトリ関数も存在しない場合は、シングルトンはアクセス不能になることに注意する。

デフォルトコンストラクタを持つクラスをシングルトンとして宣言する場合は、QML_SINGLETONマクロを記述するだけである。

 class MySingleton : public QObject
 {
    Q_OBJECT
    QML_ELEMENT
    QML_SINGLETON
 
    // Q_PROPERTY( ... )
 
 public:
    // メンバ変数 / メンバ関数, Q_INVOKABLEメソッド等
 };


シングルトンクラスがデフォルトで構築不可であり修正可能な場合は、アクセス可能にするため、静的ファクトリー関数を追加する。

 class MySingleton : public QObject
 {
    Q_OBJECT
    QML_ELEMENT
    QML_SINGLETON
 
    // Q_PROPERTY( ... )
 
 public:
    static MySingleton *create(QQmlEngine *qmlEngine, QJSEngine *jsEngine)
    {
       MySingleton *result = nullptr;
       // 何らかのカスタムコンストラクタやファクトリを用いてオブジェクトを生成する
       // QMLエンジンは、最終的にこのオブジェクトの所有権を取得および削除する
       return result;
    }
 
    // メンバ変数 / メンバ関数, Q_INVOKABLEメソッド等
 };


シングルトンクラスが変更不可で、デフォルトコンストラクタや静的ファクトリー関数が存在しない場合、QML_FOREIGNラッパーを使用して、静的ファクトリー関数を定義することが可能である。

 struct SingletonForeign
 {
    Q_GADGET
    QML_FOREIGN(MySingleton)
    QML_SINGLETON
    QML_NAMED_ELEMENT(MySingleton)
 
 public:
    static MySingleton *create(QQmlEngine *, QJSEngine *engine)
    {
       MySingleton *result = nullptr;
       // 何らかのカスタムコンストラクタやファクトリを用いてインスタンスを生成する
       // QMLエンジンは、最終的にそのインスタンスの所有権を取得および削除する
       return result;
    }
 };


もし、特定のシングルトンオブジェクトを提供する場合、その生成はコントロールできないが、静的ファクトリー関数からそれを返すことができる。
これは、qmlRegisterSingletonInstance関数の代わりとなるものである。

 qmlRegisterSingletonInstance("MyModule", 1, 0, "MySingleton", myObject);


もし、上記のqmlRegisterSingletonInstance("MyModule", 1, 0, "MySingleton", myObject)を記述している場合、MyObjectがMySingleton *型であれば、
代わりに、以下の例のようにクラスを定義することができる。

これは、既存のクラスであるMySingletonクラスは、MySingletonというQMLのシングルトンであることが宣言される。
s_singletonInstanceメンバを設定することにより、使用する前にいつでもそのインスタンスを指定することができるため、MySingletonクラス自身を変更する必要はない。

 struct SingletonForeign
 {
    Q_GADGET
    QML_FOREIGN(MySingleton)
    QML_SINGLETON
    QML_NAMED_ELEMENT(MySingleton)
 
 public:
    // Initialize this using myObject where you would previously
    // call qmlRegisterSingletonInstance().
    inline static MySingleton *s_singletonInstance = nullptr;
 
    static MySingleton *create(QQmlEngine *, QJSEngine *engine)
    {
       // The instance has to exist before it is used. We cannot replace it.
       Q_ASSERT(s_singletonInstance);
 
       // The engine has to have the same thread affinity as the singleton.
       Q_ASSERT(engine->thread() == s_singletonInstance->thread());
 
       // There can only be one engine accessing the singleton.
       if (s_engine)
           Q_ASSERT(engine == s_engine);
       else
           s_engine = engine;
 
        // Explicitly specify C++ ownership so that the engine doesn't delete
        // the instance.
        QJSEngine::setObjectOwnership(s_singletonInstance, QJSEngine::CppOwnership);
 
        return s_singletonInstance;
    }
 
 private:
    inline static QJSEngine *s_engine = nullptr;
 };


※注意
このパターンは、シングルトンが複数のQMLエンジンからアクセスされる場合、または、アクセスするQMLエンジンがシングルトンオブジェクト自身と異なるスレッドアフィニティを持っている場合は動作しない。
上記で示したように、create()メソッドのパラメータでエンジンのIDやスレッドアフィニティを確認することにより、アサーションすることができる。