📢 Webサイト閉鎖と移転のお知らせ
このWebサイトは2026年9月に閉鎖いたします。
新しい記事は移転先で追加しております。(旧サイトでは記事を追加しておりません)

 
(同じ利用者による、間の4版が非表示)
171行目: 171行目:
<br><br>
<br><br>


== : 複数のQMLから同一のシングルトンクラスを参照する ==
== QML_SINGLETONを使用する場合 ==
==== 使用例 : デフォルトコンストラクタを使用する場合 ====
以下の例では、QML_SINGLETONマクロを使用してConfigServiceをシングルトンクラスとして定義して、アプリケーションのテーマとダークモードの設定を管理している。<br>
<br>
C++側では、main関数内でqmlRegisterSingletonType関数を使用して、このシングルトンをQMLエンジンに登録している。<br>
<br>
QML側では、ConfigServiceシングルトンを直接使用して、現在の設定の表示やユーザの操作に応じて設定を変更している。<br>
これにより、アプリケーション全体で一貫した設定管理が可能になり、C++とQML間でシームレスにデータを共有することができる。<br>
<br>
シングルトンの使用により、コードの重複を避けてアプリケーション全体で一貫したステート管理を実現できる。<br>
<br>
<syntaxhighlight lang="c++">
// ConfigService.hファイル
#include <QObject>
#include <QQmlEngine>
#include <QSettings>
class ConfigService : public QObject
{
    Q_OBJECT
    QML_SINGLETON
    Q_PROPERTY(QString theme READ theme WRITE setTheme NOTIFY themeChanged)
    Q_PROPERTY(bool darkMode READ darkMode WRITE setDarkMode NOTIFY darkModeChanged)
private:
    QString m_theme;
    bool    m_darkMode;
public:
    explicit ConfigService(QObject *parent) : QObject(parent), m_theme("Default"), m_darkMode(false)
    {
      loadSettings();
    }
    QString theme() const
    {
      return m_theme;
    }
    void setTheme(const QString &theme)
    {
      if (m_theme != theme) {
          m_theme = theme;
          emit themeChanged();
      }
    }
    bool darkMode() const
    {
      return m_darkMode;
    }
    void setDarkMode(bool darkMode)
    {
      if (m_darkMode != darkMode) {
          m_darkMode = darkMode;
          emit darkModeChanged();
      }
    }
    Q_INVOKABLE void saveSettings()
    {
      QSettings settings("MyCompany", "MyApp");
      settings.setValue("theme", m_theme);
      settings.setValue("darkMode", m_darkMode);
    }
    Q_INVOKABLE void loadSettings()
    {
      QSettings settings("MyCompany", "MyApp");
      setTheme(settings.value("theme", "Default").toString());
      setDarkMode(settings.value("darkMode", false).toBool());
    }
signals:
    void themeChanged();
    void darkModeChanged();
};
</syntaxhighlight>
<br>
<syntaxhighlight lang="c++">
// main.cppファイル
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include "ConfigService.h"
int main(int argc, char *argv[])
{
    QGuiApplication app(argc, argv);
    qmlRegisterSingletonType<ConfigService>("com.mycompany.configservice", 1, 0, "ConfigService",
      [](QQmlEngine *engine, QJSEngine *scriptEngine) -> QObject * {
          Q_UNUSED(engine)
          Q_UNUSED(scriptEngine)
          return new ConfigService();
      });
    QQmlApplicationEngine engine;
    engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
    return app.exec();
}
</syntaxhighlight>
<br>
<syntaxhighlight lang="qml">
// main.qmlファイル
import QtQuick
import QtQuick.Controls
import com.mycompany.configservice 1.0
ApplicationWindow {
    visible: true
    width: 640
    height: 480
    title: qsTr("Config Service Example")
    Column {
      anchors.centerIn: parent
      spacing: 10
      Text {
          text: "Current Theme: " + ConfigService.theme
      }
      Text {
          text: "Dark Mode: " + (ConfigService.darkMode ? "On" : "Off")
      }
      Button {
          text: "Toggle Dark Mode"
          onClicked: {
            ConfigService.darkMode = !ConfigService.darkMode
            ConfigService.saveSettings()
          }
      }
      ComboBox {
          model: ["Default", "Light", "Dark"]
          onCurrentTextChanged: {
            ConfigService.theme = currentText
            ConfigService.saveSettings()
          }
      }
    }
    Component.onCompleted: {
      ConfigService.loadSettings()
    }
}
</syntaxhighlight>
<br>
==== 使用例 : 静的ファクトリー関数を使用する場合 ====
QML_SINGLETONマクロは、C++クラスをQMLシングルトンとして登録するために使用する。<br>
<br>
デフォルトコンストラクタが存在せず、静的ファクトリー関数が存在する場合、<br>
まず、クラス宣言において、QML_SINGLETONマクロを使用する。<br>
これは通常、クラスのpublicセクションに配置する。<br>
<br>
次に、静的ファクトリー関数を定義する。<br>
この関数は、シングルトンインスタンスを作成して返す役割を持つ。<br>
以下の例では、createSingletonという名前の関数を定義している。<br>
<br>
<code>QML_SINGLETON</code>マクロの引数には、この静的ファクトリー関数を指定する。<br>
つまり、<code>QML_SINGLETON(<シングルトンクラス名>, <静的ファクトリー関数名>)</code>のような形式となる。<br>
例えば、<u>QML_SINGLETON(MySingleton, createSingleton)</u>となる。<br>
<br>
実装する場合には、静的メンバ変数を使用してシングルトンインスタンスを保持して、静的ファクトリー関数内でこのインスタンスを生成・返却する方法が一般的である。<br>
<br>
QMLエンジンがシングルトンを必要とするまで、実際のインスタンス生成を遅延させることができる。<br>
これにより、リソースの効率的な利用が可能になる。<br>
<br>
<u>※注意</u><br>
<u>スレッドセーフティに関しても考慮が必要である。</u><br>
<u>複数のスレッドから同時にアクセスされる可能性がある場合、適切な同期メカニズムを実装することが重要となる。</u><br>
<br>
静的ファクトリー関数を使用することにより、デフォルトコンストラクタを持たないクラスでも、QMLシングルトンとして効果的に機能させることができる。<br>
静的ファクトリー関数を通じて、インスタンスの生成・返却を細かく制御できるため、より柔軟性の高い設計が可能になる。<br>
<br>
<syntaxhighlight lang="c++">
// MySingleton.hファイル
#include <QObject>
#include <QtQml/qqmlregistration.h>
#include <QMutex>
#include <QMutexLocker>
#include <memory>
#include <QDebug>
class MySingleton : public QObject
{
    Q_OBJECT
    QML_SINGLETON(MySingleton, createSingleton)
private:
    explicit MySingleton(QObject *parent = nullptr) : QObject(parent) {}
    static std::unique_ptr<MySingleton> instance;  // インスタンスの生存期間を適切に管理する
    QMutex                              m_mutex;
    // コピーコンストラクタと代入演算子の無効化
    MySingleton(const MySingleton&) = delete;
    MySingleton& operator=(const MySingleton&) = delete;
public:
    Q_INVOKABLE void doSomething()
    {
      // このメソッドが複数のスレッドから同時に呼ばれても、安全に実行される
      QMutexLocker locker(&m_mutex);
      qDebug() << "MySingleton is doing something!";
    }
    static MySingleton *createSingleton(QQmlEngine *engine, QJSEngine *scriptEngine)
    {
      Q_UNUSED(engine)
      Q_UNUSED(scriptEngine)
      // 複数のスレッドから同時に呼ばれても、インスタンスが1度だけ生成されることを保証する
      static QMutex mutex;
      QMutexLocker locker(&mutex);
      if (!instance) {
          // インスタンスの生存期間を適切に管理する
          instance.reset(new MySingleton());
      }
      return instance.get();
    }
};
// メモリリークを防いで、リソース管理を改善する
std::unique_ptr<MySingleton> MySingleton::instance = nullptr;
</syntaxhighlight>
<br>
<syntaxhighlight lang="c++">
// main.cppファイル
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include "MySingleton.h"
int main(int argc, char *argv[])
{
    QGuiApplication app(argc, argv);
    // Qt 6では、QMLエンジンが起動時に自動的にタイプを検出・登録する
    // そのため、qmlRegisterSingletonType関数を使用する必要はない
    // この自動登録メカニズムは、プロジェクトが適切に設定されている場合にのみ機能する
    QQmlApplicationEngine engine;
    engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
    return app.exec();
}
</syntaxhighlight>
<br>
<syntaxhighlight lang="qml">
// main.qmlファイル
import QtQuick
import QtQuick.Window
Window {
    width: 640
    height: 480
    visible: true
    title: qsTr("QML Singleton Example")
    Text {
      anchors.centerIn: parent
      text: "Click me!"
      font.pixelSize: 24
      MouseArea {
          anchors.fill: parent
          onClicked: {
            MySingleton.doSomething()
          }
      }
    }
}
</syntaxhighlight>
<br><br>
 
== QML_SINGLETONを使用しない場合 ==
==== 使用例: 複数のQMLから同一のシングルトンクラスを参照する ====
以下の例では、2つの画面 (Screen1.qmlとScreen2.qml) から同一のシングルトンクラスを参照する。<br>
以下の例では、2つの画面 (Screen1.qmlとScreen2.qml) から同一のシングルトンクラスを参照する。<br>
<br>
<br>