カスタム Qt タイプの作成

概要

Qt を使ってユーザーインターフェイスを作成する場合、特に特殊なコントロールや機能を持つユーザーインターフェイスを作成する場合、開発者は Qt の既存のデータ型のセットと一緒に、またはその代わりに使用できる新しいデータ型を作成する必要があります。

QSizeQColorQString などの標準的な型は、QVariant オブジェクトに格納したり、QObject ベースのクラスでプロパティの型として使用したり、シグナルスロット通信で発行したりすることができます。

このドキュメントでは、カスタム型を取り上げ、それをQtのオブジェクトモデルに統合し、標準のQt型と同じように格納できるようにする方法を説明します。次に、カスタム型をシグナルやスロット接続で使用できるように登録する方法を示します。

カスタム型の作成

始める前に、作成するカスタム型が、QMetaType のすべての要件を満たしていることを確認する必要があります。つまり、以下の条件を満たす必要がある:

  • パブリックなデフォルトコンストラクタ
  • パブリックなコピーコンストラクタ
  • パブリックなデストラクタ。

次のMessage クラス定義には、これらのメンバが含まれています:

class Message
{
public:
    Message() = default;
    ~Message() = default;
    Message(const Message &) = default;
    Message &operator=(const Message &) = default;

    Message(const QString &body, const QStringList &headers);

    QStringView body() const;
    QStringList headers() const;

private:
    QString m_body;
    QStringList m_headers;
};

このクラスはまた、通常使用するコンストラクタと、プライベート・データを取得するために使用する2つのパブリック・メンバ関数を提供します。

QMetaTypeによる型の宣言

Message クラスを使用するためには、適切な実装が必要です。しかし、Qtの型システムは、このクラスのインスタンスをどのように保存、取得、シリアライズするかを、何らかのアシスタントなしに理解することはできません。例えば、Message の値をQVariant に格納することはできません。

Qt でカスタム型を担当するクラスはQMetaType です。このクラスに型を知らせるには、そのクラスが定義されているヘッダーファイルでQ_DECLARE_METATYPE() マクロを呼び出します:

Q_DECLARE_METATYPE(Message);

これにより、Message の値をQVariant オブジェクトに格納し、後で取り出すことができるようになります:

QVariantstored; stored.setValue(メッセージ); ... メッセージ retrieved=  qvariant_cast<Message>(stored);qDebug() << "Retrieved:" << retrieved;
retrieved=  qvariant_cast<Message>(stored);qDebug() << "Retrieved:" << retrieved;

Q_DECLARE_METATYPE ()マクロは、これらの値をシグナルの引数として使用することも可能にするが、シグナルとスロットの直接接続に限られる。カスタム・タイプをシグナルとスロットのメカニズムで一般的に使えるようにするには、いくつかの追加作業を行う必要がある。

カスタム・オブジェクトの作成と破棄

前節の宣言により、この型はシグナルとスロットの直接接続で使用できるようになりましたが、異なるスレッドのオブジェクト間で行われるような、キューイングされたシグナルとスロットの接続には使用できません。これは、メタ・オブジェクト・システムが、実行時にカスタム・タイプのオブジェクトの生成と破棄を処理する方法を知らないためです。

実行時にオブジェクトを作成できるようにするには、qRegisterMetaType ()テンプレート関数を呼び出して、メタ・オブジェクト・システムに登録します。これにより、その型を使用する最初の接続を行う前にこの関数を呼び出す限り、キューイングされたシグナル・スロット通信でもその型を使用できるようになります。

キュー・カスタム・タイプの例では、main.cpp ファイルに登録されているBlock クラスを宣言しています:

intmain(intargc, char *argv[]) { app(argc, argv[])    QApplicationapp(argc,argv);    ...
    qRegisterMetaType<Block>();
    ...returnapp.exec(); }

この型は後に、window.cpp ファイルのシグナル・スロット接続で使用される:

Window::Window(QWidget *parent)
    : QWidget(parent), thread(new RenderThread(this))
{
    ...
    connect(thread, &RenderThread::sendBlock,
            this, &Window::addBlock);
    ...
    setWindowTitle(tr("Queued Custom Type"));
}

型が登録されずにキュー接続で使用された場合、コンソールに警告が表示されます:

QObject::connect: Cannot queue arguments of type 'Block'
(Make sure 'Block' is registered using qRegisterMetaType().)

型を印刷可能にする

以下のコードのように、デバッグのためにカスタム型を印刷可能にすることは非常に便利です:

メッセージ message(body,headers);qDebug() << "Original:" << message;

これは、その型用のストリーミング演算子を作成することで実現され、多くの場合、その型のヘッダーファイルで定義される:

QDebug operator<<(QDebug dbg, const Message &message);

ここでのMessage 型の実装では、印刷可能な表現を可能な限り読みやすくするための工夫がなされている:

QDebug operator<<(QDebug dbg, const Message &message)
{
    const QList<QStringView> pieces = message.body().split(u"\r\n", Qt::SkipEmptyParts);
    if (pieces.isEmpty())
        dbg.nospace() << "Message()";
    else if (pieces.size() == 1)
        dbg.nospace() << "Message(" << pieces.first() << ")";
    else
        dbg.nospace() << "Message(" << pieces.first() << " ...)";
    return dbg;
}

デバッグ・ストリームに送られる出力は、もちろん好きなように単純にも複雑にもできる。この関数によって返される値はQDebug オブジェクトそのものであることに注意してください。しかし、これは多くの場合、QDebugmaybeSpace() メンバ関数を呼び出すことで得られます。この関数は、読みやすくするために、ストリームをスペース文字でパディングします。

さらなる読み方

Q_DECLARE_METATYPE()マクロとqRegisterMetaType()関数のドキュメントには、その使用方法と制限に関する詳細な情報が記載されています。

キュー・カスタム・タイプの例では、このドキュメントで説明されている機能を使ってカスタム・タイプを実装する方法を示しています。

Debugging Techniquesドキュメントでは、上記で説明したデバッグ・メカニズムの概要を説明しています。

© 2025 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.