概要
Qtにおけるプリプロセッサは、標準的なC++プリプロセッサを拡張して、Qtフレームワークに特化した機能を提供している。
この拡張により、開発者はより効率的にQtアプリケーションを作成できるようになる。
また、クロスプラットフォームアプリケーションの開発がより効率的かつ柔軟になっている。
Qt独自のプリプロセッサの主な特徴として、メタオブジェクトシステムのサポートが挙げられる。
これは、Qtの中核をなす機能であり、シグナル / スロットのメカニズムやプロパティシステムを可能にするものである。
Q_OBJECT
マクロは、このメタオブジェクトシステムの中心的な要素である。
このマクロをクラス定義に含めることにより、そのクラスにQtのメタオブジェクト機能が追加される。
これにより、シグナル / スロットの宣言、動的なプロパティの追加、実行時型情報 (RTTI) の拡張等が可能になる。
プリプロセッサは、Q_PROPERTY
マクロを使用してクラスのプロパティを宣言する機能も提供している。
これにより、Qtのプロパティシステムを利用でき、GUIデザイナーツールとの連携、QML (Qt Modeling Language) でのプロパティバインディングが容易になる。
また、Qtのプリプロセッサは、プラットフォーム依存のコードを簡単に記述できるようにする機能も備えている。
例えば、Q_OS_*マクロを使用することにより、特定のOS向けのコードを条件付きでコンパイルすることができる。
さらに、国際化 (i18n) のサポートも重要な機能の1つである。
QT_TR_NOOP
やQ_TRANSLATE_NOOP
等のマクロを使用することにより、翻訳可能な文字列を簡単にマークアップすることができる。
これらの機能に加えて、Qtのプリプロセッサは、シグナル / スロットの接続を最適化するためのプライベートシグナル、メモリ管理を支援するためのスマートポインタマクロ等、
様々な便利な機能を提供している。
Qtのプリプロセッサは、moc (Meta-Object Compiler) と呼ばれるツールと密接に連携している。
mocは、Qtのマクロを含むヘッダファイルを解析して、必要なメタオブジェクトコードを生成する。
このプロセスは、一般的に、ビルドシステムにより自動的に処理されるため、開発者は特別な操作を行う必要はない。
QT_VERSION_CHECKマクロ
QT_VERSION_CHECK
マクロを使用する場合は、QtGlobal
をインクルードする必要がある。
このヘッダファイルには、QT_VERSION_CHECK
マクロを含む多くのQtの基本的な定義が含まれている。
#include <QtGlobal>
クラスに関するマクロ
Q_OBJECT
Qtのメタオブジェクトシステムの中核となるマクロである。
QObject
クラスを継承するサブクラスの定義内で使用され、シグナル / スロットのメカニズム、実行時型情報 (RTTI)、動的プロパティシステムを有効にする。
このマクロを使用することにより、クラスはQtの多くの高度な機能を使用できるようになる。
Q_PROPERTY
クラスのプロパティを宣言するために使用する。
このマクロを使用することにより、C++のメンバ変数をQtのプロパティシステムに統合できる。
これにより、QMLでのプロパティバインディングやGUIデザイナーでのプロパティ編集が可能になる。
また、プロパティの読み取り / 書き込みメソッド、通知シグナル、リセットメソッド等も定義できる。
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);
};
Q_INVOKABLE
このマクロをメソッド宣言の前に付加することにより、そのメソッドをQMLから呼び出し可能にする。
一般的に、publicスロットは自動的にQMLから呼び出せるが、publicメソッドはQ_INVOKABLE
を使用しない限り呼び出せない。
signals / Q_SIGNAL / Q_SIGNALS
シグナルを宣言するために使用する。
シグナルは、オブジェクト間の通信メカニズムの一部であり、特定のイベントが発生したことを他のオブジェクトに通知するために使用する。
slots / Q_SLOT / Q_SLOTS
スロットを宣言するために使用する。
スロットはシグナルに接続可能な特殊な関数であり、シグナルが発信されたときに呼び出される。
Q_EMIT
シグナルを発信 (emit) する場合に使用するマクロである。 本質的には、C++のソースコード内でシグナルを発信するための構文的な装飾である。
シグナルを発信する場合は、明示的にそれがシグナルの発信であることを示す。
通常は、emit
キーワードとして使用するが、Q_EMIT
はその完全修飾名である。
コンパイル時には何も行わず、コードの可読性を向上させる目的で使用する。
class MyClass : public QObject
{
Q_OBJECT
signals:
void valueChanged(int newValue);
public:
void updateValue(int value)
{
Q_EMIT valueChanged(value);
// または、emit valueChanged(value); としてもよい
}
};
Q_ENUMマクロ
列挙型をQtのメタオブジェクトシステムに登録するために使用する。
これにより、列挙型の値を文字列に変換する、または、QMLで使用したりすることが可能になる。
Q_DECLARE_METATYPE
カスタム型をQVariant
クラスで使用可能にするためのマクロである。
これにより、その型をQVariant
クラスに格納したり、シグナル / スロットシステムで使用することができる。
翻訳に関するマクロ
QT_TR_NOOP
国際化 (i18n) のために使用する。
このマクロで囲まれた文字列は、翻訳ツールによって抽出可能になるが、実行時には通常の文字列として扱われる。
Q_TRANSLATE_NOOP
国際化 (i18n) のために使用するマクロである。
翻訳が必要な文字列を標識付けするために使用するが、その場では翻訳を行わない。
文字列を翻訳ツールで認識可能にするが、実行時には元の文字列をそのまま返す。
後で翻訳が必要になる可能性のある文字列を準備する場合に使用する。
一般的に、QObject::tr
メソッドやQCoreApplication::translate
メソッドと組み合わせて使用する。
以下の例では、"File not found"という文字列が翻訳ツールにより抽出可能になるが、変数messageには元の英語の文字列がそのまま格納されている。
後で必要に応じて、QCoreApplication::translateメソッドを使用して実際の翻訳を行う。
const char *message = Q_TRANSLATE_NOOP("MyDialog", "File not found");
// 後で翻訳する場合
QString translatedMessage = QCoreApplication::translate("MyDialog", message);
Q_ARGマクロ
Q_ARG
マクロは、Qtフレームワークで提供されているマクロの1つであり、主にQMetaObject::invokeMethod
メソッドと組み合わせて使用される。
このマクロの主な目的は、メタオブジェクトシステムを介してメソッドを呼び出す時に、引数の型と値を指定することである。
Q_ARG
マクロのシンタックスを以下に示す。
// <引数の型>は、C++の型 (int型, QStringクラス, QVariantクラス等)
// <値>は、その型の具体的な値である
Q_ARG(<引数の型>, <値>)
Q_ARG
マクロは、スレッド間通信やイベントループを介したメソッド呼び出し等、直接的なメソッド呼び出しが難しい場合に特に有効である。
例えば、あるスレッドから別のスレッドにあるオブジェクトのメソッドを呼び出す場合等に使用される。
以下の例では、someObjectオブジェクトのupdateValueメソッド (int型とQStringクラスの2つの引数を持つ) を呼び出している。
Q_ARGマクロを使用して、このメソッドの引数の型と値を指定している。
QMetaObject::invokeMethod(someObject, "updateValue",
Qt::QueuedConnection,
Q_ARG(int, 42),
Q_ARG(QString, "Hello"));
Q_ARG
マクロのメリットを以下に示す。
- 型安全性
- コンパイル時に引数の型チェックが行われるため、誤った型の引数を渡すことによるランタイムエラーを防ぐことができる。
- 可変個数の引数を持つメソッドの呼び出しに対応
- 必要な数だけQ_ARGマクロを追加することにより、任意の数の引数を持つメソッドを呼び出すことができる。
ただし、Q_ARG
マクロは、ポインタ型や参照型の引数を直接扱うことはできない。
ポインタ型や参照型の引数を使用する場合は、QVariant
クラスを介して渡す必要がある。
Q_ARG
マクロは、Qtのシグナル / スロットシステムと密接に関連しており、Qtプログラミングにおいて柔軟なメソッド呼び出しを実現するための重要なツールの1つである。