キュー・カスタム・タイプ

キューに入れられたカスタム・タイプの例では、キューに入れられたシグナルとスロットを持つスレッド間でカスタム・タイプを送信する方法を示している。

概要

この例では、値クラス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 クラスの実装は些細なものなので、ここでの引用は避ける。

ウィンドウ・クラス

Block オブジェクトを受け取るpublicスロットを持つ単純な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[]) { app(argc, argv[])    QApplicationapp(argc,argv);    qRegisterMetaType<Block>();

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

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

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

参考文献

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

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

Qt でのカスタム型の使用に関する詳細は、「Creating Custom Qt Types(カスタム Qt 型の作成)」を参照してください。

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

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