How to return a value from one slot to another
-
I am facing a strange problem. I have successfully tested a threaded program running parallely. However, I wanted to add another thread within that thread like this:
worker.cpp
#include "worker.h" #include <QTimer> #include <QEventLoop> #include <QThread> #include <QDebug> #include <QUrl> #include <QNetworkRequest> #include <QNetworkReply> #include <QNetworkAccessManager> #include <QNetworkReply> #include <QNetworkRequest> #include <QJsonArray> #include <QJsonDocument> #include <QJsonObject> #include <QJsonValue> #include <QJsonValueRef> Worker::Worker(QObject *parent) : QObject(parent) { _working =false; _abort = false; } void Worker::requestWork() { mutex.lock(); _working = true; _abort = false; qDebug()<<"Request worker start in Thread "<<thread()->currentThreadId(); mutex.unlock(); emit workRequested(); } void Worker::abort() { mutex.lock(); if (_working) { _abort = true; qDebug()<<"Request worker aborting in Thread "<<thread()->currentThreadId(); } mutex.unlock(); } void Worker::syncRequestFinished(QNetworkReply *rep){ mutex.lock(); bool abort = _abort; mutex.unlock(); QString answer = rep->readAll(); qDebug() << answer; emit valueChanged(pic, str,indx); mutex.lock(); _working = false; mutex.unlock(); emit finishedLPR(); } void Worker::doWork(QPixmap pic, QString str, int indx) { qDebug()<<"Starting worker process in Thread "<<thread()->currentThreadId(); QString extract = "External API call"; QUrl url("https://vision.googleapis.com/v1/images:annotate?key=AIzaSyfbdf************PWDC7qcprU"); QNetworkAccessManager *APImanager = new QNetworkAccessManager(this); QNetworkRequest Request(url); Request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json"); Request.setRawHeader("charset", "utf-8"); connect(APImanager, SIGNAL(finished(QNetworkReply*)),this, SLOT(syncRequestFinished(QNetworkReply*))); APImanager->post(Request,json_bytes); // Set _working to false, meaning the process can't be aborted anymore. mutex.lock(); _working = false; mutex.unlock(); qDebug()<<"Worker process finished in Thread "<<thread()->currentThreadId(); }
and worker.h
#ifndef WORKER_H #define WORKER_H #include <QObject> #include <QMutex> #include <QWidget> #include <QUrl> #include <QNetworkRequest> #include <QNetworkReply> class Worker : public QObject { Q_OBJECT public: explicit Worker(QObject *parent = 0); /** * @brief Requests the process to start * * It is thread safe as it uses #mutex to protect access to #_working variable. */ void requestWork(); /** * @brief Requests the process to abort * * It is thread safe as it uses #mutex to protect access to #_abort variable. */ void abort(); private: /** * @brief Process is aborted when @em true */ bool _abort; /** * @brief @em true when Worker is doing work */ bool _working; /** * @brief Protects access to #_abort */ QMutex mutex; QString plateNum; signals: /** * @brief This signal is emitted when the Worker request to Work * @sa requestWork() */ void workRequested(); /** * @brief This signal is emitted when counted value is changed (every sec) */ void valueChanged(QPixmap pic, QString str, int indx); /** * @brief This signal is emitted when process is finished (either by counting 60 sec or being aborted) */ void finished(QNetworkReply*rep); void finishedLPR(); public slots: void doWork(QPixmap picture, QString str, int indx); void syncRequestFinished(QNetworkReply*rep, QPixmap pic, QString str, int indx); }; #endif // WORKER_H
The problem I am facing here is that when the
emit valueChanged(pic, str,indx)
emit finishedLPR()
signal is being called from
doWork
slot, its running normally. But as I have network reply dependency, I have to call it from
syncRequestFinished(QNetworkReply*rep, QPixmap pic, QString str, int indx)
slot which results empty output. Can someone tell me what I am doing wrong? Or how can I pass a value from
syncRequestFinished()
to
doWork()
efficiently? Thanks in advance.
-
I am facing a strange problem. I have successfully tested a threaded program running parallely. However, I wanted to add another thread within that thread like this:
worker.cpp
#include "worker.h" #include <QTimer> #include <QEventLoop> #include <QThread> #include <QDebug> #include <QUrl> #include <QNetworkRequest> #include <QNetworkReply> #include <QNetworkAccessManager> #include <QNetworkReply> #include <QNetworkRequest> #include <QJsonArray> #include <QJsonDocument> #include <QJsonObject> #include <QJsonValue> #include <QJsonValueRef> Worker::Worker(QObject *parent) : QObject(parent) { _working =false; _abort = false; } void Worker::requestWork() { mutex.lock(); _working = true; _abort = false; qDebug()<<"Request worker start in Thread "<<thread()->currentThreadId(); mutex.unlock(); emit workRequested(); } void Worker::abort() { mutex.lock(); if (_working) { _abort = true; qDebug()<<"Request worker aborting in Thread "<<thread()->currentThreadId(); } mutex.unlock(); } void Worker::syncRequestFinished(QNetworkReply *rep){ mutex.lock(); bool abort = _abort; mutex.unlock(); QString answer = rep->readAll(); qDebug() << answer; emit valueChanged(pic, str,indx); mutex.lock(); _working = false; mutex.unlock(); emit finishedLPR(); } void Worker::doWork(QPixmap pic, QString str, int indx) { qDebug()<<"Starting worker process in Thread "<<thread()->currentThreadId(); QString extract = "External API call"; QUrl url("https://vision.googleapis.com/v1/images:annotate?key=AIzaSyfbdf************PWDC7qcprU"); QNetworkAccessManager *APImanager = new QNetworkAccessManager(this); QNetworkRequest Request(url); Request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json"); Request.setRawHeader("charset", "utf-8"); connect(APImanager, SIGNAL(finished(QNetworkReply*)),this, SLOT(syncRequestFinished(QNetworkReply*))); APImanager->post(Request,json_bytes); // Set _working to false, meaning the process can't be aborted anymore. mutex.lock(); _working = false; mutex.unlock(); qDebug()<<"Worker process finished in Thread "<<thread()->currentThreadId(); }
and worker.h
#ifndef WORKER_H #define WORKER_H #include <QObject> #include <QMutex> #include <QWidget> #include <QUrl> #include <QNetworkRequest> #include <QNetworkReply> class Worker : public QObject { Q_OBJECT public: explicit Worker(QObject *parent = 0); /** * @brief Requests the process to start * * It is thread safe as it uses #mutex to protect access to #_working variable. */ void requestWork(); /** * @brief Requests the process to abort * * It is thread safe as it uses #mutex to protect access to #_abort variable. */ void abort(); private: /** * @brief Process is aborted when @em true */ bool _abort; /** * @brief @em true when Worker is doing work */ bool _working; /** * @brief Protects access to #_abort */ QMutex mutex; QString plateNum; signals: /** * @brief This signal is emitted when the Worker request to Work * @sa requestWork() */ void workRequested(); /** * @brief This signal is emitted when counted value is changed (every sec) */ void valueChanged(QPixmap pic, QString str, int indx); /** * @brief This signal is emitted when process is finished (either by counting 60 sec or being aborted) */ void finished(QNetworkReply*rep); void finishedLPR(); public slots: void doWork(QPixmap picture, QString str, int indx); void syncRequestFinished(QNetworkReply*rep, QPixmap pic, QString str, int indx); }; #endif // WORKER_H
The problem I am facing here is that when the
emit valueChanged(pic, str,indx)
emit finishedLPR()
signal is being called from
doWork
slot, its running normally. But as I have network reply dependency, I have to call it from
syncRequestFinished(QNetworkReply*rep, QPixmap pic, QString str, int indx)
slot which results empty output. Can someone tell me what I am doing wrong? Or how can I pass a value from
syncRequestFinished()
to
doWork()
efficiently? Thanks in advance.
@sigmind said in How to return a value from one slot to another:
QNetworkAccessManager *APImanager = new QNetworkAccessManager(this); QNetworkRequest Request(url); Request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json"); Request.setRawHeader("charset", "utf-8"); connect(APImanager, SIGNAL(finished(QNetworkReply*, QPixmap, QString, int)),this, SLOT(syncRequestFinished(QNetworkReply*, QPixmap, QString, int)));
This is copied from your worker.cpp
Check the return value of the connect and also the application output. That cannot work.QNetworkAccessManager *APImanager = new QNetworkAccessManager(this); // that is a standard Qt class connect(APImanager, SIGNAL(finished(QNetworkReply*, QPixmap, QString, int)),this, SLOT(syncRequestFinished(QNetworkReply*, QPixmap, QString, int))); // it has no signal finished with that parameter list
I have seen a signal defined in worker.h which has that parameter list. However, how should the standard class QNetworkAccessManager know this signal and even have an idea what to assign.
The signal you define in worker.h will be a signal you can emit from routines of worker.cpp.
IMHO it is easier to use the functor-based connect, that will tell you immediately that you have done something at this point.
-
Hi,
The goal of the slots is not to return values. Can you explain exactly what you are trying to achieve ?
-
Why do you need to be synchronous in that method ?
-
Again, I don't see what part of this requires that your doWork method content be synchronous.
-
@SGaist @koahnig Slightly updated my original post to make it clear.
Okey, briefly, please understand that the doWork(QPixmap pic, QString str, int indx) function takes 3 arguments and emit valueChanged(pic, str,indx) signal also returns 3 arguments. But the problem is, the doWork() slot also contains a Qt Network request, which is connected to syncRequestFinished() slot.Now, I had successfully emitted 3 arguments to the doWork() slot, the doWork() slot then take the QPixmap and call external API to OCR it. When the request finishes, I have to emit the OCR value to valueChange( ) slot along with other parameters found on doWork() slot.
I could have easily emit the valueChanged() signal from syncRequestFinished() slot, but it takes default argument, no more no less. So I found no way to emit the valueChanged() signal from there. I have also tried to declare global variable and update from slots, but I found it not synchronous.
That is why I wanted to sync it to the doWork() slot. Any suggestion would be highly appreciated. -
What about simplifying that using a lambda expression where you pass it the complementary parameters you need ? See the new connect syntax.
-
@SGaist @koahnig Slightly updated my original post to make it clear.
Okey, briefly, please understand that the doWork(QPixmap pic, QString str, int indx) function takes 3 arguments and emit valueChanged(pic, str,indx) signal also returns 3 arguments. But the problem is, the doWork() slot also contains a Qt Network request, which is connected to syncRequestFinished() slot.Now, I had successfully emitted 3 arguments to the doWork() slot, the doWork() slot then take the QPixmap and call external API to OCR it. When the request finishes, I have to emit the OCR value to valueChange( ) slot along with other parameters found on doWork() slot.
I could have easily emit the valueChanged() signal from syncRequestFinished() slot, but it takes default argument, no more no less. So I found no way to emit the valueChanged() signal from there. I have also tried to declare global variable and update from slots, but I found it not synchronous.
That is why I wanted to sync it to the doWork() slot. Any suggestion would be highly appreciated.Stupid question: Does your code compile as posted?
In worker.cpp you have
void Worker::syncRequestFinished(QNetworkReply *rep){ mutex.lock(); bool abort = _abort; mutex.unlock(); QString answer = rep->readAll(); qDebug() << answer; emit valueChanged(pic, str,indx); mutex.lock(); _working = false; mutex.unlock(); emit finishedLPR(); }
The parameters used in emit valueChanged(pic, str,indx) are neither local nor in the definition of the class nor global.