I want to get string that appears on following link in my Qt program how can I get it ?
http://en.wikipedia.org/w/api.php?action=opensearch&search=centaurus_constellation
I have coded following files to get string appearing on above page in m_DownloadedData, but it is storing empty string at the end of the program , can someone please help me get data from above link ?
.h file:
#ifndef SKYOBJDESCRIPTION_H
#define SKYOBJDESCRIPTION_H
#include <QObject>
#include <QByteArray>
#include <QString>
#include <QNetworkAccessManager>
#include <QNetworkRequest>
#include <QNetworkReply>
class SkyObjDescription : public QObject
{
Q_OBJECT
public:
explicit SkyObjDescription(const QString soName, const QString soType, QObject* parent = 0);
virtual ~SkyObjDescription();
QByteArray downloadedData() const;
signals:
void downloaded();
private slots:
void fileDownloaded(QNetworkReply* reply);
private:
QString soName,soType;
QByteArray m_DownloadedData;
};
#endif // SKYOBJDESCRIPTION_H
and
.cpp file
#include <QString>
#include <QUrl>
#include <QDebug>
#include "skyobjdescription.h"
SkyObjDescription::SkyObjDescription(const QString so_Name, const QString so_Type, QObject* parent): soName(so_Name), soType(so_Type), QObject(parent)
{
QString wikiLink = "http://en.wikipedia.org/w/api.php?action=opensearch&search="+ soName.replace(" ", "_").toLower() + "_" + soType.toLower() + "&format=xml&limit=1.xml";
// QUrl wikiUrl("http://en.wikipedia.org/w/api.php?action=opensearch&search=hello_world&format=xml&limit=1.xml");
m_DownloadedData = wikiUrl.toEncoded();
qDebug() << "wikiUrl.toEncoded(): " << m_DownloadedData;
QNetworkRequest req(wikiUrl);
QNetworkAccessManager* manager = new QNetworkAccessManager(this);
connect(manager, SIGNAL(finished(QNetworkReply*)), SLOT(fileDownloaded(QNetworkReply*)));
manager->get(req);
}
SkyObjDescription::~SkyObjDescription()
{
}
void SkyObjDescription::fileDownloaded(QNetworkReply* reply)
{
m_DownloadedData = reply->readAll();
qDebug() << "received reply";
qDebug() << m_DownloadedData;
reply->deleteLater();
emit downloaded();
}
QByteArray SkyObjDescription::downloadedData() const
{
qDebug() << m_DownloadedData;
return m_DownloadedData;
}
part of main.cpp
SkyObjDescription * skd = new SkyObjDescription(m_Name, "Constellation");
QString data(skd->downloadedData());
qDebug() << data;
delete skd;
If there is other way to get data from link please explain it.
Thank you very much :)
What you probably experiment is caused by your double call on QNetworkReply::readAll.
Remembers it is a IO operation, and there is no way to read multiple times the information contain by the netwrk reply.
Just comment your debug line :
void SkyObjDescription::fileDownloaded(QNetworkReply* pReply)
{
//qDebug() << pReply->readAll();
m_DownloadedData = pReply->readAll();
//emit a signal
pReply->deleteLater();
emit downloaded();
}
edit (for completness)
The test code I use :
#ifndef TMP_H
#define TMP_H
#include <QObject>
class QNetworkReply;
class Tmp : public QObject
{
Q_OBJECT
public:
explicit Tmp(QObject *parent = 0);
signals:
public slots:
void displayResult(QNetworkReply* reply);
};
#endif // TMP_H
//tmp.cpp
#include "tmp.h"
#include <QNetworkAccessManager>
#include <QNetworkReply>
#include <QNetworkRequest>
#include <QDebug>
Tmp::Tmp(QObject *parent) :
QObject(parent)
{
QUrl url("http://en.wikipedia.org/wiki/Centaurus_constellation");
QNetworkRequest req(url);
QNetworkAccessManager* manager = new QNetworkAccessManager(this);
connect(manager, SIGNAL(finished(QNetworkReply*)), SLOT(displayResult(QNetworkReply*)));
manager->get(req);
}
void Tmp::displayResult(QNetworkReply *reply) {
QByteArray buffer = reply->readAll();
qDebug() << "received reply";
qDebug() << buffer;
reply->deleteLater();
}
Related
How to catch incorrect link errors? For example:
ftp://cddis.gsfc.nasa.gov/pub/slr/data/npt_crd/gracea/2010/gracea_20100101.npt.Z
-- this is incorrect link
Why doesn't any error signal work? Or How to determine the correct links? Please, write an example of correct work with errors.
#ifndef WIDGET_H
#define WIDGET_H
#include "Downloader.h"
#include <QWidget>
#include <QNetworkReply>
namespace Ui {
class Widget;
}
class Widget : public QWidget
{
Q_OBJECT
public:
explicit Widget(QWidget *parent = nullptr);
~Widget();
private slots:
void onDownloadButtonClicked();
void onSelectTargetFolderButtonClicked();
void onCancelButtonClicked();
void onUpdateProgress(qint64 bytesReceived, qint64 bytesTotal);
void onResult(QNetworkReply *reply);
private:
Ui::Widget *ui;
Downloader m_downloader;
};
#endif // WIDGET_H
Widget.cpp
#include "Widget.h"
#include "ui_Widget.h"
#include <QFileDialog>
#include <QStandardPaths>
Widget::Widget(QWidget *parent) :
QWidget(parent),
ui(new Ui::Widget)
{
ui->setupUi(this);
connect(ui->downloadPushButton, &QPushButton::clicked, this, &Widget::onDownloadButtonClicked);
connect(ui->selectTargetFolderPushButton, &QPushButton::clicked, this, &Widget::onSelectTargetFolderButtonClicked);
connect(ui->cancelPushButton, &QPushButton::clicked, this, &Widget::onCancelButtonClicked);
connect(&m_downloader, &Downloader::updateDownloadProgress, this, &Widget::onUpdateProgress);
connect(&m_downloader.manager, &QNetworkAccessManager::finished, this, &Widget::onResult);
}
Widget::~Widget()
{
delete ui;
}
void Widget::onDownloadButtonClicked()
{
m_downloader.get(ui->targetFolderLineEdit->text(), ui->urlLineEdit->text());
}
void Widget::onSelectTargetFolderButtonClicked()
{
QString targetFolder = QFileDialog::getExistingDirectory(this,
tr("Select folder"),
QStandardPaths::writableLocation(QStandardPaths::DownloadLocation),
QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks);
ui->targetFolderLineEdit->setText(targetFolder);
}
void Widget::onCancelButtonClicked()
{
m_downloader.cancelDownload();
ui->downloadProgressBar->setMaximum(100);
ui->downloadProgressBar->setValue(0);
}
void Widget::onUpdateProgress(qint64 bytesReceived, qint64 bytesTotal)
{
ui->downloadProgressBar->setMaximum(bytesTotal);
ui->downloadProgressBar->setValue(bytesReceived);
}
void Widget::onResult(QNetworkReply *reply)
{
if (reply->error()) {
qDebug() << "Error";
qDebug() << reply->error();
} else {
qDebug() << "Done";
}
}
Downloader.h
#ifndef DOWNLOADER_H
#define DOWNLOADER_H
#include <QNetworkAccessManager>
#include <QNetworkReply>
//class QNetworkReply;
class QFile;
class Downloader : public QObject
{
Q_OBJECT
using BaseClass = QObject;
public:
explicit Downloader(QObject* parent = nullptr);
bool get(const QString& targetFolder, const QUrl& url);
QNetworkReply* currentReply {nullptr};
QNetworkAccessManager manager;
QString fullName;
public slots:
void cancelDownload();
signals:
void updateDownloadProgress(qint64 bytesReceived, qint64 bytesTotal);
private slots:
void onReadyRead();
void onReply(QNetworkReply* reply);
void errorSlot(QNetworkReply::NetworkError er);
private:
QFile* m_file {nullptr};
};
#endif // DOWNLOADER_H
Downloader.cpp
#include "Downloader.h"
#include <QNetworkReply>
#include <QNetworkRequest>
#include <QFile>
#include <QDir>
Downloader::Downloader(QObject* parent) :
BaseClass(parent)
{
connect(&manager, &QNetworkAccessManager::finished, this, &Downloader::onReply);
}
bool Downloader::get(const QString& targetFolder, const QUrl& url)
{
qDebug() << "get";
if (targetFolder.isEmpty() || url.isEmpty())
{
return false;
}
fullName = targetFolder + QDir::separator() + url.fileName();
m_file = new QFile(fullName);
if (!m_file->open(QIODevice::WriteOnly))
{
delete m_file;
m_file = nullptr;
return false;
}
QNetworkRequest request(url);
request.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true);
currentReply = manager.get(request);
connect(currentReply, QOverload<QNetworkReply::NetworkError>::of(&QNetworkReply::error),
this, &Downloader::errorSlot);
connect(currentReply, &QNetworkReply::readyRead, this, &Downloader::onReadyRead);
connect(currentReply, &QNetworkReply::downloadProgress, this, &Downloader::updateDownloadProgress);
return true;
}
void Downloader::onReadyRead()
{
qDebug() << "onReadyRead";
if (m_file)
{
m_file->write(currentReply->readAll());
}
}
void Downloader::cancelDownload()
{
qDebug() << "cancelDownload";
if (currentReply)
{
currentReply->abort();
}
}
void Downloader::onReply(QNetworkReply* reply)
{
qDebug() << "onReply";
if (reply->error() == QNetworkReply::NoError)
{
m_file->flush();
m_file->close();
}
else
{
m_file->remove();
}
delete m_file;
m_file = nullptr;
reply->deleteLater();
}
void Downloader::errorSlot(QNetworkReply::NetworkError er)
{
qDebug() << er;
}
My code compiles error free but the output to a little lcd panel I have should read 22. It reads the number 44 which is the initial value set in the constuctor. It is failing to update to a new value.
It appears MainWindow::finishedSlot(QNetworkReply* reply) is not being accessed and ui->lcdNumber->display(22) does not update the object as expected.
I can confirm that the connection does establish, I have wireshark running and I can see the software try and reach google, but nothing about that LCD I can get working because I cannot access the constructor object.
The purpose of the LCD is to reflect connection information, but right now I am just trying to reach the constructor.
//mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QNetworkAccessManager>
#include <QUrl>
#include <QNetworkRequest>
#include <QNetworkReply>
#include <QImageReader>
#include <QLCDNumber>
#include <QDebug>
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
nam = new QNetworkAccessManager();
ui->lcdNumber->display(44);
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::connect()
{
qDebug() << "connect";
QObject::connect(nam, SIGNAL(finished(QNetworkReply*)),
this, SLOT(finishedSlot(QNetworkReply*)));
QObject::connect(nam, SIGNAL(finished(QNetworkReply*)),
this, SLOT(on_pushButton_clicked()));
}
void MainWindow::requestPage(){
QUrl url("http://www.google.com");
QNetworkReply* reply = nam->get(QNetworkRequest(url));
}
void MainWindow::finishedSlot(QNetworkReply* reply){
qDebug() << "finishedSlot";
QVariant statusCodeV = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute);
QVariant redirectionTargetUrl = reply->attribute(QNetworkRequest::RedirectionTargetAttribute);
QByteArray bytes = reply->readAll(); // bytes
QString string(bytes); // string
ui->lcdNumber->display(22);
// if (reply->error() == QNetworkReply::NoError)
// {
// QImageReader imageReader(reply);
// QImage pic = imageReader.read();
// QByteArray bytes = reply->readAll(); // bytes
// QString string(bytes); // string
// ui->lcdNumber->display(22);
//qDebug()<<string;
// }
// else
// {
// }
}
void MainWindow::on_pushButton_clicked()
{
requestPage();
}
//mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QObject>
#include <QNetworkAccessManager>
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
private:
Ui::MainWindow *ui;
public slots:
void connect();
void requestPage();
void finishedSlot(QNetworkReply* reply);
void on_pushButton_clicked();
private slots:
private:
QNetworkAccessManager* nam;
};
#endif // MAINWINDOW_H
//main.cpp
#include "mainwindow.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow mConnect;
mConnect.show();
return a.exec();
}
Maybe it's me, but it seems that there's no connection between button clicked signal and on_pushButton_clicked slot.
Final working solution
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QNetworkAccessManager>
#include <QUrl>
#include <QNetworkRequest>
#include <QNetworkReply>
#include <QImageReader>
#include <QLCDNumber>
#include <QDebug>
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
nam = new QNetworkAccessManager();
//connect2();
//on_pushButton_clicked();
QObject::connect(ui->pushButton, SIGNAL(clicked()), this, SLOT(on_pushButton_clicked()));
QObject::connect(nam, SIGNAL(finished(QNetworkReply*)), this, SLOT(finishedSlot(QNetworkReply*)));
QObject::connect(nam, SIGNAL(finished(QNetworkReply*)), this, SLOT(finishedSlot(QNetworkReply*)));
ui->lcdNumber->display(66);
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::connect2()
{
qDebug() << "connect";
//QObject::connect(nam, SIGNAL(finished(QNetworkReply*)),
//this, SLOT(finishedSlot(QNetworkReply*)));
//QObject::connect(nam, SIGNAL(clicked()), this, SLOT(finishedSlot(QNetworkReply* reply)));
//;
}
void MainWindow::requestPage(){
QUrl url("http://www.google.com");
QNetworkReply* reply = nam->get(QNetworkRequest(url));
}
void MainWindow::finishedSlot(QNetworkReply* reply){
qDebug() << "finishedSlot";
QVariant statusCodeV = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute);
QVariant redirectionTargetUrl = reply->attribute(QNetworkRequest::RedirectionTargetAttribute);
QByteArray bytes = reply->readAll(); // bytes
QString string(bytes); // string
ui->lcdNumber->display(11);
qDebug()<<string;
// if (reply->error() == QNetworkReply::NoError)
// {
// QImageReader imageReader(reply);
// QImage pic = imageReader.read();
// QByteArray bytes = reply->readAll(); // bytes
// QString string(bytes); // string
// ui->lcdNumber->display(22);
//qDebug()<<string;
// }
// else
// {
// }
}
void MainWindow::on_pushButton_clicked()
{
requestPage();
//connect();
}
There is no error in my code though there is never any request packet hits my server. I run tcpdump port 80 and nothing ever crosses the wire, wireshark says the same.
//coreeng.h
#ifndef COREENG_H
#define COREENG_H
#include <QObject>
#include <QNetworkAccessManager>
class coreEng : public QObject
{
Q_OBJECT
public:
private slots:
public slots:
void connect();
void url();
void finishedSlot(QNetworkReply* reply);
private:
QNetworkAccessManager* nam;
};
#endif // COREENG_H
//coreengine.cpp
#include "coreeng.h"
#include <QNetworkAccessManager>
#include <QUrl>
#include <QNetworkRequest>
#include <QNetworkReply>
#include <QImageReader>
coreEng::coreEng(QObject *parent) :
QObject(parent)
{
}
explicit coreEng(QObject *parent = 0)
{
nam = new QNetworkAccessManager();
}
void coreEng::connect(){
QObject::connect(nam, SIGNAL(finished(QNetworkReply*)),
this, SLOT(finishedSlot(QNetworkReply*)));
}
void coreEng::url(){
QUrl url("http://www.myserver.com");
QNetworkReply* reply = nam->get(QNetworkRequest(url));
}
void coreEng::finishedSlot(QNetworkReply* reply){
QVariant statusCodeV = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute);
QVariant redirectionTargetUrl = reply->attribute(QNetworkRequest::RedirectionTargetAttribute);
if (reply->error() == QNetworkReply::NoError)
{
QImageReader imageReader(reply);
QImage pic = imageReader.read();
QByteArray bytes = reply->readAll(); // bytes
QString string(bytes); // string
}
else
{
}
delete reply();
}
//main.cpp
#include <QCoreApplication>
#include "coreeng.h"
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
coreEng mConnect;
mConnect.connect();
return a.exec();
}
You never call coreEng::url() so you never make a request.
I'm also not sure your constructors are correct. Why not just ditch the explicit constructor and create the QNetworkAccessManager in the default constructor?
I am trying to implement http://developer.nokia.com/community/wiki/Creating_an_HTTP_network_request_in_Qt and my code compiles without error but does not function. I have a warning that reply in "QNetworkReply* reply = nam->get(QNetworkRequest(url));" is not being used. I am sure this is my error and I am not setting up my HTTP GET correctly, but I am unsure of how to correct it.
//coreEng.h
#ifndef COREENG_H
#define COREENG_H
#include <QObject>
#include <QNetworkAccessManager>
class coreEng : public QObject
{
Q_OBJECT
public:
//coreEng(QObject);
coreEng(QObject *parent = 0) :
QObject(parent)
{
nam = new QNetworkAccessManager();
}
private slots:
public slots:
void connect();
void url(QNetworkReply *reply);
void finishedSlot(QNetworkReply* reply);
private:
QNetworkAccessManager* nam;
};
#endif // COREENG_H
//coreEng.cpp
"coreeng.h"
#include <QNetworkAccessManager>
#include <QUrl>
#include <QNetworkRequest>
#include <QNetworkReply>
#include <QImageReader>
void coreEng::connect(){
QObject::connect(nam, SIGNAL(finished(QNetworkReply*)),
this, SLOT(finishedSlot(QNetworkReply*)));
}
void coreEng::url(QNetworkReply*){
QUrl url("http://www.nyctelecomm.com");
QNetworkReply* reply = nam->get(QNetworkRequest(url));
}
void coreEng::finishedSlot(QNetworkReply* reply){
QVariant statusCodeV = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute);
QVariant redirectionTargetUrl = reply->attribute(QNetworkRequest::RedirectionTargetAttribute);
if (reply->error() == QNetworkReply::NoError)
{
QImageReader imageReader(reply);
QImage pic = imageReader.read();
QByteArray bytes = reply->readAll(); // bytes
QString string(bytes); // string
}
else
{
}
//delete reply();
}
//main.cpp
#include <QCoreApplication>
#include "coreeng.h"
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
coreEng mConnect;
mConnect.connect();
return a.exec();
}
changed void coreEng::url(QNetworkReply*) to void coreEng::url()
changed void url(QNetworkReply *reply); to void url();
added mConnect.url(); to main.cpp and I could see the http packet with wireshark exit the NIC and begin the session.
I don't know what the problem is...The compiler (Qt) runs program without errors, but the file is not downloaded...
Can you tell me please tell what is wrong?
I made by example "download", which is located in the qt folder. The only difference is that they have is a console, and I have windows application.
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QtNetwork>
#include <QMainWindow>
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
private slots:
void on_pushButton_clicked();
private:
Ui::MainWindow *ui;
};
class DownloadManager: public QObject
{
Q_OBJECT
QNetworkAccessManager manager;
QList<QNetworkReply *> currentDownloads;
public:
DownloadManager();
void doDownload(const QUrl &url);
QString saveFileName(const QUrl &url);
bool saveToDisk(const QString &filename, QIODevice *data);
public slots:
void execute();
void downloadFinished(QNetworkReply *reply);
};
#endif // MAINWINDOW_H
main.cpp
#include <QtGui/QApplication>
#include "mainwindow.h"
#include <QtNetwork>
#include <QNetworkAccessManager>
#include <QStringList>
#include <QCoreApplication>
#include <QFile>
#include <QFileInfo>
#include <QList>
#include <QNetworkAccessManager>
#include <QNetworkRequest>
#include <QNetworkReply>
#include <QStringList>
#include <QTimer>
#include <QUrl>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
#if defined(Q_WS_S60)
w.showMaximized();
#else
w.show();
#endif
return a.exec();
}
DownloadManager::DownloadManager()
{
connect(&manager, SIGNAL(finished(QNetworkReply*)),
SLOT(downloadFinished(QNetworkReply*)));
}
void DownloadManager::doDownload(const QUrl &url)
{
QNetworkRequest request(url);
QNetworkReply *reply = manager.get(request);
currentDownloads.append(reply);
}
QString DownloadManager::saveFileName(const QUrl &url)
{
QString path = url.path();
QString basename = QFileInfo(path).fileName();
if (basename.isEmpty())
basename = "download";
if (QFile::exists(basename)) {
// already exists, don't overwrite
int i = 0;
basename += '.';
while (QFile::exists(basename + QString::number(i)))
++i;
basename += QString::number(i);
}
return basename;
}
bool DownloadManager::saveToDisk(const QString &filename, QIODevice *data)
{
QFile file(filename);
if (!file.open(QIODevice::WriteOnly)) {
fprintf(stderr, "Could not open %s for writing: %s\n",
qPrintable(filename),
qPrintable(file.errorString()));
return false;
}
file.write(data->readAll());
file.close();
return true;
}
void DownloadManager::execute()
{
QStringList args = QCoreApplication::instance()->arguments();
args[0]="http://www.google.ru/images/srpr/logo3w.png";
QString arg=args[0];
QUrl url = QUrl::fromEncoded(arg.toLocal8Bit());
doDownload(url);
}
void DownloadManager::downloadFinished(QNetworkReply *reply)
{
QUrl url = reply->url();
if (reply->error()) {
fprintf(stderr, "Download of %s failed: %s\n",
url.toEncoded().constData(),
qPrintable(reply->errorString()));
} else {
QString filename = saveFileName(url);
if (saveToDisk(filename, reply))
printf("Download of %s succeded (saved to %s)\n",
url.toEncoded().constData(), qPrintable(filename));
}
currentDownloads.removeAll(reply);
reply->deleteLater();
if (currentDownloads.isEmpty())
// all downloads finished
QCoreApplication::instance()->quit();
}
mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::on_pushButton_clicked()
{
DownloadManager manager;
manager.execute();
QTimer::singleShot(0, &manager, SLOT(execute()));
}
The problem is at that point of your code:
void MainWindow::on_pushButton_clicked()
{
DownloadManager manager;
manager.execute();
}
QNetworkAccessManager is asynchronous, so it needs an event loop to do any downloading. But when the function on_pushButton_clicked() returns and gives the control back to the event loop, the QNetworkAccessManager is already destroyed, and didn't have the time to do anything.
When you add a QMessageBox in DownloadManager::execute, you are in fact running another event loop withing the slot on_pushButton_clicked(), and it gives the opportunity to the QNetworkAccessManager to do its work.
The correct solution would be to allocate DownloadManager dynamically, and eventually to make it destroy itself when it has finished all downloads.
void MainWindow::on_pushButton_clicked()
{
DownloadManager *manager = new DownloadManager(this);
manager->execute();
}
void DownloadManager::downloadFinished(QNetworkReply *reply)
{
...
if (currentDownloads.isEmpty())
this->deleteLater();
}