自学内容网 自学内容网

Qt文档阅读笔记-Queued Custom Type Example

此篇展示了使用Qt编写多线程程序。

概述

此案例创建一Block类,用于存储数据,并且在元对象系统中注册后,在多线程中进行信号与槽函数的连接中充当参数。

Block类

在元对象系统中,注册类,需要类在public部分提供默认构造函数、拷贝构造函数、析构函数。如下所示:

 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()将类注册到元对象系统前,需要使用Q_DECLARE_METATYPE声明下新类型。

Window类

Window类的public槽函数用于接收Block对象的信号。功能包含了构造界面及图像相关处理。

 class Window : public QWidget
 {
     Q_OBJECT

 public:
     Window();
     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对象,这个是工作线程,RenderThread将发射信号,参数是Block对象,在Window类中使用addBlock(Block)槽进行接收。

在Window类的构造函数中渲染了图像,设置用户界面(2个按钮+1个label)并且进行了信号与槽的连接。

 Window::Window()
 {
     thread = new RenderThread();
     label = new QLabel();
     label->setAlignment(Qt::AlignCenter);

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

     connect(loadButton, SIGNAL(clicked()), this, SLOT(loadImage()));
     connect(resetButton, SIGNAL(clicked()), thread, SLOT(stopProcess()));
     connect(thread, SIGNAL(finished()), this, SLOT(resetUi()));
     connect(thread, SIGNAL(sendBlock(Block)), this, SLOT(addBlock(Block)));

上面最后2行代码是RenderThread对象发出的信号,其中sendBlock是本例的关键。

     ...
     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);
 }

当信号发过来,会调用到此槽函数,随后使用paint在label上画图。

RenderThread类

RenderThread类用于处理图像,创建Block对象并发送sendBlock(Block)信号。

 class RenderThread : public QThread
 {
     Q_OBJECT

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

     void processImage(const QImage &image);

 signals:
     void sendBlock(const Block &block);

 public slots:
     void stopProcess();

 protected:
     void run();

 private:
     bool m_abort;
     QImage m_image;
     QMutex mutex;
 };

首先调用processImage()函数,随后这个函数调用start()方法,调用start()后,会回调到从QThread中继承的run()方法:

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

     m_image = image;
     m_abort = false;
     start();
 }

 void RenderThread::run()
 {
     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) {

如何处理图片的,在此案例中不用太多考虑,看此函数最后,发出了sendBlock()信号了。

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

在多线程中每一个sendBlock()信号,都会被放到一个队列中,然后依次调用Window类的addBlock(Block)槽函数。

类型注册

在main()函数中使用qRegisterMetaType()函数对Block类进行注册

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

     Window window;
     window.show();

     window.loadImage(createImage(256, 256));
     return app.exec();
 }

此类注册完成后,才能在信号与槽中,作为参数使用。


原文地址:https://blog.csdn.net/qq78442761/article/details/140258136

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!