Error POSTing data with Qt - qt

I want to POST data to a PHP form using this code, but after compiling I have message:
Object::connect: No such signal NetworkReplyImpl::finished(QNetworkReply*):
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent)
{
QUrl params;
QUrl url("localhost/test2.php");
params.addQueryItem("name","aaa");
params.addQueryItem("country","bbb");
QByteArray data;
data.append(params.toString());
data.remove(0,1);
QNetworkAccessManager *manager = new QNetworkAccessManager(this);
QNetworkReply *reply = manager->post(QNetworkRequest(url), data);
connect(reply, SIGNAL(finished(QNetworkReply*)), this,SLOT(replyFinished(QNetworkReply*)));
}
MainWindow::~MainWindow()
{
}
void MainWindow::replyFinished(QNetworkReply *reply)
{
QString data = reply->readAll().trimmed();
qDebug() << data;
}

The message says it quite clear: QNetworkReply doesn't have a signal finished(QNetworkReply*). It does however have a signal finished(), which takes no arguments. You can't pass the reply this way.

Related

QNetworkReply finished signal slot not emitting on Windows 10

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

QT downloading large file error

When I try to downloading file up to 50mb example, no problem, but with a big files give the following error
void MainWindow::downloadFile() {
QNetworkRequest requests;
requests.setUrl(QUrl("https://urlToFile"));
QSslConfiguration configSsl = QSslConfiguration::defaultConfiguration();
configSsl.setProtocol(QSsl::AnyProtocol);
requests.setSslConfiguration(configSsl);
QNetworkAccessManager *manager5 = new QNetworkAccessManager(this);
QNetworkReply *reply5;
reply5 = manager5->get( requests );
connect(manager5, SIGNAL(finished(QNetworkReply*)), this, SLOT(downloadFinished(QNetworkReply*)));
}
void MainWindow::downloadFinished(QNetworkReply *data) {
QFile localFile("fileName");
if (!localFile.open(QIODevice::WriteOnly))
return;
localFile.write(data->readAll());
localFile.close();
}
In your code, You are holding the whole file in memory until the download process finishes (that is when QNetworkAccessManager::finished() signal gets emitted). Of course, this is not the best way to deal with large files.
Remember that QNetworkReply is a QIODevice. This means that you should use the readyRead() signal to save data chunks to the disk as soon as they are received from the network, in order to avoid holding the whole file in memory until the download is finished.
Here is a minimal complete example:
#include <QtNetwork>
int main(int argc, char* argv[]){
QCoreApplication a(argc, argv);
QNetworkAccessManager nam;
QFile file("downloadedFile.xxx");
if(!file.open(QIODevice::ReadWrite)) return 1;
QNetworkRequest request(QUrl("http://download_url/..."));
QNetworkReply* reply = nam.get(request);
QObject::connect(reply, &QNetworkReply::readyRead, [&]{
//this will be called every time a chunk of data is received
QByteArray data= reply->readAll();
qDebug() << "received data of size: " << data.size();
file.write(data);
});
//use the finished signal from the reply object to close the file
//and delete the reply object
QObject::connect(reply, &QNetworkReply::finished, [&]{
qDebug() << "finished downloading";
QByteArray data= reply->readAll();
file.write(data);
file.close();
reply->deleteLater();
a.quit();
});
return a.exec();
}
Update:
I have wrapped the whole thing in a class FileDownloader, which can be used to download a file using QNetworkAccessManager, Here is an example of using this class:
#include <QtWidgets>
#include <QtNetwork>
//downloads one file at a time, using a supplied QNetworkAccessManager object
class FileDownloader : public QObject{
Q_OBJECT
public:
explicit FileDownloader(QNetworkAccessManager* nam, QObject* parent= nullptr)
:QObject(parent),nam(nam)
{
}
~FileDownloader(){
//destructor cancels the ongoing dowload (if any)
if(networkReply){
a_abortDownload();
}
}
//call this function to start downloading a file from url to fileName
void startDownload(QUrl url, QString fileName){
if(networkReply) return;
destinationFile.setFileName(fileName);
if(!destinationFile.open(QIODevice::WriteOnly)) return;
emit goingBusy();
QNetworkRequest request(url);
networkReply= nam->get(request);
connect(networkReply, &QIODevice::readyRead, this, &FileDownloader::readData);
connect(networkReply, &QNetworkReply::downloadProgress,
this, &FileDownloader::downloadProgress);
connect(networkReply, &QNetworkReply::finished,
this, &FileDownloader::finishDownload);
}
//call this function to abort the ongoing download (if any)
void abortDownload(){
if(!networkReply) return;
a_abortDownload();
emit backReady();
}
//connect to the following signals to get information about the ongoing download
Q_SIGNAL void downloadProgress(qint64 bytesReceived, qint64 bytesTotal);
Q_SIGNAL void downloadSuccessful();
Q_SIGNAL void downloadError(QString errorString);
//the next two signals are used to indicate transitions between busy and
//ready states of the file downloader, they can be used to update the GUI
Q_SIGNAL void goingBusy();
Q_SIGNAL void backReady();
private:
Q_SLOT void readData(){
QByteArray data= networkReply->readAll();
destinationFile.write(data);
}
Q_SLOT void finishDownload(){
if(networkReply->error() != QNetworkReply::NoError){
//failed download
a_abortDownload();
emit downloadError(networkReply->errorString());
} else {
//successful download
QByteArray data= networkReply->readAll();
destinationFile.write(data);
destinationFile.close();
networkReply->deleteLater();
emit downloadSuccessful();
}
emit backReady();
}
//private function, cleans things up when the download is aborted
//(due to an error or user interaction)
void a_abortDownload(){
networkReply->abort();
networkReply->deleteLater();
destinationFile.close();
destinationFile.remove();
}
QNetworkAccessManager* nam;
QUrl downloadUrl;
QFile destinationFile;
QPointer<QNetworkReply> networkReply;
};
//A sample GUI application that uses the above class
class Widget : public QWidget{
Q_OBJECT
public:
explicit Widget(QWidget* parent= nullptr):QWidget(parent){
layout.addWidget(&lineEditUrl, 0, 0);
layout.addWidget(&buttonDownload, 0, 1);
layout.addWidget(&progressBar, 1, 0);
layout.addWidget(&buttonAbort, 1, 1);
layout.addWidget(&labelStatus, 2, 0, 1, 2);
lineEditUrl.setPlaceholderText("URL to download");
connect(&fileDownloader, &FileDownloader::downloadSuccessful,
this, &Widget::downloadFinished);
connect(&fileDownloader, &FileDownloader::downloadError,
this, &Widget::error);
connect(&fileDownloader, &FileDownloader::downloadProgress,
this, &Widget::updateProgress);
connect(&buttonDownload, &QPushButton::clicked,
this, &Widget::startDownload);
connect(&buttonAbort, &QPushButton::clicked,
this, &Widget::abortDownload);
showReady();
//use goingBusy() and backReady() from FileDownloader signals to update the GUI
connect(&fileDownloader, &FileDownloader::goingBusy, this, &Widget::showBusy);
connect(&fileDownloader, &FileDownloader::backReady, this, &Widget::showReady);
}
~Widget() = default;
Q_SLOT void startDownload(){
if(lineEditUrl.text().isEmpty()){
QMessageBox::critical(this, "Error", "Enter file Url", QMessageBox::Ok);
return;
}
QString fileName =
QFileDialog::getSaveFileName(this, "Destination File");
if(fileName.isEmpty()) return;
QUrl url= lineEditUrl.text();
fileDownloader.startDownload(url, fileName);
}
Q_SLOT void abortDownload(){
fileDownloader.abortDownload();
}
Q_SLOT void downloadFinished(){
labelStatus.setText("Download finished successfully");
}
Q_SLOT void error(QString errorString){
labelStatus.setText(errorString);
}
Q_SLOT void updateProgress(qint64 bytesReceived, qint64 bytesTotal){
progressBar.setRange(0, bytesTotal);
progressBar.setValue(bytesReceived);
}
private:
Q_SLOT void showBusy(){
buttonDownload.setEnabled(false);
lineEditUrl.setEnabled(false);
buttonAbort.setEnabled(true);
labelStatus.setText("Downloading. . .");
}
Q_SLOT void showReady(){
buttonDownload.setEnabled(true);
lineEditUrl.setEnabled(true);
buttonAbort.setEnabled(false);
progressBar.setRange(0,1);
progressBar.setValue(0);
}
QGridLayout layout{this};
QLineEdit lineEditUrl;
QPushButton buttonDownload{"Start Download"};
QProgressBar progressBar;
QPushButton buttonAbort{"Abort Download"};
QLabel labelStatus{"Idle"};
QNetworkAccessManager nam;
FileDownloader fileDownloader{&nam};
};
int main(int argc, char* argv[]){
QApplication a(argc, argv);
Widget w;
w.show();
return a.exec();
}
#include "main.moc"

QNetworkAccessManager returning empty results

I am struggling with qnetworkaccessmanager for quite sometime. I googled a lot, but I donot find a solution for this.
I am creating a client using qaccessmanager to talk with a rest server. QNetworkReply is not returning any results. The server is working properly but the client is not returning results. On top of that the server gets called 3 times and sometimes the server is crashing. Hope some one can figure out what is going wrong. I am attaching the client code.
I tried different approches like connecting finished signal of networkaccessmanager, qnetworkreply e.t.c. But all of them ends up in giving the same error "Connection Closed" or the readAll bytearray being empty.
void RestClientCore::ConnectToServer()
{
m_NetworkManager = new QNetworkAccessManager(this);
QUrl url("http://localhost");
url.setPort(5432);
QByteArray postData;
postData.append("/?userid=user");
postData.append("&site=site");
QNetworkReply *reply = m_NetworkManager->post(request,postData);
connect(reply, SIGNAL(readyRead()),this, SLOT(slotReadyRead()));
connect(reply, SIGNAL(finished()), this, SLOT(onRequestCompleted()));
}
void RestClientCore::onRequestCompleted() {
QNetworkReply *reply = qobject_cast<QNetworkReply *>(sender());
if(reply->error())
{
qDebug() <<reply->bytesAvailable() << reply->errorString();
}
else
{
qDebug() << reply->readAll();
}
reply->deleteLater();
}
void RestClientCore::slotReadyRead()
{
QNetworkReply *reply = qobject_cast<QNetworkReply *>(sender());
qDebug() << reply->readAll();
}
Thanks in advance
Regards
Rejo

QNetworkAccessManager does not return any data

I have come across bug that I am not able to see myself. After studing QT and stack sites I wrote following code:
void RateOfExchangeGetter::run(){
mRunning = true;
mAccessManager = new QNetworkAccessManager();
//connect(mAccessManager, SIGNAL(finished(QNetworkReply*)),
// this, SLOT(replyFinished(QNetworkReply*)));
while(mRunning){
QNetworkReply *reply;
for(SiteParser *parser: mSiteParsers){
QNetworkRequest request(QUrl("https://www.google.pl/"));
request.setRawHeader("User-Agent", "MyOwnBrowser 1.0");
qDebug() << "here";
reply = mAccessManager->get(request);
parser->setQNetworkReply(reply);
connect(reply, SIGNAL(readyRead()), parser, SLOT(slotReadyRead()));
connect(reply, SIGNAL(error(QNetworkReply::NetworkError)),
parser, SLOT(slotError(QNetworkReply::NetworkError)));
connect(reply, SIGNAL(sslErrors(QList<QSslError>)),
parser, SLOT(slotSslErrors(QList<QSslError>)));
}
//for test only ->
this->sleep(10);
QByteArray array = reply->read(50);
qDebug() << array;
}
}
As good eye might have already noticed - this code is placed in class that inherits QThread.
For some reason (that I cannot find) I can't receive any data from get function (I know that it is asynchronous), no signals are transmitted, and also after waiting 10 second there are no data available in read. I had also tried to get data via finished signal from QNetworkAccessManager itself but also nothing appeared.
Thanks to anyone who might have a clue what is happening.
You don't have an event loop in your thread's run() method, so there's no chance of any networking code working.
You should put all of your code into a QObject, and move it to a generic thread. The default implementation of QThread::run() spins an event loop.
I also don't see much reason for there to be more than one parser. You can simply let the QNetworkReply accumulate the response in its internal buffer until the request is finished - you can then parse it all in one go, obviating the need for parser state. Use the finished slot instead of readyRead. The readyRead slot only makes sense for large requests.
Below is how it might be done. Note the arming mechanism to prevent races between the worker thread and the main thread. You're guaranteed that the finishedAllRequests signal will be emitted exactly once after a call to arm(). Without this mechanism, the worker thread might be able to process all requests before the connect has a chance to run, and no signal will reach the recipient, or you might get multiple signals as the requests are processed before the next one is added.
#include <QCoreApplication>
#include <QNetworkAccessManager>
#include <QNetworkRequest>
#include <QNetworkReply>
#include <QPointer>
#include <QSslError>
#include <QThread>
#include <QMetaMethod>
#include <QDebug>
class Parser : public QObject {
Q_OBJECT
bool m_armed;
QList<QNetworkReply*> m_replies;
QPointer<QNetworkAccessManager> m_manager;
QMetaMethod m_addRequestImpl, m_armImpl;
Q_SLOT void finished() {
QNetworkReply * reply = static_cast<QNetworkReply*>(sender());
Q_ASSERT(m_replies.contains(reply));
qDebug() << "reply" << reply << "is finished";
// ... use the data
m_replies.removeAll(reply);
if (m_armed && m_replies.isEmpty()) {
emit finishedAllRequests();
m_armed = false;
}
}
Q_SLOT void error(QNetworkReply::NetworkError) {
QNetworkReply * reply = static_cast<QNetworkReply*>(sender());
m_replies.removeAll(reply);
}
Q_SLOT void sslErrors(QList<QSslError>) {
QNetworkReply * reply = static_cast<QNetworkReply*>(sender());
m_replies.removeAll(reply);
}
Q_INVOKABLE void addRequestImpl(const QNetworkRequest & req) {
QNetworkReply * reply = m_manager->get(req);
connect(reply, SIGNAL(finished()), SLOT(finished()));
connect(reply, SIGNAL(error(QNetworkReply::NetworkError)),
SLOT(error(QNetworkReply::NetworkError)));
connect(reply, SIGNAL(sslErrors(QList<QSslError>)),
SLOT(sslErrors(QList<QSslError>)));
m_replies << reply;
}
Q_INVOKABLE void armImpl() {
if (m_replies.isEmpty()) {
emit finishedAllRequests();
m_armed = false;
} else
m_armed = true;
}
static QMetaMethod method(const char * signature) {
return staticMetaObject.method(staticMetaObject.indexOfMethod(signature));
}
public:
// The API is fully thread-safe. The methods can be accessed from any thread.
explicit Parser(QNetworkAccessManager * nam, QObject * parent = 0) :
QObject(parent), m_armed(false), m_manager(nam),
m_addRequestImpl(method("addRequestImpl(QNetworkRequest)")),
m_armImpl(method("armImpl()"))
{}
void addRequest(const QNetworkRequest & req) {
m_addRequestImpl.invoke(this, Q_ARG(QNetworkRequest, req));
}
void arm() {
m_armImpl.invoke(this);
}
Q_SIGNAL void finishedAllRequests();
};
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
QThread * thread = new QThread(&a);
thread->start();
QNetworkAccessManager mgr;
Parser parser(&mgr);
mgr.moveToThread(thread);
parser.moveToThread(thread);
for (int i = 0; i < 10; ++i) {
QNetworkRequest request(QUrl("https://www.google.pl/"));
request.setRawHeader("User-Agent", "MyOwnBrowser 1.0");
parser.addRequest(request);
}
thread->connect(&parser, SIGNAL(finishedAllRequests()), SLOT(quit()));
a.connect(thread, SIGNAL(finished()), SLOT(quit()));
parser.arm();
int rc = a.exec();
thread->wait();
delete thread; // Otherwise mgr's destruction would fail
return rc;
}
#include "main.moc"
Output:
reply QNetworkReplyHttpImpl(0x1011619e0) is finished
reply QNetworkReplyHttpImpl(0x101102260) is finished
reply QNetworkReplyHttpImpl(0x101041670) is finished
reply QNetworkReplyHttpImpl(0x1011023e0) is finished
reply QNetworkReplyHttpImpl(0x10102fa00) is finished
reply QNetworkReplyHttpImpl(0x101040090) is finished
reply QNetworkReplyHttpImpl(0x101163110) is finished
reply QNetworkReplyHttpImpl(0x10103af10) is finished
reply QNetworkReplyHttpImpl(0x10103e6b0) is finished
reply QNetworkReplyHttpImpl(0x101104c80) is finished

Qt HTTP GET freezes screen

I'm writing a Qt program to get an image from site and insert in a QLabel. When I send my request my screen freezes and nothing more occurs.
Notice I'm new in Qt.
Based on my initial knowledge of Qt it's enough send a signal when download is finished.
...
MapReader::MapReader(QWidget *parent, Qt::WFlags flags)
: QMainWindow(parent, flags)
{
ui.setupUi(this);
imageLabelMap = ui.imageMap;
getImageButton = ui.getImageButton;
networkManager = new QNetworkAccessManager(this);
setup();
}
MapReader::~MapReader()
{
}
void MapReader::setup()
{
QObject::connect(getImageButton, SIGNAL(clicked()), this, SLOT(triggerDownload()));
QObject::connect(networkManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(finishedDownload(QNetworkReply*)));
}
void MapReader::setImage(QByteArray imageBytes)
{
QImage map;
...
}
void MapReader::triggerDownload()
{
QUrl url("http://images.tsn.ca/images/stories/2012/09/26/terrydunfield_2035-430x298.jpg");
QNetworkReply* reply = networkManager->get(QNetworkRequest(url));
QObject::connect(reply, SIGNAL(readyRead()), &loop, SLOT(quit()));
}
void MapReader::finishedDownload(QNetworkReply* reply)
{
reply->deleteLater();
QVariant statusCodeV = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute);
QVariant redirectionTargetUrl = reply->attribute(QNetworkRequest::RedirectionTargetAttribute);
if(reply->error() != QNetworkReply::NoError)
{
QMessageBox msgBox;
msgBox.setWindowTitle("Error");
msgBox.setInformativeText("Error on downloading file: \n"+reply->errorString());
msgBox.exec();
return;
}
QVariant attribute = reply->attribute(QNetworkRequest::RedirectionTargetAttribute);
if (attribute.isValid())
{
QUrl url = attribute.toUrl();
qDebug() << "must go to:" << url;
return;
}
setImage(reply->readAll());
}
I think there is some code missing that might give us a clue. You have
QObject::connect(reply, SIGNAL(readyRead()), &loop, SLOT(quit()));
But I don't see where loop is defined? Sounds like you are running an additional event loop?
Regardless, you don't need that. This should be as simple as:
void MapReader::triggerDownload()
{
QUrl url("http://images.tsn.ca/images/stories/2012/09/26/terrydunfield_2035-430x298.jpg");
QNetworkReply* reply = networkManager->get(QNetworkRequest(url));
QObject::connect(reply, SIGNAL(finished()), this, SLOT(finishedDownload()));
}
void MapReader::finishedDownload()
{
QNetworkReply *reply = qobject_cast<QNetworkReply *>(sender()); // sender() allows us to see who triggered this slot - in this case the QNetworkReply
QVariant statusCodeV = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute);
QVariant redirectionTargetUrl = reply->attribute(QNetworkRequest::RedirectionTargetAttribute);
if(reply->error() != QNetworkReply::NoError)
{
QMessageBox msgBox;
msgBox.setWindowTitle("Error");
msgBox.setInformativeText("Error on downloading file: \n"+reply->errorString());
msgBox.exec();
return;
}
QVariant attribute = reply->attribute(QNetworkRequest::RedirectionTargetAttribute);
if (attribute.isValid())
{
QUrl url = attribute.toUrl();
qDebug() << "must go to:" << url;
return;
}
setImage(reply->readAll());
reply->deleteLater();
}
Make sure you have defined finishedDownload() as a slot in your header file

Resources