I wrote a piece of code that sends me, via a post request, a json to my API Rest; and works!
main.cpp
void replyFinished(QNetworkReply *reply)
{
reply->deleteLater();
qDebug() << "reply delete!";
qDebug() << "https post_request done!";
}
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
QNetworkAccessManager *manager = new QNetworkAccessManager();
QUrl url("https://.../");
QNetworkRequest request(url);
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
QObject::connect(manager, &QNetworkAccessManager::finished, replyFinished);
quint8 speed = 0x12;
quint8 accelleration = 0x2b;
QString json = QString("{\"speed\":\"%1\",\"acceleration\":\"%2\"}").arg(speed).arg(accelleration);
manager->post(request, json.toUtf8());
return a.exec();
}
But when I want to integrate this piece of code in my program, it does not work. Briefly, my program gets through the SIGNAL and SLOT mechanism, a QByteArray, from which I take the data and I send them to my API Rest.
This is my Header.h
...
class Packet : public QObject
{
Q_OBJECT
public:
Packet();
public slots:
void receivePayload(QByteArray &bufferToJson);
void replyFinished(QNetworkReply *reply);
private:
QNetworkAccessManager *m_manager;
quint8 m_speed;
quint8 m_accelleration;
public:
QString json;
};
...
This is my class.cpp
Packet::Packet()
: m_manager { new QNetworkAccessManager }
{
QObject::connect(m_manager, SIGNAL(finished(QNetworkReply*)), this, SLOT(replyFinished(QNetworkReply*)));
}
void Packet::replyFinished(QNetworkReply *reply)
{
reply->deleteLater();
qDebug() << "reply delete!";
qDebug() << "https post_request done!";
}
void Packet::receivePayload(QByteArray &bufferToJson){
m_speed = bufferToJson.at(0);
m_accelleration = bufferToJson.at(1);
QUrl url("https://.../");
QNetworkRequest request(url);
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
QString json = QString("{\"speed\":\"%1\",\"acceleration\":\"%2\"}").arg(m_speed).arg(m_accelleration);
m_manager->post(request, json.toUtf8());
}
What's the problem of my change?
Related
I am working with a team on a C++ project using Qt. As part of our project, we have to be able to retrieve coordinates of any given address in France. The French government provivdes an API that handles that for us.
The call to the API looks like this:
curl -X POST -F data=#path/to/file.csv https://api-adresse.data.gouv.fr/search/csv/
Here is the code I wrote:
int main (int argc, char* argv[]){
QCoreApplication app(argc, argv);
QNetworkAccessManager man;
QUrl url("https://api-adresse.data.gouv.fr/search/csv/");
QNetworkRequest req(url);
QFile inputFile("<path_to_search.csv>");
inputFile.open(QIODevice::ReadOnly);
QByteArray data = inputFile.readAll();
QNetworkReply* reply = man.post(req, "data=" + data);
QObject::connect(reply, &QNetworkReply::finished, [&](){
QByteArray read = reply->readAll();
std::cout << "Reading Data:" << std::endl;
std::cout << read.toStdString() << std::endl;
reply->close();
reply->deleteLater();
app.quit();
});
return app.exec();
}
The server replies with
{"code":400,"message":"A CSV file must be provided in data field"}
So clearly I am forwarding the form incorrectly. How should I proceed?
To send information through the forms, I don't know the query section, but rather you want to use QHttpMultiPart as I show in this old post. Applying to your case the solution is:
#include <QCoreApplication>
#include <QFile>
#include <QHttpMultiPart>
#include <QNetworkAccessManager>
#include <QNetworkReply>
QHttpMultiPart *buildMultpart(const QVariantMap & data, const QMap<QString, QString> filenames){
QHttpMultiPart *multipart = new QHttpMultiPart(QHttpMultiPart::FormDataType);
QVariantMap::const_iterator i_data = data.constBegin();
while (i_data != data.constEnd()) {
QHttpPart postpart;
postpart.setHeader(QNetworkRequest::ContentDispositionHeader, QString("form-data; name=\"%1\"").arg(i_data.key()));
postpart.setBody(i_data.value().toByteArray());
multipart->append(postpart);
++i_data;
}
QMap<QString, QString>::const_iterator i_filenames = filenames.constBegin();
while (i_filenames != filenames.constEnd()) {
QFile *file = new QFile(i_filenames.value());
if(!file->open(QIODevice::ReadOnly)){
delete file;
continue;
}
QHttpPart postpart;
postpart.setHeader(QNetworkRequest::ContentDispositionHeader,
QString("form-data; name=\"%1\"; filename=\"%2\"")
.arg(i_filenames.key(), file->fileName()));
postpart.setBodyDevice(file);
multipart->append(postpart);
file->setParent(multipart);
++i_filenames;
}
return multipart;
}
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
QNetworkAccessManager manager;
QNetworkRequest request;
QUrl url("https://api-adresse.data.gouv.fr/search/csv/");
request.setUrl(url);
QMap<QString, QString> filenames;
filenames["data"] = "/path/of/file.csv";
QHttpMultiPart *multipart = buildMultpart({}, filenames);
QNetworkReply *reply = manager.post(request, multipart);
multipart->setParent(reply);
QObject::connect(reply, &QNetworkReply::finished, [reply](){
if(reply->error() == QNetworkReply::NoError){
qDebug().noquote() << reply->readAll();
}
else{
qDebug() << reply->error() << reply->errorString();
}
reply->deleteLater();
QCoreApplication::quit();
});
return a.exec();
}
I'm new to Qt Framework and I'm trying to get the list of earthquakes from EMSC api. My code looks like this:
void MainWindow::getJsonData(QNetworkAccessManager *mNetworkManager) {
const QUrl json("https://www.seismicportal.eu/fdsnws/event/1/query?limit=100&format=json");
QNetworkRequest *mNetworkRequest = new QNetworkRequest;
mNetworkRequest->setUrl(json);
mNetworkRequest->setRawHeader("Content-Type", "application/json");
mNetworkRequest->setRawHeader("Accept", "application/json");
QNetworkReply *mNetworkReply = mNetworkManager->get(*mNetworkRequest);
QString replyString = (QString) mNetworkReply->readAll();
QJsonDocument document = QJsonDocument::fromJson(replyString.toUtf8());
QJsonObject object = document.object();
QJsonValue type = object["type"].toString();
QJsonArray featuresArray = object["features"].toArray();
qDebug() << type;
qDebug() << featuresArray;
}
The problem is that I'm not getting any response from the server.
Qt is a library (not a framework) that handles all transactions asynchronously through signals and slots, so don't expect the response to be obtained synchronously.
#include <QCoreApplication>
#include <QJsonArray>
#include <QJsonDocument>
#include <QJsonObject>
#include <QNetworkAccessManager>
#include <QNetworkReply>
class Client: public QObject{
public:
void startRequest(){
const QUrl json("https://www.seismicportal.eu/fdsnws/event/1/query?limit=100&format=json");
QNetworkRequest request;
request.setUrl(json);
request.setRawHeader("Content-Type", "application/json");
request.setRawHeader("Accept", "application/json");
QNetworkReply *reply = mNetworkManager.get(request);
connect(reply, &QNetworkReply::finished, this, &Client::processRequest);
}
private:
void processRequest(){
QNetworkReply * reply = qobject_cast<QNetworkReply *>(sender());
if(!reply) return;
QJsonDocument document = QJsonDocument::fromJson(reply->readAll());
QJsonObject object = document.object();
QJsonValue type = object["type"].toString();
QJsonArray featuresArray = object["features"].toArray();
qDebug() << type << featuresArray;
reply->deleteLater();
}
QNetworkAccessManager mNetworkManager;
};
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
Client client;
client.startRequest();
return a.exec();
}
Output:
QJsonValue(string, "FeatureCollection") QJsonArray([{"geometry":{"coordinates":[16.23,45.4,-2],"type":"Point"},"id":"20210202_0000178", ...
Here's some of my code:
QNetworkRequest req (QUrl(QString::fromStdString(url)));
req.setHeader(QNetworkRequest::KnownHeaders::ContentTypeHeader, "application/json");
if (authHeader.length() > 0) {
req.setRawHeader(QByteArray("Authorization"), QByteArray::fromStdString(authHeader));
}
QByteArray bodyArray;
if (body.length() > 0) {
bodyArray.append(QString::fromStdString(body).toUtf8());
}
QNetworkReply * reply = method(req, bodyArray);
QObject::connect(reply, &QNetworkReply::finished, [=]{
.... });
Qcompleter which is associated with a lineEdit doesn't work in the slot of a QNetworkRequest finished.The Qcompleter disappeared quite quickly.Each time the text in lineEdit changed a request was send.I tried a demo without other code,it also occured.
Every time the text in lineEdit was edit,a request contains the text will be send to my server.And then I want to show the content in reply in a Qcompleter.But the prompt disappears in a instant.
void MainWindow::onRequestFinished(QNetworkReply* reply){
QStringList stringList;
stringList << "test1" <<"test2"<<"test3";
QCompleter* completer = new QCompleter(stringList,this);
completer->setCompletionMode(QCompleter::UnfilteredPopupCompletion);
ui->lineEdit->setCompleter(completer);
reply->deleteLater();
}
void MainWindow::on_lineEdit_textChanged(const QString &arg1)
{
QUrl url("http://www.google.com");
QNetworkRequest request;
request.setUrl(url);
manager->get(request);
}
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow){
...
this->manager = new QNetworkAccessManager(this);
connect(manager,SIGNAL(finished(QNetworkReply*)),this,SLOT(onRequestFinished(QNetworkReply*)));
...
}
The logic is similar to an old answer of mine, in it a model is created that will store the information this prevents you from creating a QCompleter at every moment avoiding the problem the disappearance of the popup.
#include <QtWidgets>
#include <QtNetwork>
class SuggestModel: public QStandardItemModel
{
Q_OBJECT
public:
using QStandardItemModel::QStandardItemModel;
void search(const QString & text)
{
QNetworkRequest request = create_request(text);
if(m_reply)
m_reply->abort();
m_reply = manager.get(request);
connect(m_reply, &QNetworkReply::finished, this, &SuggestModel::onFinished);
QEventLoop loop;
connect(this, &SuggestModel::finished, &loop, &QEventLoop::quit);
loop.exec();
}
private Q_SLOTS:
void onFinished(){
QNetworkReply *reply = qobject_cast<QNetworkReply *>(sender());
QUrl url = reply->url();
if (reply->error() == QNetworkReply::NoError) {
QVector<QString> choices;
QByteArray response(reply->readAll());
QXmlStreamReader xml(response);
while (!xml.atEnd()) {
xml.readNext();
if (xml.tokenType() == QXmlStreamReader::StartElement)
if (xml.name() == "suggestion") {
QStringRef str = xml.attributes().value("data");
choices << str.toString();
}
}
clear();
for(const QString & choice: choices)
appendRow(new QStandardItem(choice));
}
reply->deleteLater();
Q_EMIT finished();
m_reply = nullptr;
}
Q_SIGNALS:
void finished();
private:
QNetworkRequest create_request(const QString & text){
const QString suggestUrl(QStringLiteral("http://google.com/complete/search?output=toolbar&q=%1"));
QString url = suggestUrl.arg(text);
return QNetworkRequest(url);
}
QNetworkAccessManager manager;
QNetworkReply *m_reply = nullptr;
};
class SuggestCompleter: public QCompleter{
public:
SuggestCompleter(QObject *parent=nullptr):
QCompleter(parent)
{
SuggestModel *m_model = new SuggestModel(this);
setModel(m_model);
setCompletionMode(QCompleter::UnfilteredPopupCompletion);
}
QStringList splitPath(const QString &path) const override{
if(SuggestModel * m = qobject_cast<SuggestModel *>(model()))
m->search(path);
return QCompleter::splitPath(path);
}
};
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QLineEdit le;
le.setCompleter(new SuggestCompleter(&le));
le.show();
return a.exec();
}
#include "main.moc"
I am trying to connect to a FTP server but I got the following issue :
QObject::connect: No such slot Object::replyFinished
in ...\ here my program name ......
Where is my mistake? I suppose it is in the following code :
///////////////Connection.h file////////
class Connection : public QObject
{
public:
explicit Connection(QObject *parent=0);
Connection(QString uri, QString usernmae, QString password);
void FTP_Connection();
public slots:
void replyFinished(QNetworkReply *);
private:
QString URI;
QString USERNAME;
QString PASSWORD;
QNetworkAccessManager *manager;
};
///////////////Connection.cpp file////////
Connection::Connection(QString uri, QString usernmae, QString password)
{
this->URI=uri;
this->USERNAME=usernmae;
this->PASSWORD=password;
}
void Connection::FTP_Connection()
{
QUrl url(this->URI);
url.setUserName(this->USERNAME);
url.setPassword(this->PASSWORD);
url.setPort(21);
QNetworkRequest request(url);
manager=new QNetworkAccessManager(this);
connect(manager,
SIGNAL(finished(QNetworkReply*)),
this,
SLOT(replyFinished(QNetworkReply *)));
manager->get(request);
}
///////////////main.cpp file////////
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
Connection *con=new Connection("ftp://192.168.3.62//",
"win7",
"053253");
con->FTP_Connection();
return a.exec();
}
This is my code (C++: Qt) for getting webpage source:
QString htmlString;
QEventLoop eventLoop;
QNetworkAccessManager mgr;
QObject::connect(&mgr, SIGNAL(finished(QNetworkReply*)), &eventLoop, SLOT(quit()));
QNetworkRequest req( QUrl( QString( "http://stackoverflow.com" ) ) );
QNetworkReply *reply = mgr.get(req);
eventLoop.exec();
htmlString = reply->readAll();
Is there any way to get webpage source with progress bar ?!
Write special class for this:
#ifndef DOWNLOADER_H
#define DOWNLOADER_H
#include <QObject>
#include <QNetworkAccessManager>
#include <QNetworkRequest>
#include <QNetworkReply>
#include <QUrl>
#include <QDebug>
#include <QProgressBar>
class Downloader : public QObject
{
Q_OBJECT
public:
explicit Downloader(QObject *parent = 0);
void doDownload();
public slots:
void replyFinished (QNetworkReply *reply);
void updateDownloadProgress(qint64, qint64);
private:
QNetworkAccessManager *manager;
QProgressBar *bar;
};
#endif
Cpp:
Downloader::Downloader(QObject *parent) :
QObject(parent)
{
}
void Downloader::doDownload()
{
manager = new QNetworkAccessManager(this);
connect(manager, SIGNAL(finished(QNetworkReply*)),
this, SLOT(replyFinished(QNetworkReply*)));
QNetworkReply * rep = manager->get(QNetworkRequest(QUrl("http://qt-project.org/")));
connect(rep, SIGNAL(downloadProgress(qint64, qint64)),
this, SLOT(updateDownloadProgress(qint64, qint64)));
bar = new QProgressBar;
bar->show();
}
void Downloader::replyFinished (QNetworkReply *reply)
{
if(reply->error())
{
qDebug() << "ERROR!";
qDebug() << reply->errorString();
}
else
{
qDebug() << reply->readAll();
}
reply->deleteLater();
}
void Downloader::updateDownloadProgress(qint64 read, qint64 total)
{
qDebug() << read << total;
bar->setMaximum(total);
bar->setValue(read);
}
Usage:
Downloader down;
down.doDownload();
Main idea here is to use void QNetworkReply::downloadProgress(qint64 bytesReceived, qint64 bytesTotal) [signal] to get progress and show this progress in QProgressBar.
And you can do this with your current code without class:
QString htmlString;
QEventLoop eventLoop;
QNetworkAccessManager mgr;
QObject::connect(&mgr, SIGNAL(finished(QNetworkReply*)), &eventLoop, SLOT(quit()));
QProgressBar *bar = new QProgressBar;
bar->show();
QNetworkRequest req( QUrl( QString( "http://stackoverflow.com" ) ) );
QNetworkReply *reply = mgr.get(req);
QObject::connect(reply,&QNetworkReply::downloadProgress,[=](qint64 bytesReceived, qint64 bytesTotal) {//with lambda
bar->setMaximum(bytesTotal);
bar->setValue(bytesReceived);
});
eventLoop.exec();
htmlString = reply->readAll();
qDebug() << htmlString;
I used here C++11 (CONFIG += c++11 to .pro file) and new syntax of signals and slots.