このページでは

キューに登録されたカスタムタイプ

「キュー化されたカスタム型」の例では、キュー化されたシグナルとスロットを使用して、スレッド間でカスタム型を送信する方法を示しています。

ワーカースレッドから、色付きのブロックが順次描画されるウィンドウ

概要

この例では、値クラス `Block` を作成し、メタオブジェクトシステムに登録することで、キュー化されたシグナルとスロットを使用してそのインスタンスをスレッド間でやり取りできるようにします。

ブロッククラス

Block クラスは、メタオブジェクトシステムの要件に従い、クラスのパブリックセクションにデフォルトコンストラクタ、コピーコンストラクタ、およびデストラクタを定義しています。このクラスは、色付きの矩形を表します。

class Block
{
public:
    Block();
    Block(const Block &other);
    ~Block();

    Block(const QRect &rect, const QColor &color);

    QColor color() const;
    QRect rect() const;

private:
    QRect m_rect;
    QColor m_color;
};

Q_DECLARE_METATYPE(Block);

この型を使用するシグナル・スロットの接続を行う前に、qRegisterMetaType() テンプレート関数を呼び出して、実行時にメタオブジェクトシステムに登録する必要があります。この例では、QVariant を使用してこの型を使用する予定はありませんが、Q_DECLARE_METATYPE() を使用して新しい型を宣言しておくことも良い慣習です。

Block クラスの実装は単純であるため、ここでは省略します。

Window クラス

Block オブジェクトを受け取るパブリックスロットを持つ、単純なWindow クラスを定義します。クラスの残りの部分は、ユーザーインターフェースの管理と画像の処理を担当します。

class Window : public QWidget
{
    Q_OBJECT

public:
    Window(QWidget *parent = nullptr);
    void loadImage(const QImage &image);

public slots:
    void addBlock(const Block &block);

private slots:
    void loadImage();
    void resetUi();

private:
    QLabel *label;
    QPixmap pixmap;
    QPushButton *loadButton;
    QPushButton *resetButton;
    QString path;
    RenderThread *thread;
};

Window クラスには、RenderThread オブジェクトによって提供されるワーカースレッドも含まれています。このスレッドは、Block オブジェクトをウィンドウのaddBlock(Block) スロットに送信するためのシグナルを発信します。

Window クラスの中で最も関連性の高い部分は、コンストラクタとaddBlock(Block) スロットです。

コンストラクタは、画像をレンダリングするためのスレッドを作成し、ラベルと2つのプッシュボタンを含むユーザーインターフェースを設定します。これらのボタンは、同じクラス内のスロットに接続されています。

Window::Window(QWidget *parent)
    : QWidget(parent), thread(new RenderThread(this))
{
    label = new QLabel(this);
    label->setAlignment(Qt::AlignCenter);

    loadButton = new QPushButton(tr("&Load image..."), this);
    resetButton = new QPushButton(tr("&Stop"), this);
    resetButton->setEnabled(false);

    connect(loadButton, &QPushButton::clicked,
            this, QOverload<>::of(&Window::loadImage));
    connect(resetButton, &QPushButton::clicked,
            thread, &RenderThread::requestInterruption);
    connect(thread, &RenderThread::finished,
            this, &Window::resetUi);
    connect(thread, &RenderThread::sendBlock,
            this, &Window::addBlock);

これらの接続の最後では、RenderThread オブジェクトのシグナルを、ウィンドウのaddBlock(Block) スロットに接続します。

    ...
    setWindowTitle(tr("Queued Custom Type"));
}

コンストラクタの残りの部分では、単にウィンドウのレイアウトを設定するだけです。

addBlock(Block) スロットは、コンストラクタで設定されたシグナル・スロット接続を介して、レンダリングスレッドからブロックを受け取ります:

void Window::addBlock(const Block &block)
{
    QColor color = block.color();
    color.setAlpha(64);

    QPainter painter;
    painter.begin(&pixmap);
    painter.fillRect(block.rect(), color);
    painter.end();
    label->setPixmap(pixmap);
}

これらは、到着した順にラベルに描画するだけです。

RenderThread クラス

RenderThread クラスは画像を処理し、Block オブジェクトを作成して、sendBlock(Block) シグナルを使用して、それらをこの例の他のコンポーネントに送信します。

class RenderThread : public QThread
{
    Q_OBJECT

public:
    RenderThread(QObject *parent = nullptr);
    ~RenderThread();

    void processImage(const QImage &image);

signals:
    void sendBlock(const Block &block);

protected:
    void run();

private:
    QImage m_image;
};

コンストラクタとデストラクタについてはここでは割愛します。これらは、スレッドの内部状態の設定や、スレッドが破棄される際のクリーンアップ処理を担当します。

処理は `processImage() ` 関数によって開始され、この関数は `RenderThread ` クラスが再実装した `QThread::run()` 関数を呼び出します。

void RenderThread::processImage(const QImage &image)
{
    if (image.isNull())
        return;

    m_image = image;
    start();
}

void RenderThread::run()
{
    const int size = qMax(m_image.width()/20, m_image.height()/20);
    for (int s = size; s > 0; --s) {
        for (int c = 0; c < 400; ++c) {

画像の処理方法の詳細はさておき、ブロックを含むシグナルが通常どおり発信されることがわかります:

    ...
            const Block block(QRect(x1, y1, x2 - x1 + 1, y2 - y1 + 1),
                        QColor(red/n, green/n, blue/n));
            emit sendBlock(block);
            if (isInterruptionRequested())
                return;
            msleep(10);
        }
    }
}

送信される各信号はキューに入れられ、後でウィンドウのaddBlock(Block) スロットに配信されます。

型の登録

この例のmain() 関数では、qRegisterMetaType()テンプレート関数を呼び出すことで、Block クラスをメタオブジェクトシステムに対するカスタム型として登録しています:

intmain(intargc, char *argv[])
{
    QApplication app(argc,argv);
    qRegisterMetaType<Block>();

    Window window;
    window.show();

    window.loadImage(createImage(256, 256));
    returnapp.exec();
}

この呼び出しは、その型を使用するシグナル・スロットの接続が行われる前に、確実に型が登録されるようにするためにここに配置されています。

main() 関数の残りの部分は、擬似乱数生成器のシードの設定、ウィンドウの作成と表示、およびデフォルト画像の設定に関するものです。createImage() 関数の実装については、ソースコードを参照してください。

関連資料

この例では、スレッド間のシグナル・スロット接続で使用できるように、カスタム型をメタオブジェクトシステムに登録する方法を示しました。

実際には、Q_DECLARE_METATYPE() マクロとqRegisterMetaType() テンプレート関数の両方をカスタム型の登録に使用できますが、qRegisterMetaType() が必要となるのは、シグナル・スロット通信を行う場合、あるいは実行時にカスタム型のオブジェクトを作成・破棄する必要がある場合に限られます。

Qt でのカスタム型の使用に関する詳細は、「カスタム Qt 型の作成」ドキュメントを参照してください。

サンプルプロジェクト @ code.qt.io

© 2026 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.