📢 Webサイト閉鎖と移転のお知らせ
このWebサイトは2026年9月に閉鎖いたします。
新しい記事は移転先で追加しております。(旧サイトでは記事を追加しておりません)
| (同じ利用者による、間の5版が非表示) | |||
| 45行目: | 45行目: | ||
*: もし、両方が存在して両方アクセス可能な場合は、デフォルトコンストラクタが優先される。 | *: もし、両方が存在して両方アクセス可能な場合は、デフォルトコンストラクタが優先される。 | ||
*: <u>ただし、デフォルトコンストラクタも静的ファクトリ関数も存在しない場合は、シングルトンはアクセス不能になることに注意する。</u> | *: <u>ただし、デフォルトコンストラクタも静的ファクトリ関数も存在しない場合は、シングルトンはアクセス不能になることに注意する。</u> | ||
<br> | |||
QMLファイル内でシングルトンを使用する場合は、通常のQMLタイプと同様にインポートする。<br> | |||
インスタンス化する必要はなく、直接そのプロパティやメソッドにアクセスすることができる。<br> | |||
<br> | |||
<u>※注意</u><br> | |||
<u><code>QML_SINGLETON</code>マクロを使用する場合は、クラスが<code>Q_OBJECT</code>マクロも使用している必要がある。</u><br> | |||
<u>また、シングルトンクラスは少なくとも1つの<code>Q_INVOKABLE</code>メソッド、または、<code>NOTIFIABLE</code>プロパティを持っている必要がある。</u><br> | |||
<br> | <br> | ||
==== デフォルトコンストラクタが存在する場合 ==== | ==== デフォルトコンストラクタが存在する場合 ==== | ||
| 164行目: | 171行目: | ||
<br><br> | <br><br> | ||
== | == 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> | ||