Qt cannot figure out how to pass my return value in my program

I read several articles on the Internet about how multi-threaded applications in Qt such as the article here , and I noticed Qt also updated the official documentation on this topic, however I'm still trying to figure out how I can create a stream, do some image processing and return their new QImage for updating my GUI.

What I'm trying to figure out is:

  • Where can I put the connection code, in most examples I see connections declared in the constructor of the object.

  • Why does the connect statement require so many lines to execute a single process? That is, in my case, I have a slider for changing the image saturation on QGraphicsView , I want to create a stream for processing pixel manipulation of images, and then return the formatted QPixmap to my GUI and run the rendering method to draw a new image on the canvas (I don’t think What can I update my canvas from my stream?)

Following point 2, here is the current code that I wrote for my thread (I do not subclass QThread, and I think that I am following the documentation correctly).

WorkerThread.h

 #include "sliders.h" class WorkerThread : public QObject { Q_OBJECT public: WorkerThread(); ~WorkerThread(); public slots: void modifySaturation(const int, const QPixmap); signals: void SaturationChanged(const QPixmap); private: Sliders *slider; 

};

WorkerThread.cpp

 WorkerThread::WorkerThread() { } WorkerThread::~WorkerThread() { } // Create a new Sliders object on the thread (declaring in construct would place it on the main thread?) // Call the modifySaturation() method in the slider class and store its returned QPixmap into the variable to emit it back to the GUI void WorkerThread::modifySaturation(const int value, const QPixmap image) { slider = new Sliders; QPixmap img = slider->modifySaturation(value, image); emit resultReady(img); } 

I hope that the above comments will tell you about what I want to do to fix the newly created Pixmap in the main thread, in order to bring it to the GUI.

I am having trouble writing logic to bridge the connection between my main thread and the workflow, so far I have created a QThread object called "thread" in my mainwindow.h and then in my mainwindow.cpp I do the following:

 MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow) { // Instanciate a scene object that we can draw to and then set up the ui scene = new QGraphicsScene(this); filter = new Filters; worker = new WorkerThread; ui->setupUi(this); thread = new QThread; worker->moveToThread(&thread); // This is what I am struggling to understand connect(thread, SIGNAL(started()), worker, SLOT(modifySaturation(int,QPixmap))); connect(worker, SIGNAL(SaturationChanged(QPixmap)), MainWindow, SLOT(onSaturationChanged())); } // Public slot on my main window to update the GUI void MainWindow::onSaturationChanged(QPixmap) { // image is a private member describing the current loaded image m_image = QPixmap; renderImageToCanvas(); } 

From what I read, I have to create a new thread when the task starts, but how can I:

  • Reusing this topic for several methods (changing saturation, changing brightness, changing hue ...), do I need to create a new thread for every other task (does this seem a bit more complicated)?
  • How to connect the value changed method of my saturation slider to start the calculation in a new thread and then return it to update the GUI using the OnSaturationChanged slot in my main window?
+7
c ++ multithreading qt
source share
2 answers

As you mentioned about the great article How to Really Use QThread , start by explaining code that you are not sure about breaking it.

 QThread* thread = new QThread; Worker* worker = new Worker(); worker->moveToThread(thread); connect(worker, SIGNAL(error(QString)), this, SLOT(errorString(QString))); connect(thread, SIGNAL(started()), worker, SLOT(process())); connect(worker, SIGNAL(finished()), thread, SLOT(quit())); connect(worker, SIGNAL(finished()), worker, SLOT(deleteLater())); connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater())); thread->start(); 

This code is usually placed in an object in the main thread, possibly in MainWindow: -

Create a new thread object - QThread is actually more of a thread controller than a thread

 QThread* thread = new QThread; 

Create a new work object. This is an object that will work in another thread. Since this can be moved to another stream, note that you can create multiple objects and move them to the same stream.

 Worker* worker = new Worker(); 

Move the object and its children to a new stream

 worker->moveToThread(thread); 

Set up useful connections for monitoring and managing your work. Let's start with any mistakes, so we know if the worker had a problem

 connect(worker, SIGNAL(error(QString)), this, SLOT(errorString(QString))); 

To begin processing the worker’s object, we connect the initial () stream signal to the worker’s process () slot. In your example, the process will be a modifySaturation slot

 connect(thread, SIGNAL(started()), worker, SLOT(process())); 

When the worker finishes processing, if this is the only object, he needs to exit and clear, so the thread must exit

 connect(worker, SIGNAL(finished()), thread, SLOT(quit())); 

To tidy up, now both the worker and the stream are no longer needed, make sure they are cleaned after themselves

 connect(worker, SIGNAL(finished()), worker, SLOT(deleteLater())); connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater())); 

Finally, let us go to the thread-> start () call, which initiates the initial start () signal that we previously connected to the worker process () function

 thread->start(); 

With all this in mind, let me solve the questions posed: -

1 How can I reuse this thread for several methods (changing saturation, changing brightness, changing hue ...), I need to create a new stream for every other task (it seems a little more complicated)?

No, you do not need a new thread for each method. You can either use the current object or expand it to do all the processing, manage it through signals and slots from the main thread, or you could create a separate object for each method and move all of them to a new thread.

If you are using multiple objects that have been moved to a new thread, make sure that you have not connected a completed object () signal to call quit () on the stream if other objects are still using this stream. However, you still need to clear the objects and the stream when you are done with them.

2 Why does a join statement require so many lines to execute a single process? those. in my case, I have a slider for changing the saturation of the image in QGraphicsView, I want to create a stream for processing manipulations with image pixels, and then return the formatted QPixmap to my GUI and start the rendering method to draw a new image on the canvas (I don’t think that can I update my canvas from my stream?)

The general rule is that you can only update graphic objects (widgets, graphic elements, etc.) from the main stream. (There is an exception, but it is beyond the scope of this discussion and does not matter here.)

When using only one object from several connection signals, three are used to delete objects upon completion, one for processing error messages and final connection ensures that the work object starts from the beginning of the stream.

Nothing prevents you from changing this by creating your stream and first starting it, creating work objects, connecting the corresponding signals and then moving them to the stream, but you need to get workers to start doing something, for example, processing saturation as soon as they are transferred to new stream.

 QThread* pThread = new QThread; pThread->start(); Worker* worker1 = new Worker(); Worker* worker2 = new Worker(); Worker* worker3 = new Worker(); worker1->moveToThread(pThread); worker2->moveToThread(pThread); worker3->moveToThread(pThread); 

Work objects are moved here to a new thread that is running. However, work objects are inactive. Without a connection, we can call the slot that needs to be called. Suppose a process slot accepts an integer parameter ...

 QMetaObject::invokeMethod( worker1, "process", Q_ARG( int, param ) ); QMetaObject::invokeMethod( worker2, "process", Q_ARG( int, param ) ); QMetaObject::invokeMethod( worker3, "process", Q_ARG( int, param ) ); 

So, as you see here, you do not always need to connect the signals, but it is convenient.

+7
source share

I will answer one of your questions because Merlin did a good job with the rest.

how can I connect the value changed method of my saturation slider to launch the computation on a new thread and then return it to update the GUI using the OnSaturationChanged slot in my main window?

Well, for example, in the MainWindow::OnSaturationChanged you can emit a signal that passes the QImage and slider value to your stream. This signal will be connected to the slot of your WorkerThread , which performs some image manipulation.

mainwindow.h

 public slots: void addNewImage(QImage image); signals: void requestImageUpdate(QImage image, int sliderValue); 

mainwindow.cpp

  //in your MainWindow constructor or wherever you create your worker... connect(this, SIGNAL(requestImageUpdate(QImage, int)), worker, SLOT(updateImage(QImage, int))); connect(worker, SIGNAL(imageUpdated(QImage)), this, SLOT(addNewImage(QImage))); ... void MainWindow::OnSaturationChanged() { emit requestImageUpdate(myImage, slider->value()); } void MainWindow::addNewImage(QImage image) { //update the image in your graphics view or do whatever you want to do with it } 

workerthread.h

 public slots: void updateImage(QImage image, int sliderValue); signals: void imageUpdated(QImage newImage); 

workerthread.cpp

 void WorkerThread::updateImage(QImage image, int sliderValue) { QImage newImage; // you might no need this, this is just an example .... emit imageUpdated(newImage); } 

PS Use QPixmap only in the main thread. In other threads, use QImage .

+2
source share

All Articles