Benutzerdefinierter Typ in der Warteschlange
Das Beispiel „Benutzerdefinierter Typ in der Warteschlange“ zeigt, wie benutzerdefinierte Typen mithilfe von Signalen und Slots in der Warteschlange zwischen Threads übertragen werden können.

Übersicht
In diesem Beispiel erstellen wir eine Wertklasse, „ Block “, und registrieren sie im Metaobjektsystem, um Instanzen dieser Klasse mithilfe von Signalen und Slots in der Warteschlange zwischen Threads zu übertragen.
Die Blockklasse
Die Klasse ` Block ` stellt im öffentlichen Bereich der Klasse den Standardkonstruktor, den Kopierkonstruktor und einen Destruktor bereit, wie vom Metaobjektsystem gefordert. Die Klasse beschreibt ein farbiges Rechteck.
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);Wir müssen sie dennoch zur Laufzeit beim Metaobjektsystem registrieren, indem wir die Template-Funktion ` qRegisterMetaType()` aufrufen, bevor wir Signal-Slot-Verbindungen herstellen, die diesen Typ verwenden. Auch wenn wir in diesem Beispiel nicht vorhaben, den Typ mit ` QVariant ` zu verwenden, ist es empfehlenswert, den neuen Typ zusätzlich mit ` Q_DECLARE_METATYPE()` zu deklarieren.
Die Implementierung der Klasse ` Block ` ist trivial, daher verzichten wir hier auf eine Darstellung.
Die Window-Klasse
Wir definieren eine einfache Klasse „ Window “ mit einem öffentlichen Slot, der ein „ Block “-Objekt akzeptiert. Der Rest der Klasse befasst sich mit der Verwaltung der Benutzeroberfläche und der Verarbeitung von Bildern.
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;
};Die Klasse ` Window ` enthält außerdem einen Worker-Thread, der von einem ` RenderThread `-Objekt bereitgestellt wird. Dieser sendet Signale, um ` Block `-Objekte an den Slot ` addBlock(Block) ` des Fensters zu übermitteln.
Die relevantesten Teile der Klasse „ Window “ sind der Konstruktor und der Slot „ addBlock(Block) “.
Der Konstruktor erstellt einen Thread zum Rendern von Bildern und richtet eine Benutzeroberfläche ein, die ein Label und zwei Drucktasten enthält, die mit Slots derselben Klasse verbunden sind.
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);Bei der letzten dieser Verbindungen verknüpfen wir ein Signal des „ RenderThread “-Objekts mit dem Slot „ addBlock(Block) “ im Fenster.
...
setWindowTitle(tr("Queued Custom Type"));
}Der Rest des Konstruktors dient lediglich dazu, das Layout des Fensters festzulegen.
Der Slot „ addBlock(Block) “ empfängt Blöcke vom Rendering-Thread über die im Konstruktor eingerichtete Signal-Slot-Verbindung:
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);
}Wir zeichnen diese einfach auf das Label, sobald sie eintreffen.
Die Klasse „RenderThread“
Die Klasse „ RenderThread “ verarbeitet ein Bild, erstellt „ Block “-Objekte und sendet diese mithilfe des Signals „ sendBlock(Block) “ an andere Komponenten im Beispiel.
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;
};Der Konstruktor und der Destruktor werden hier nicht wiedergegeben. Diese sorgen für die Einrichtung des internen Zustands des Threads und für die Bereinigung, wenn dieser zerstört wird.
Die Verarbeitung wird mit der Funktion ` processImage() ` gestartet, die die Neuimplementierung der Funktion ` QThread::run()` der Klasse ` RenderThread ` aufruft:
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) {Lassen wir die Details der Bildverarbeitung einmal außer Acht, so sehen wir, dass das Signal, das einen Block enthält, auf die übliche Weise ausgesendet wird:
...
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);
}
}
}Jedes ausgegebene Signal wird in eine Warteschlange gestellt und später an den Slot „ addBlock(Block) “ des Fensters übermittelt.
Registrierung des Typs
In der Funktion ` main() ` des Beispiels registrieren wir die Klasse ` Block ` als benutzerdefinierten Typ im Metaobjektsystem, indem wir die Template-Funktion ` qRegisterMetaType()` aufrufen:
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
qRegisterMetaType<Block>();
Window window;
window.show();
window.loadImage(createImage(256, 256));
return app.exec();
}Dieser Aufruf wird hier eingefügt, um sicherzustellen, dass der Typ registriert ist, bevor Signal-Slot-Verbindungen hergestellt werden, die ihn verwenden.
Der Rest der Funktion „ main() “ befasst sich mit der Festlegung eines Startwerts für den Pseudozufallszahlengenerator, der Erstellung und Anzeige des Fensters sowie der Festlegung eines Standardbildes. Die Implementierung der Funktion „ createImage() “ finden Sie im Quellcode.
Weiterführende Literatur
Dieses Beispiel hat gezeigt, wie ein benutzerdefinierter Typ im Metaobjektsystem registriert werden kann, damit er für Signal-Slot-Verbindungen zwischen Threads verwendet werden kann.
In der Praxis können sowohl das Makro ` Q_DECLARE_METATYPE()` als auch die Template-Funktion ` qRegisterMetaType()` zur Registrierung benutzerdefinierter Typen verwendet werden, wobei ` qRegisterMetaType()` nur erforderlich ist, wenn Sie Signal-Slot-Kommunikation durchführen oder Objekte des benutzerdefinierten Typs zur Laufzeit anlegen und löschen müssen.
Weitere Informationen zur Verwendung benutzerdefinierter Typen mit Qt finden Sie im Dokument „Erstellen benutzerdefinierter Qt-Typen “.
© 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.