Here is the code where I use CONNECT.I use it to go to the slot slotReadyRead where i can read the content the reply.
But I have a message while debugging or running the program which is
QObject::connect: Incompatible sender/receiver arguments
QNetworkReplyImpl::readyRead() --> MainWindow::slotReadyRead(QNetworkReply*)
.cpp
void MainWindow::on_pushButton_clicked()
{
QNetworkAccessManager* manager = new QNetworkAccessManager(this);
QNetworkRequest request;
request.setUrl(QUrl("http://lascivio.co/mobile/get.php?name=marwa"));
QNetworkReply *reply = manager->get(request);
connect(reply, SIGNAL(readyRead()), this, SLOT(slotReadyRead(QNetworkReply*)));
}
void MainWindow::slotReadyRead(QNetworkReply* reply)
{
QByteArray b (reply->readAll());
QString s(b);
ui->lineEdit->setText(s);
}
.h
public slots:
void slotReadyRead(QNetworkReply* reply);
The slot needs to have a signature compatible with the signal. So either define it as:
void slotReadyRead();
Or make the reply optional:
void slotReadyRead(QNetworkReply* reply = null);
You cannot force a plug into a socket, if it is not meant to be. I see two options:
Make reply a member of MainWindow (the quick and dirty solution)
Create a new class that will have a QNetworkReply* as a member and a slot to process the data of the reply, when it is ready.
BTW: I think you want to connect(reply, SIGNAL(finished()), this, SLOT(slotProcessReply()) (documentation). And here is the HTTP example from the Qt example collection! Have a look at network/http/httpwindow.h and network/http/httpwindow.cpp
Related
I'm doing a very small and simple implementation of a protocol where my program will send a specific URL to a target machine and the target will reply with a JSON file.
I have read many examples of how to do this in QT but still I face a log message that I don't understand and I haven't been able to figure out what the problem actually is.
This is parts of my minimalistic code that sends the http request:
The main class:
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = nullptr);
~MainWindow();
private slots:
void on_connectToSiteButton_clicked();
void httpFinished();
void httpReadyRead();
signals:
private:
Ui::MainWindow *ui;
QByteArray *mByteArray;
QNetworkAccessManager *mNetMan;
QNetworkReply *reply;
};
This is the implementation of the actual sending of the network request:
void MainWindow::on_connectToSiteButton_clicked()
{
mNetMan = new QNetworkAccessManager;
// Send a Alarm status request
const QUrl ALARMLIST_URL("http://192.168.1.115/JSON.HTML?FN=ALSummary");
reply = mNetMan->get(QNetworkRequest(ALARMLIST_URL));
connect(reply, &QNetworkReply::finished, this, &MainWindow::httpFinished);
connect(reply, &QIODevice::readyRead, this, &MainWindow::httpReadyRead);
}
When I run the code and press the button I get following message in the Application output window:
QNetworkReplyHttpImplPrivate::_q_startOperation was called more than once QUrl("http://192.168.1.115/JSON.HTML?FN=ALSummary")
When I search for a solution I find only git comments but no explanation to the cause of this.
This seems to be a (meanwhile) known bug, which will be fixed in Qt 5.12.2: QTBUG-72463
I have the following code to get the response of the url using QNetworkAccessManager and using QNetworkReply for getting the response code. I am getting the onReplyfinished()slot properly while testing this in windows 8. I am not getting the onReplyfinished() while using the application in Windows 10.
NetManager.h :
class NetManager:public QNetworkAccessManager
{
Q_OBJECT
public:
NetManager(QObject* inParent = 0);
~NetManager();
public slots:
void onReplyfinished();
private:
QNetworkAccessManager *AManager;
QNetworkReply *NReply;
QString urlStr;
};
NetManager.cpp :
NetManager::NetManager( QObject* inParent ) : QNetworkAccessManager(
inParent )
{
AManager = new QNetworkAccessManager(this);
urlStr= "https://sampleurl.com/";
qDebug() << urlStr;
QUrl url(urlStr);
QNetworkRequest NetRequest((url));
NReply= AManager->get(NetRequest);
connect(NReply, SIGNAL(finished()), this, SLOT(onReplyfinished()));
}
void NetManager::onReplyfinished()
{
qDebug () << "in getting response";
}
Thanks in advance
do not forget to add
QT += network in .pro file
and also if you are receiving ssl problems do not forget to copy libcryptoand libsslinto your project directory
I'm running Qt 4.8.1
I'm trying to use QNetworkRequest to send a request and I'm getting a 'QEventLoop: Cannot be used without QApplication' error. I believe I'm running within an event loop.
void WebLoader::load()
{
QNetworkRequest request;
request.setUrl(QUrl("http://www.bbc.co.uk/"));
QNetworkAccessManager *manager = new QNetworkAccessManager();
connect(manager, SIGNAL(finished(QNetworkReply*)),
this, SLOT(checkForUpdateFinished(QNetworkReply*)));
QNetworkReply *reply = manager->get(request);
connect(reply, SIGNAL(readyRead()), this, SLOT(checkForUpdateSlot()));
}
The manager->get(reply) call never returns.
This function is being called when a menu item is clicked upon. There is QWidget::event(QEvent) in its stack trace. The application is definitely running with the rest of a complex UI working.
as variations I've tried:
using new QNetworkAccessManager(mainWindow) - mainWindow inherits from QMainWindow
using new QNetworkAccessManager(application) - application inherits from QApplication
calling load() from a customEvent
calling load() from a timer callback
[edit]
I'm now constructing the QNetworkAccessManager in the MainWindow constructor:
MainWindow::MainWindow() : queryAnalyser(NULL)
{
manager = new QNetworkAccessManager(this);
connect(manager, SIGNAL(finished(QNetworkReply*)), this, SLOT(managerFinished(QNetworkReply*)));
managerFinished is not being called.
I'm getting the debug IO:
'QObject: Cannot create children for a parent that is in a different thread.
(Parent is MainWindow(0x28fcd0), parent's thread is QThread(0x4862828), current thread is QThread(0x7d90b70)'
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
WXApplication *a = WXApplication::getApp();
MainWindow mainWin;
mainWin.show();
mainWin.checkArgs();
return app.exec();
}
Ensure that your QNetworkAccessManager is not destroyed at the end of the method which sens the request. If it is destroyed, your request is lost since the destroyed QNetworkAccessManager will not be able to send the finished() signal to the connected slot.
This is exactly what happened in the WebLoader::load(); method. The manager variable only exists during the method execution and the method will end before you will receive the reply.
What you can do is putting the QNetworkAccessManager in a global variable and use this global variable every time you need it :
Afile.hpp :
//...
#include <QNetworkAccessManager>
extern QNetworkAccessManager QNAM;
//...
Afile.cpp :
//...
#include "afile.hpp"
QNetworkAccessManager QNAM = QNetworkAccessManager();
//...
In your code (WebLoader::load(); for example) :
//...
#include "afile.hpp"
//...
QNetworkAccessManager * manager = &QNAM;
//...
In requests, set an originating object to "tag" requests and to ensure that the right methods will treat the right replies :
void WebLoader::load()
{
QNetworkRequest request;
request.setUrl(QUrl("http://www.bbc.co.uk/"));
request.setOriginatingObject(this);
QNetworkAccessManager * manager = &QNAM;
connect(manager, SIGNAL(finished(QNetworkReply*)), this, SLOT(checkForUpdateFinished(QNetworkReply*)));
manager->get(request);
}
void WebLoader::checkForUpdateFinished(QNetworkReply* reply)
{
if (reply == 0 || reply->request().originatingObject() != this)
{
return;
}
disconnect(manager, SIGNAL(finished(QNetworkReply*)), this, SLOT(checkForUpdateFinished(QNetworkReply*)));
// Reply treatment
reply->deleteLater();
// ...
}
In your MainWindow constructor, forget the this if it is not necessary or use the QNAM global variable.
I am working on an application which uploads the content of the file to server.
To upload the file to server I am using ‘QNetworkAccessManager’ class. Since it works as asynchronous way, I changed it to work as synchronous way by using QEventLoop.
Class FileTransfer
{
Public :
QNetworkAccessManager mNetworkManager;
Void Upload(QNetworkRequest request, QIODevice *data)
{
responce = mNetworkManager.put(request, data);
EventLoop.exec();
ReadResponce(responce);
}
Void Stop()
{
responce ->close();
}
}
In my sample application I have 2 windows. 1st to select the files and 2nd to show the progress.
When user click on upload button in the first window, the 2nd window will be displayed and then I create the FileTransfer object and start uploading.
While uploading the file if user closes the form then in the destructor of the window I call the stop of ‘FileTransfer’ after that I delete the ‘FileTransfer’ object.
But here the Upload() function is not yet completed so it will crash.
Please help me to:
How to wait in 'stop()' function until the Upload() function is completed
From what I can see from your code, you're executing a QEventLoop but you're not actually connecting its "quit" slot to any signal. Take the below as an example, login is a QHttp - and the code is taken from something different - but the principle applies.
/* Create the QEventLoop */
QEventLoop pause;
/* connect the QHttp.requestFinished() Signal to the QEventLoop.quit() Slot */
connect(&login, SIGNAL(requestFinished( int, bool )), &pause, SLOT(quit()));
/* The code that will run during the QEventLoop */
login.request(header,&logmein,&result);
/* Execute the QEventLoop - it will quit when the above finished due to the connect() */
pause.exec();
This could be applied to your code, if I'm not mistaken, like this...
/* connect the signal to the relevant slot */
connect(&mNetworkManager, SIGNAL(finished( QNetworkReply )), &EventLoop, SLOT(quit()));
/* Execute the code that will run during QEventLoop */
responce = mNetworkManager.put(request, data);
/* Execute the QEventLoop */
EventLoop.exec();
Apologies if I've mistaken your query! I'm only getting to grips with qt again after a break, but I believe this is what you mean! Good luck!
I think you need to add something like that in your upload function:
if (upf->openFile())
{
reply = manager->post(request, upf);
connect(reply, SIGNAL(uploadProgress(qint64,qint64)), this, SIGNAL(progress(qint64,qint64)));
connect(reply, SIGNAL(finished()), this, SLOT(replyFinished()));
isInProgress = true;
emit started();
} else
{
emit finished(true, false, tr("Error: can't open file %1").arg(filename));
}
Here is the full text code: datacod-qt-tools
Hope it help.
Personally, I would recommend to not use any of these answers.
It would be sufficient to connect a countdown latch to the signal.
So you could write:
Latch latch( 1 );
QObject::connect( reply, SIGNAL(finished()),
&latch, SLOT(countDown()) );
latch.wait();
For this you would need a wrapper:
class Latch : public QObject {
Q_OBJECT
public:
Latch( uint count );
void wait();
public slots:
void countDown();
private:
gcl::countdown_latch _latch;
};
I would like to test an asynchronous request to a webserver. For that purpose I'm creating a simple unittest to quickly try a few lines of code:
void AsynchronousCall::testGet()
{
QNetworkAccessManager *nam = new QNetworkAccessManager(this);
QUrl url("http://myownhttpserver.org");
QNetworkRequest req(url);
this->connect(nam, SIGNAL(finished(QNetworkReply*)), this, SLOT(reqFinished(QNetworkReply *)));
QNetworkReply *rep = nam->get(req);
}
void AsynchronousCall::reqFinished(QNetworkReply *rep)
{
qDebug() << rep->readAll();
qDebug() << "finshed";
}
The problem is that reqFinished() is never reached.
If I had a simple QEventLoop and and a loop.exec() just after the nam->get(req); the request is executed.
Any hint ? Do I have to use a loop.exec() in my every unittests ?
If you want to test asynchronous behavior, you have to use QEventLoop or other class with similar functionality. I suggest you write helper method like this:
bool waitForSignal(QObject *sender, const char *signal, int timeout = 1000) {
QEventLoop loop;
QTimer timer;
timer.setInterval(timeout);
timer.setSingleShot(true);
loop.connect(sender, signal, SLOT(quit()));
loop.connect(&timer, SIGNAL(timeout()), SLOT(quit()));
timer.start();
loop.exec();
return timer.isActive();
}
Then you can use it in your unit tests like this:
void AsynchronousCall::testGet()
{
QNetworkAccessManager *nam = new QNetworkAccessManager(this);
QUrl url("http://myownhttpserver.org");
QNetworkRequest req(url);
this->connect(nam, SIGNAL(finished(QNetworkReply*)), this, SLOT(reqFinished(QNetworkReply *)));
QNetworkReply *rep = nam->get(req);
QVERIFY(waitForSignal(nam, SIGNAL(finished(QNetworkReply*)), 5000));
}
There are also other issues with your test:
Tests that depend on network connection shouldn't be unit tests. You want your unit tests to be blazing fast, which is impossible to achieve with network connections.
Your test doesn't really test anything: it just puts some info to debug console. You should define expectations and verify them using QVERIFY and QCOMPARE macros.
QTest sucks IMHO. If you're creating test base from scratch, start using gtest + gmock instead.