📢 Webサイト閉鎖と移転のお知らせ
このWebサイトは2026年9月に閉鎖いたします。
新しい記事は移転先で追加しております。(旧サイトでは記事を追加しておりません)
ページの作成:「== 概要 == <br><br> == QT_VERSION_CHECKマクロ == <code>QT_VERSION_CHECK</code>マクロを使用する場合は、<code>QtGlobal</code>をインクルードする必要がある。<br> このヘッダファイルには、<code>QT_VERSION_CHECK</code>マクロを含む多くのQtの基本的な定義が含まれている。<br> <syntaxhighlight lang="c++"> #include <QtGlobal> </syntaxhighlight> <br><br> __FORCETOC__ カテゴリ:Qt」 |
|||
| (同じ利用者による、間の16版が非表示) | |||
| 1行目: | 1行目: | ||
== 概要 == | == 概要 == | ||
Qtにおけるプリプロセッサは、標準的なC++プリプロセッサを拡張して、Qtフレームワークに特化した機能を提供している。<br> | |||
この拡張により、開発者はより効率的にQtアプリケーションを作成できるようになる。<br> | |||
また、クロスプラットフォームアプリケーションの開発がより効率的かつ柔軟になっている。<br> | |||
<br> | |||
Qt独自のプリプロセッサの主な特徴として、メタオブジェクトシステムのサポートが挙げられる。<br> | |||
これは、Qtの中核をなす機能であり、シグナル / スロットのメカニズムやプロパティシステムを可能にするものである。<br> | |||
<br> | |||
<code>Q_OBJECT</code>マクロは、このメタオブジェクトシステムの中心的な要素である。<br> | |||
このマクロをクラス定義に含めることにより、そのクラスにQtのメタオブジェクト機能が追加される。<br> | |||
これにより、シグナル / スロットの宣言、動的なプロパティの追加、実行時型情報 (RTTI) の拡張等が可能になる。<br> | |||
<br> | |||
プリプロセッサは、<code>Q_PROPERTY</code>マクロを使用してクラスのプロパティを宣言する機能も提供している。<br> | |||
これにより、Qtのプロパティシステムを利用でき、GUIデザイナーツールとの連携、QML (Qt Modeling Language) でのプロパティバインディングが容易になる。<br> | |||
<br> | |||
また、Qtのプリプロセッサは、プラットフォーム依存のコードを簡単に記述できるようにする機能も備えている。<br> | |||
例えば、Q_OS_*マクロを使用することにより、特定のOS向けのコードを条件付きでコンパイルすることができる。<br> | |||
<br> | |||
さらに、国際化 (i18n) のサポートも重要な機能の1つである。<br> | |||
<code>QT_TR_NOOP</code>や<code>Q_TRANSLATE_NOOP</code>等のマクロを使用することにより、翻訳可能な文字列を簡単にマークアップすることができる。<br> | |||
<br> | |||
これらの機能に加えて、Qtのプリプロセッサは、シグナル / スロットの接続を最適化するためのプライベートシグナル、メモリ管理を支援するためのスマートポインタマクロ等、<br> | |||
様々な便利な機能を提供している。<br> | |||
<br> | |||
Qtのプリプロセッサは、moc (Meta-Object Compiler) と呼ばれるツールと密接に連携している。<br> | |||
mocは、Qtのマクロを含むヘッダファイルを解析して、必要なメタオブジェクトコードを生成する。<br> | |||
<br> | |||
このプロセスは、一般的に、ビルドシステムにより自動的に処理されるため、開発者は特別な操作を行う必要はない。<br> | |||
<br><br> | <br><br> | ||
| 7行目: | 34行目: | ||
<syntaxhighlight lang="c++"> | <syntaxhighlight lang="c++"> | ||
#include <QtGlobal> | #include <QtGlobal> | ||
</syntaxhighlight> | |||
<br><br> | |||
== クラスに関するマクロ == | |||
==== Q_OBJECT ==== | |||
Qtのメタオブジェクトシステムの中核となるマクロである。<br> | |||
<code>QObject</code>クラスを継承するサブクラスの定義内で使用され、シグナル / スロットのメカニズム、実行時型情報 (RTTI)、動的プロパティシステムを有効にする。<br> | |||
<br> | |||
このマクロを使用することにより、クラスはQtの多くの高度な機能を使用できるようになる。<br> | |||
<br> | |||
==== Q_PROPERTY ==== | |||
クラスのプロパティを宣言するために使用する。<br> | |||
<br> | |||
このマクロを使用することにより、C++のメンバ変数をQtのプロパティシステムに統合できる。<br> | |||
これにより、QMLでのプロパティバインディングやGUIデザイナーでのプロパティ編集が可能になる。<br> | |||
<br> | |||
また、プロパティの読み取り / 書き込みメソッド、通知シグナル、リセットメソッド等も定義できる。<br> | |||
<br> | |||
<syntaxhighlight lang="c++"> | |||
class Person : public QObject | |||
{ | |||
Q_OBJECT | |||
Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged) | |||
Q_PROPERTY(int age READ age WRITE setAge NOTIFY ageChanged) | |||
private: | |||
QString m_name; | |||
int m_age = 0; | |||
public: | |||
Person(QObject *parent = nullptr) : QObject(parent) {} | |||
QString name() const { return m_name; } | |||
void setName(const QString &name) | |||
{ | |||
if (m_name != name) { | |||
m_name = name; | |||
emit nameChanged(m_name); | |||
} | |||
} | |||
int age() const { return m_age; } | |||
void setAge(int age) | |||
{ | |||
if (m_age != age) { | |||
m_age = age; | |||
emit ageChanged(m_age); | |||
} | |||
} | |||
signals: | |||
void nameChanged(const QString &name); | |||
void ageChanged(int age); | |||
}; | |||
</syntaxhighlight> | |||
<br> | |||
==== Q_INVOKABLE ==== | |||
このマクロをメソッド宣言の前に付加することにより、そのメソッドをQMLから呼び出し可能にする。<br> | |||
<br> | |||
一般的に、publicスロットは自動的にQMLから呼び出せるが、publicメソッドは<code>Q_INVOKABLE</code>を使用しない限り呼び出せない。<br> | |||
<br> | |||
==== signals / Q_SIGNAL / Q_SIGNALS ==== | |||
シグナルを宣言するために使用する。<br> | |||
<br> | |||
シグナルは、オブジェクト間の通信メカニズムの一部であり、特定のイベントが発生したことを他のオブジェクトに通知するために使用する。<br> | |||
<br> | |||
==== slots / Q_SLOT / Q_SLOTS ==== | |||
スロットを宣言するために使用する。<br> | |||
<br> | |||
スロットはシグナルに接続可能な特殊な関数であり、シグナルが発信されたときに呼び出される。<br> | |||
<br> | |||
==== Q_EMIT ==== | |||
シグナルを発信 (emit) する場合に使用するマクロである。 | |||
本質的には、C++のソースコード内でシグナルを発信するための構文的な装飾である。 | |||
シグナルを発信する場合は、明示的にそれがシグナルの発信であることを示す。 | |||
通常は、<code>emit</code>キーワードとして使用するが、<code>Q_EMIT</code>はその完全修飾名である。 | |||
コンパイル時には何も行わず、コードの可読性を向上させる目的で使用する。 | |||
<br> | |||
<syntaxhighlight lang="c++"> | |||
class MyClass : public QObject | |||
{ | |||
Q_OBJECT | |||
signals: | |||
void valueChanged(int newValue); | |||
public: | |||
void updateValue(int value) | |||
{ | |||
Q_EMIT valueChanged(value); | |||
// または、emit valueChanged(value); としてもよい | |||
} | |||
}; | |||
</syntaxhighlight> | |||
<br> | |||
==== Q_GADGET ==== | |||
<code>QObject</code>クラスを継承せずに、Qtのメタオブジェクトシステムの一部の機能 (プロパティ、列挙型等) を利用可能にするマクロである。<br> | |||
<br> | |||
軽量なオブジェクトを作成する場合に有効である。<br> | |||
<br> | |||
<syntaxhighlight lang="c++"> | |||
class Point | |||
{ | |||
Q_GADGET | |||
Q_PROPERTY(int x MEMBER m_x) | |||
Q_PROPERTY(int y MEMBER m_y) | |||
private: | |||
int m_x, | |||
m_y; | |||
public: | |||
Point(int x = 0, int y = 0) : m_x(x), m_y(y) {} | |||
int x() const { return m_x; } | |||
int y() const { return m_y; } | |||
}; | |||
Q_DECLARE_METATYPE(Point) | |||
</syntaxhighlight> | |||
<br> | |||
==== Q_ENUMマクロ ==== | |||
列挙型をQtのメタオブジェクトシステムに登録するために使用する。<br> | |||
これにより、列挙型の値を文字列に変換する、または、QMLで使用したりすることが可能になる。<br> | |||
<br> | |||
<syntaxhighlight lang="c++"> | |||
class TrafficLight : public QObject | |||
{ | |||
Q_OBJECT | |||
private: | |||
Color m_color = Color::Red; | |||
public: | |||
enum class Color { | |||
Red, | |||
Yellow, | |||
Green | |||
}; | |||
Q_ENUM(Color) | |||
TrafficLight(QObject *parent = nullptr) : QObject(parent) {} | |||
void setColor(Color color) | |||
{ | |||
m_color = color; | |||
qDebug() << "Color set to:" << QMetaEnum::fromType<Color>().valueToKey(static_cast<int>(m_color)); | |||
} | |||
}; | |||
</syntaxhighlight> | |||
<br> | |||
==== Q_ENUMSマクロ (Qt 5のみ) ==== | |||
列挙型をQtのメタオブジェクトシステムに登録するために使用する。<br> | |||
<br> | |||
複数の列挙型を1度に登録することができる。<br> | |||
列挙型の値を文字列に変換する、または、その逆を行うことが可能である。<br> | |||
<br> | |||
また、QMLで列挙型を使用可能にする。<br> | |||
<br> | |||
<u>ただし、Qt 6以降では、<code>Q_ENUM</code>マクロに置き換えられている。</u><br> | |||
<u>後方互換性のためにサポートされている。</u><br> | |||
<br> | |||
==== Q_DISABLE_COPY / Q_DISABLE_MOVE ==== | |||
<code>Q_DISABLE_COPY</code>マクロは、クラスのコピーコンストラクタとコピー代入演算子を削除する。<br> | |||
これにより、クラスのインスタンスが誤ってコピーされることを防ぐ。<br> | |||
<br> | |||
<code>Q_DISABLE_MOVE</code>マクロは、クラスのムーブコンストラクタとムーブ代入演算子を削除する。<br> | |||
これにより、クラスのインスタンスが移動されることを防ぐ。<br> | |||
<br> | |||
これらのマクロは、以下に示すようなメリットがある。<br> | |||
* オブジェクトの意図しない複製や移動を防ぐことができる。 | |||
* リソースの所有権に関する問題を回避できる。 | |||
* クラスの設計意図を明確に示すことができる。 | |||
<br> | |||
以下の例では、クラスのインスタンスがコピーや移動されることを防ぐ方法を示している。<br> | |||
これにより、意図しないオブジェクトの複製や移動を防ぎ、リソース管理を適切に行うことができる。<br> | |||
<br> | |||
<syntaxhighlight lang="c++"> | |||
// NonCopyable.hファイル | |||
class NonCopyable | |||
{ | |||
private: | |||
Q_DISABLE_COPY(NonCopyable) | |||
public: | |||
NonCopyable() = default; | |||
~NonCopyable() = default; | |||
void doSomething() { qDebug() << "Doing something"; } | |||
}; | |||
</syntaxhighlight> | |||
<br> | |||
<syntaxhighlight lang="c++"> | |||
// NonMovable.hファイル | |||
class NonMovable | |||
{ | |||
private: | |||
Q_DISABLE_MOVE(NonMovable) | |||
public: | |||
NonMovable() = default; | |||
~NonMovable() = default; | |||
void doSomething() { qDebug() << "Doing something"; } | |||
}; | |||
</syntaxhighlight> | |||
<br> | |||
<syntaxhighlight lang="c++"> | |||
// 使用例 | |||
#include "NonCopyable.h" | |||
#include "NonMovable.h" | |||
void testNonCopyable() | |||
{ | |||
NonCopyable nc1; | |||
// NonCopyable nc2 = nc1; // コンパイルエラー: コピーコンストラクタは削除されている | |||
// NonCopyable nc3(nc1); // コンパイルエラー: コピーコンストラクタは削除されている | |||
// nc1 = NonCopyable(); // コンパイルエラー: コピー代入演算子は削除されている | |||
nc1.doSomething(); // コンパイル可能 | |||
} | |||
void testNonMovable() | |||
{ | |||
NonMovable nm1; | |||
// NonMovable nm2 = std::move(nm1); // コンパイルエラー: ムーブコンストラクタは削除されている | |||
// nm1 = NonMovable(); // コンパイルエラー: ムーブ代入演算子は削除されている | |||
nm1.doSomething(); // コンパイル可能 | |||
} | |||
int main() | |||
{ | |||
testNonCopyable(); | |||
testNonMovable(); | |||
return 0; | |||
} | |||
</syntaxhighlight> | |||
<br> | |||
==== Q_FLAG / Q_FLAGS ==== | |||
列挙型をQtのメタオブジェクトシステムに登録するために使用する。<br> | |||
<code>Q_FLAG</code>マクロは単一の列挙型、<code>Q_FLAGS</code>マクロは複数の列挙型を登録する。<br> | |||
<br> | |||
これにより、列挙型の値を文字列に変換する、または、QMLで使用することが可能になる。<br> | |||
<br> | |||
<syntaxhighlight lang="c++"> | |||
class Window : public QObject | |||
{ | |||
Q_OBJECT | |||
public: | |||
enum Option { | |||
NoOption = 0x0, | |||
ShowTitle = 0x1, | |||
ShowButtons = 0x2 | |||
}; | |||
Q_FLAG(Option) | |||
enum Mode { | |||
Normal, | |||
Fullscreen | |||
}; | |||
Q_ENUM(Mode) | |||
Q_FLAGS(Options, Option) | |||
public: | |||
Window(QObject *parent = nullptr) : QObject(parent) {} | |||
}; | |||
</syntaxhighlight> | |||
<br> | |||
<syntaxhighlight lang="c++"> | |||
// 使用例 | |||
void useEnums() | |||
{ | |||
Window window; | |||
QMetaEnum optionEnum = QMetaEnum::fromType<Window::Option>(); | |||
qDebug() << optionEnum.valueToKey(Window::ShowTitle); // 出力: "ShowTitle" | |||
} | |||
</syntaxhighlight> | |||
<br> | |||
==== Q_CLASSINFO ==== | |||
クラスに関する追加のメタデータを定義するために使用する。<br> | |||
これは、クラスに関する任意の名前と値のペアとして情報を格納することができ、実行時にこの情報にアクセスすることができる。<br> | |||
<br> | |||
リフレクションを通じてランタイムにこの情報にアクセスすることができる。<br> | |||
<br> | |||
以下の例では、MyClassに対して3つの追加情報 (Version、Author、Description) を定義している。<br> | |||
printClassInfoメソッドでは、QMetaObjectを使用してこれらの情報にアクセスして表示している。<br> | |||
<br> | |||
<syntaxhighlight lang="c++"> | |||
// MyClass.hファイル | |||
#include <QObject> | |||
#include <QMetaClassInfo> | |||
#include <QDebug> | |||
class MyClass : public QObject | |||
{ | |||
Q_OBJECT | |||
Q_CLASSINFO("Version", "1.0") | |||
Q_CLASSINFO("Author", "John Doe") | |||
Q_CLASSINFO("Description", "This is a sample class") | |||
public: | |||
MyClass(QObject *parent = nullptr) : QObject(parent) {} | |||
static void printClassInfo() | |||
{ | |||
const QMetaObject* metaObject = &MyClass::staticMetaObject; | |||
qDebug() << "Class name: " << metaObject->className(); | |||
int count = metaObject->classInfoCount(); | |||
qDebug() << "Class info count: " << count; | |||
for (int i = 0; i < count; ++i) { | |||
QMetaClassInfo classInfo = metaObject->classInfo(i); | |||
qDebug() << classInfo.name() << ":" << classInfo.value(); | |||
} | |||
} | |||
}; | |||
</syntaxhighlight> | |||
<br> | |||
<syntaxhighlight lang="c++"> | |||
// main.cppファイル | |||
#include "MyClass.h" | |||
int main() | |||
{ | |||
MyClass::printClassInfo(); | |||
return 0; | |||
} | |||
</syntaxhighlight> | |||
<br> | |||
==== Q_DECLARE_TYPEINFO ==== | |||
カスタム型の特性をQtに伝えるために使用する。<br> | |||
<br> | |||
主に、型がトリビアルにコピー可能かどうか、また、ポインタ型のように扱えるかどうかを指定する。<br> | |||
これにより、Qtのコンテナクラスが特定の型を効率的に扱えるようになる。<br> | |||
<br> | |||
<syntaxhighlight lang="c++"> | |||
struct MyPOD { | |||
int x; | |||
double y; | |||
}; | |||
Q_DECLARE_TYPEINFO(MyPOD, Q_PRIMITIVE_TYPE); | |||
struct MyComplex { | |||
QString str; | |||
QVector<int> vec; | |||
}; | |||
Q_DECLARE_TYPEINFO(MyComplex, Q_MOVABLE_TYPE); | |||
</syntaxhighlight> | |||
<br> | |||
==== Q_DECLARE_INTERFACE ==== | |||
抽象インターフェースクラスを宣言するために使用する。<br> | |||
<br> | |||
主に、Qtのプラグインシステムで使用され、インターフェースにユニークな識別子を割り当てる。<br> | |||
<br> | |||
<syntaxhighlight lang="c++"> | |||
class MyInterface | |||
{ | |||
public: | |||
virtual ~MyInterface() {} | |||
virtual void doSomething() = 0; | |||
}; | |||
Q_DECLARE_INTERFACE(MyInterface, "com.mycompany.MyInterface") | |||
class MyPlugin : public QObject, public MyInterface | |||
{ | |||
Q_OBJECT | |||
Q_INTERFACES(MyInterface) | |||
public: | |||
void doSomething() override | |||
{ | |||
// 実装を記述する | |||
} | |||
}; | |||
</syntaxhighlight> | |||
<br> | |||
==== Q_DECLARE_FLAGS / Q_DECLARE_OPERATORS_FOR_FLAGS ==== | |||
<code>Q_DECLARE_FLAGS</code>マクロは、列挙型からフラグ型を生成するために使用する。<br> | |||
<br> | |||
フラグ型は、複数の列挙値をビット演算子で組み合わせて使用できるようにする。<br> | |||
<br> | |||
<code>Q_DECLARE_OPERATORS_FOR_FLAGS</code>マクロは、<code>Q_DECLARE_FLAGS</code>マクロで宣言されたフラグ型に対して、ビット演算子のオーバーロードを提供する。<br> | |||
これにより、フラグ値を簡単に組み合わせたり操作したりすることができる。<br> | |||
<br> | |||
一般的に、これら2つのマクロは同時に使用する。<br> | |||
<br> | |||
<syntaxhighlight lang="c++"> | |||
class Window : public QObject | |||
{ | |||
Q_OBJECT | |||
private: | |||
Options m_options; | |||
public: | |||
enum Option { | |||
NoOption = 0x0, | |||
ShowTitle = 0x1, | |||
ShowButtons = 0x2, | |||
ClosableWindow = 0x4 | |||
}; | |||
Q_DECLARE_FLAGS(Options, Option) | |||
public: | |||
Window(QObject *parent = nullptr) : QObject(parent) {} | |||
void setOptions(Options options) | |||
{ | |||
m_options = options; | |||
} | |||
}; | |||
Q_DECLARE_OPERATORS_FOR_FLAGS(Window::Options) | |||
</syntaxhighlight> | |||
<br> | |||
<syntaxhighlight lang="c++"> | |||
// 使用例 | |||
int main() | |||
{ | |||
Window window; | |||
window.setOptions(Window::ShowTitle | Window::ShowButtons); | |||
return 0; | |||
} | |||
</syntaxhighlight> | |||
<br> | |||
==== Q_DECLARE_PRIVATE / Q_DECLARE_PUBLIC ==== | |||
これは、Qtのプライベート実装パターンと共有データの管理に関連している。<br> | |||
<br> | |||
Qtのd-pointerイディオムを実装するために使用する。<br> | |||
このパターンは、クラスの実装詳細を隠蔽して、バイナリ互換性を維持するのに役立つ。<br> | |||
<br> | |||
また、プライベートクラスとパブリッククラス間で相互にアクセスが可能となる。<br> | |||
<br> | |||
<syntaxhighlight lang="c++"> | |||
// MyClass.hファイル | |||
#include "MyClassPrivate.h" | |||
class MyClassPrivate; | |||
class MyClass | |||
{ | |||
private: | |||
Q_DECLARE_PRIVATE(MyClass) | |||
MyClassPrivate *d_ptr; | |||
public: | |||
MyClass() : d_ptr(new MyClassPrivate(this)) | |||
{} | |||
~MyClass() | |||
{ | |||
delete d_ptr; | |||
} | |||
void doSomething() | |||
{ | |||
Q_D(MyClass); | |||
d->internalFunction(); | |||
} | |||
}; | |||
</syntaxhighlight> | |||
<br> | |||
<syntaxhighlight lang="c++"> | |||
// MyClassPrivate.hファイル | |||
class MyClassPrivate | |||
{ | |||
public: | |||
MyClassPrivate(MyClass *q) : q_ptr(q) {} | |||
void MyClassPrivate::internalFunction() | |||
{ | |||
Q_Q(MyClass); | |||
// publicクラスのメンバーにアクセスできる | |||
someData = 42; | |||
} | |||
MyClass *q_ptr; | |||
Q_DECLARE_PUBLIC(MyClass) | |||
int someData; | |||
}; | |||
</syntaxhighlight> | |||
<br> | |||
==== Q_DECLARE_SHARED ==== | |||
暗黙的な共有 (implicit sharing) を使用するクラスを宣言するために使用する。<br> | |||
これにより、クラスのインスタンスを効率的にコピーできる。<br> | |||
<br> | |||
これは、メモリ使用量を削減でき、大きなオブジェクトの不必要なコピーを避けることができる。<br> | |||
<br> | |||
<syntaxhighlight lang="c++"> | |||
// MySharedData.hファイル | |||
#include <QSharedData> | |||
#include <QSharedDataPointer> | |||
#include "MySharedDataPrivate.h" | |||
class MySharedDataPrivate; | |||
class MySharedData | |||
{ | |||
private: | |||
QSharedDataPointer<MySharedDataPrivate> d; | |||
public: | |||
MySharedData() : d(new MySharedDataPrivate) {} | |||
MySharedData::MySharedData(const MySharedData &other) : d(other.d) {} | |||
MySharedData &operator=(const MySharedData &other) | |||
{ | |||
if (this != &other) | |||
d = other.d; | |||
return *this; | |||
} | |||
~MySharedData(){} | |||
void setValue(int value) | |||
{ | |||
d->value = value; | |||
} | |||
int MySharedData::value() const | |||
{ | |||
return d->value; | |||
} | |||
}; | |||
// クラスの宣言に関連する情報を提供して、 | |||
// そのクラスを使用するコードがこの情報にアクセスする必要があるため、ここで宣言する | |||
Q_DECLARE_SHARED(MySharedData) | |||
</syntaxhighlight> | |||
<br> | |||
<syntaxhighlight lang="c++"> | |||
// MySharedDataPrivate.hファイル | |||
#include <QSharedData> | |||
class MySharedDataPrivate : public QSharedData | |||
{ | |||
public: | |||
MySharedDataPrivate() : value(0) {} | |||
MySharedDataPrivate(const MySharedDataPrivate &other) : QSharedData(other), value(other.value) {} | |||
int value; | |||
}; | |||
</syntaxhighlight> | |||
<br> | |||
<syntaxhighlight lang="c++"> | |||
// 使用例 | |||
void useSharedData() | |||
{ | |||
MySharedData data1; | |||
data1.setValue(42); | |||
MySharedData data2 = data1; // データは共有される | |||
data2.setValue(100); // この時点で、データのコピーが作成される | |||
qDebug() << data1.value(); // 出力: 42 | |||
qDebug() << data2.value(); // 出力: 100 | |||
} | |||
</syntaxhighlight> | |||
<br> | |||
==== Q_D / Q_Q ==== | |||
d-pointerイディオムの実装時において、privateクラスとpublicクラス間のアクセスを容易にする。<br> | |||
<br> | |||
Q_Dマクロは、publicクラスからprivateクラスにアクセスするために使用する。<br> | |||
Q_Qマクロは、privateクラスからpublicクラスにアクセスするために使用する。<br> | |||
<br> | |||
これらのマクロを使用することにより、以下に示すようなメリットがある。<br> | |||
* private実装とpublicインターフェース間のアクセスを簡潔に記述することができる。 | |||
* タイプセーフなアクセスが可能になる。 | |||
* ソースコードの可読性が向上する。 | |||
<br> | |||
以下の例では、publicクラスとprivateクラス間で相互にアクセスする方法を示している。<br> | |||
これにより、実装の詳細を隠蔽しつつ、必要な場合に内部データにアクセスすることができる。<br> | |||
<syntaxhighlight lang="c++"> | |||
// MyClass.hファイル | |||
#include "MyClassPrivate.h" | |||
class MyClassPrivate; | |||
class MyClass | |||
{ | |||
private: | |||
Q_DECLARE_PRIVATE(MyClass) | |||
MyClassPrivate *d_ptr; | |||
public: | |||
MyClass() : d_ptr(new MyClassPrivate(this)) {} | |||
~MyClass() | |||
{ | |||
delete d_ptr; | |||
} | |||
void publicMethod() | |||
{ | |||
Q_D(MyClass); // d は MyClassPrivate* 型 | |||
d->privateMethod(); | |||
qDebug() << "Public method called, someData:" << d->someData; | |||
} | |||
}; | |||
</syntaxhighlight> | |||
<br> | |||
<syntaxhighlight lang="c++"> | |||
// MyClassPrivate.hファイル | |||
class MyClassPrivate | |||
{ | |||
public: | |||
MyClassPrivate(MyClass *q) : q_ptr(q) {} | |||
void privateMethod() | |||
{ | |||
Q_Q(MyClass); // qはMyClass*型 | |||
someData = 42; | |||
qDebug() << "Private method called by" << q; | |||
} | |||
MyClass *q_ptr; | |||
Q_DECLARE_PUBLIC(MyClass) | |||
int someData; | |||
}; | |||
</syntaxhighlight> | |||
<br><br> | |||
== 型に関するマクロ == | |||
==== Q_DECLARE_METATYPE ==== | |||
カスタム型を<code>QVariant</code>クラスで使用可能にするためのマクロである。<br> | |||
これにより、その型を<code>QVariant</code>クラスに格納したり、シグナル / スロットシステムで使用することができる。<br> | |||
<br> | |||
<syntaxhighlight lang="c++"> | |||
struct CustomData | |||
{ | |||
int id; | |||
QString name; | |||
}; | |||
Q_DECLARE_METATYPE(CustomData) | |||
// 使用例 | |||
void useCustomData() | |||
{ | |||
CustomData data{1, "Example"}; | |||
QVariant variant = QVariant::fromValue(data); | |||
if (variant.canConvert<CustomData>()) { | |||
CustomData retrievedData = variant.value<CustomData>(); | |||
qDebug() << "ID:" << retrievedData.id << "Name:" << retrievedData.name; | |||
} | |||
} | |||
</syntaxhighlight> | |||
<br><br> | |||
== 翻訳に関するマクロ == | |||
==== QT_TR_NOOP ==== | |||
国際化 (i18n) のために使用する。<br> | |||
<br> | |||
このマクロで囲まれた文字列は、翻訳ツールによって抽出可能になるが、実行時には通常の文字列として扱われる。<br> | |||
つまり、QT_TR_NOOPマクロは、文字列を直接翻訳せずに、後で<code>tr</code>メソッドを使用して翻訳できるようにするために使用する。<br> | |||
<br> | |||
実際に翻訳を行う場合は、<code>QObject::tr</code>メソッド (現在のロケールに基づいて適切な翻訳を返す) を使用する。<br> | |||
<br> | |||
以下の例では、は実際の翻訳ファイル(.qmファイル)をロードするため、QTranslatorクラスを使用している。<br> | |||
InternationalWidget::showMessagesメソッドを実行して、翻訳されたメッセージを表示している。<br> | |||
<br> | |||
<syntaxhighlight lang="c++"> | |||
// InternationalWidget.hファイル | |||
#include <QCoreApplication> | |||
#include <QTranslator> | |||
#include <QLocale> | |||
#include <QDebug> | |||
class InternationalWidget : public QObject | |||
{ | |||
Q_OBJECT | |||
public: | |||
InternationalWidget(QObject *parent = nullptr) : QObject(parent) {} | |||
void showMessages() | |||
{ | |||
// QT_TR_NOOPを使用して、翻訳が必要な文字列を標識付けします | |||
const char* message1 = QT_TR_NOOP("Hello, World!"); | |||
const char* message2 = QT_TR_NOOP("Welcome to Qt!"); | |||
const char* message3 = QT_TR_NOOP("Goodbye!"); | |||
// 実際に翻訳を行う際は、QObject::tr()を使用します | |||
qDebug() << "Translated messages:"; | |||
qDebug() << tr(message1); | |||
qDebug() << tr(message2); | |||
qDebug() << tr(message3); | |||
} | |||
}; | |||
</syntaxhighlight> | |||
<br> | |||
<syntaxhighlight lang="c++"> | |||
// main.cppファイル | |||
#include "InternationalWidget.h" | |||
int main(int argc, char *argv[]) | |||
{ | |||
QCoreApplication app(argc, argv); | |||
// トランスレータを設定 (実際には、翻訳ファイルが必要) | |||
QTranslator translator; | |||
if (translator.load(QLocale(), QLatin1String("myapp"), QLatin1String("_"), QLatin1String(":/translations"))) { | |||
QCoreApplication::installTranslator(&translator); | |||
} | |||
InternationalWidget widget; | |||
widget.showMessages(); | |||
return app.exec(); | |||
} | |||
</syntaxhighlight> | |||
<br> | |||
==== Q_TRANSLATE_NOOP ==== | |||
国際化 (i18n) のために使用するマクロである。<br> | |||
翻訳が必要な文字列を標識付けするために使用するが、その場では翻訳を行わない。<br> | |||
<br> | |||
文字列を翻訳ツールで認識可能にするが、実行時には元の文字列をそのまま返す。<br> | |||
後で翻訳が必要になる可能性のある文字列を準備する場合に使用する。<br> | |||
<br> | |||
一般的に、<code>QObject::tr</code>メソッドや<code>QCoreApplication::translate</code>メソッドと組み合わせて使用する。<br> | |||
<br> | |||
以下の例では、"File not found"という文字列が翻訳ツールにより抽出可能になるが、変数messageには元の英語の文字列がそのまま格納されている。<br> | |||
後で必要に応じて、QCoreApplication::translateメソッドを使用して実際の翻訳を行う。<br> | |||
<syntaxhighlight lang="c++"> | |||
const char *message = Q_TRANSLATE_NOOP("MyDialog", "File not found"); | |||
// 後で翻訳する場合 | |||
QString translatedMessage = QCoreApplication::translate("MyDialog", message); | |||
</syntaxhighlight> | |||
<br><br> | |||
== Q_ARGマクロ == | |||
<code>Q_ARG</code>マクロは、Qtフレームワークで提供されているマクロの1つであり、主に<code>QMetaObject::invokeMethod</code>メソッドと組み合わせて使用される。<br> | |||
このマクロの主な目的は、メタオブジェクトシステムを介してメソッドを呼び出す時に、引数の型と値を指定することである。<br> | |||
<br> | |||
<code>Q_ARG</code>マクロのシンタックスを以下に示す。<br> | |||
<syntaxhighlight lang="c++"> | |||
// <引数の型>は、C++の型 (int型, QStringクラス, QVariantクラス等) | |||
// <値>は、その型の具体的な値である | |||
Q_ARG(<引数の型>, <値>) | |||
</syntaxhighlight> | |||
<br> | |||
<code>Q_ARG</code>マクロは、スレッド間通信やイベントループを介したメソッド呼び出し等、直接的なメソッド呼び出しが難しい場合に特に有効である。<br> | |||
例えば、あるスレッドから別のスレッドにあるオブジェクトのメソッドを呼び出す場合等に使用される。<br> | |||
<br> | |||
以下の例では、someObjectオブジェクトのupdateValueメソッド (int型とQStringクラスの2つの引数を持つ) を呼び出している。<br> | |||
Q_ARGマクロを使用して、このメソッドの引数の型と値を指定している。<br> | |||
<syntaxhighlight lang="c++"> | |||
QMetaObject::invokeMethod(someObject, "updateValue", | |||
Qt::QueuedConnection, | |||
Q_ARG(int, 42), | |||
Q_ARG(QString, "Hello")); | |||
</syntaxhighlight> | |||
<br> | |||
<code>Q_ARG</code>マクロのメリットを以下に示す。<br> | |||
* 型安全性 | |||
*: コンパイル時に引数の型チェックが行われるため、誤った型の引数を渡すことによるランタイムエラーを防ぐことができる。 | |||
* 可変個数の引数を持つメソッドの呼び出しに対応 | |||
*: 必要な数だけQ_ARGマクロを追加することにより、任意の数の引数を持つメソッドを呼び出すことができる。 | |||
<br> | |||
ただし、<code>Q_ARG</code>マクロは、ポインタ型や参照型の引数を直接扱うことはできない。<br> | |||
ポインタ型や参照型の引数を使用する場合は、<code>QVariant</code>クラスを介して渡す必要がある。<br> | |||
<br> | |||
<code>Q_ARG</code>マクロは、Qtのシグナル / スロットシステムと密接に関連しており、Qtプログラミングにおいて柔軟なメソッド呼び出しを実現するための重要なツールの1つである。<br> | |||
<br><br> | |||
== プラットフォームに関するマクロ == | |||
* Q_OS_WINDOWS | |||
* Q_OS_LINUX | |||
* Q_OS_MACOS | |||
* Q_OS_IOS | |||
* Q_OS_ANDROID | |||
<br> | |||
上記のマクロは、特定のOS向けのコードを条件付きでコンパイルするために使用する。<br> | |||
OS固有の機能や最適化を実装する場合に、ソースコードの可読性を保ちながら異なるOS向けの処理を記述することができる。<br> | |||
<br> | |||
使用例としては、以下に示すようなケースが考えられる。<br> | |||
* ファイルシステムのパス区切り文字の違いに対応する。 | |||
* OS固有のAPIを使用する。 | |||
* GUIの外観や振る舞いをプラットフォームに合わせて調整する。 | |||
* デバイス固有の機能 (例: iOSやAndroidのセンサ) にアクセスする。 | |||
<br> | |||
<syntaxhighlight lang="c++"> | |||
// PlatformSpecificWidget.hファイル | |||
#include <QApplication> | |||
#include <QWidget> | |||
#include <QPushButton> | |||
#include <QVBoxLayout> | |||
#include <QDebug> | |||
class PlatformSpecificWidget : public QWidget | |||
{ | |||
public: | |||
PlatformSpecificWidget(QWidget *parent = nullptr) : QWidget(parent) | |||
{ | |||
QVBoxLayout *layout = new QVBoxLayout(this); | |||
QPushButton *button = new QPushButton("Click me", this); | |||
layout->addWidget(button); | |||
connect(button, &QPushButton::clicked, this, &PlatformSpecificWidget::onButtonClicked); | |||
} | |||
private slots: | |||
void onButtonClicked() | |||
{ | |||
#if defined(Q_OS_WINDOWS) | |||
qDebug() << "Hello from Windows!"; | |||
// Windows固有のAPI呼び出し等を記述 | |||
#elif defined(Q_OS_LINUX) | |||
qDebug() << "Hello from Linux!"; | |||
// Linux固有の処理を記述 | |||
#elif defined(Q_OS_MACOS) | |||
qDebug() << "Hello from macOS!"; | |||
// MacOS固有の処理を記述 | |||
#elif defined(Q_OS_IOS) | |||
qDebug() << "Hello from iOS!"; | |||
// iOS固有の処理を記述 | |||
#elif defined(Q_OS_ANDROID) | |||
qDebug() << "Hello from Android!"; | |||
// Android固有の処理を記述 | |||
#else | |||
qDebug() << "Hello from an unknown platform!"; | |||
#endif | |||
// プラットフォーム共通の処理 | |||
qDebug() << "This code runs on all platforms."; | |||
} | |||
}; | |||
</syntaxhighlight> | |||
<br> | |||
<syntaxhighlight lang="c++"> | |||
// main.cppファイル | |||
#include "PlatformSpecificWidget.h" | |||
int main(int argc, char *argv[]) | |||
{ | |||
QApplication app(argc, argv); | |||
PlatformSpecificWidget widget; | |||
widget.show(); | |||
return app.exec(); | |||
} | |||
</syntaxhighlight> | </syntaxhighlight> | ||
<br><br> | <br><br> | ||