Adding code example to QT C++ - c++

I'd like to add some QT example code to my simple project. The sample code is here: https://wiki.qt.io/Download_Data_from_URL
It consists of filedownloader.cpp and filedownloader.h -- this code downloads a graphic from a supplied URL.
I've added these files to my project and get a clean compile. I think I understand the code ok (I'm mainly a c coder, not c++) but I don't understand how I can pass the QUrl created by my project to filedownloader.cpp
The "project" is just a simple main.cpp/mainwindow.cpp/mainwindow.ui that offers a button to be pressed. Pressing the button calls the routine below:
void MainWindow::on_pushButton_clicked()
{
// pass to filedownloader to process
QUrl fileloc("http://www.test.com/test.jpg");
}
How do I feed the QUrl fileloc to filedownload.cpp?

You have to add a new method to FileDownloader, that accepts QUrl and starts the download.
filedownloader.h:
#ifndef FILEDOWNLOADER_H
#define FILEDOWNLOADER_H
#include <QObject>
#include <QByteArray>
#include <QNetworkAccessManager>
#include <QNetworkRequest>
#include <QNetworkReply>
class FileDownloader : public QObject
{
Q_OBJECT
public:
explicit FileDownloader(QUrl imageUrl, QObject *parent = 0);
virtual ~FileDownloader();
QByteArray downloadedData() const;
signals:
void downloaded();
public slots:
void download(QUrl url); // <------ Here it is
private slots:
void fileDownloaded(QNetworkReply* pReply);
private:
QNetworkAccessManager m_WebCtrl;
QByteArray m_DownloadedData;
};
#endif // FILEDOWNLOADER_H
filedownloader.cpp:
#include "filedownloader.h"
FileDownloader::FileDownloader(QObject *parent) :
QObject(parent)
{
connect(
&m_WebCtrl, SIGNAL (finished(QNetworkReply*)),
this, SLOT (fileDownloaded(QNetworkReply*))
);
// <------ Notice, that i've removed downloading code from here
}
FileDownloader::~FileDownloader() { }
void FileDownloader::fileDownloaded(QNetworkReply* pReply) {
m_DownloadedData = pReply->readAll();
//emit a signal
pReply->deleteLater();
emit downloaded();
}
void FileDownloader::download(QUrl url) { // <------ And its definition
QNetworkRequest request(url);
m_WebCtrl.get(request);
}
QByteArray FileDownloader::downloadedData() const {
return m_DownloadedData;
}
And then your on_pushButton_clicked will look like this:
void MainWindow::on_pushButton_clicked()
{
// pass to filedownloader to process
QUrl fileloc("http://www.test.com/test.jpg");
m_filedownloader.download(fileloc);
}

Related

QT request "QObject::connect: No such slot BackEnd::RequestReceived"

Im trying to make a request to get some data with QT.
my backend.h
#ifndef BACKEND_H
#define BACKEND_H
#include <QNetworkAccessManager>
#include <QObject>
#include <QString>
#include <QNetworkReply>
class BackEnd : public QObject
{
Q_OBJECT
Q_PROPERTY(QString userName READ userName WRITE setUserName NOTIFY userNameChanged)
public:
explicit BackEnd(QObject *parent = nullptr);
QString userName();
void setUserName(const QString &userName);
signals:
void userNameChanged();
private:
QString m_userName;
QNetworkAccessManager *manager;
//also tried: void RequestReceived(QNetworkReply* reply); << without space after QNetworkReply
void RequestReceived(QNetworkReply * reply);
};
#endif // BACKEND_H
my .cpp
#include "backend.h"
#include <string>
#include <iostream>
#include <QtNetwork>
BackEnd::BackEnd(QObject *parent) :
QObject(parent)
{
manager = new QNetworkAccessManager(this);
}
void BackEnd::RequestReceived(QNetworkReply * reply){
QByteArray rawData = reply->readAll();
QString textData(rawData);
qDebug() << textData;
}
QString BackEnd::userName()
{
return m_userName;
}
void BackEnd::setUserName(const QString &userName)
{
if (userName == m_userName)
return;
m_userName = userName;
connect(manager, SIGNAL(finished(QNetworkReply*)),
this, SLOT(RequestReceived(QNetworkReply*)));
manager->get(QNetworkRequest(QUrl("https://google.com")));
emit userNameChanged();
}
I found similair questions but almost all answers say Q_OBJECT should be added (which I have). Im very new to qt but if I understand correctly the error indicates that I do not have a
BackEnd::RequestReceived(QNetworkReply*)
method, which I do have. Any help is welcome.
You need to mark void RequestReceived(QNetworkReply * reply); as a slot:
Q_SLOT void RequestReceived(QNetworkReply * reply);

How to get text from website in Qt (QNetworkAccessManager not working)?

I am trying to get text from a website using the QNetworkAccessManager class, but it's not working. When the replyFinished slot above is called, the parameter it takes is the QNetworkReply object containing the downloaded data as well as meta-data (headers, etc.). When the slot gets called, I append the gotten text to a QString and print it out, but it prints an empty string. Here is my code:
//.pro file
TEMPLATE = app
QT += qml quick
QT += network
CONFIG += c++11
//xmlparser.h
#ifndef XMLPARSER_H
#define XMLPARSER_H
#include <QObject>
#include <QNetworkAccessManager>
class XMLParser : public QNetworkAccessManager
{
Q_OBJECT
public:
~XMLParser()=default;
static XMLParser &Instance();
Q_INVOKABLE void readXML();
signals:
finished(QNetworkReply* reply);
public slots:
void replyFinished(QNetworkReply* reply);
private:
XMLParser()=default;
XMLParser(XMLParser const&)=delete;
void operator = (XMLParser const&)=delete;
QByteArray m_text;
};
#endif // XMLPARSER_H
//xmlparser.cpp
#include <QUrl>
#include <QDebug>
#include <QNetworkAccessManager>
#include <QNetworkRequest>
#include <QNetworkReply>
#include <QEventLoop>
#include "xmlparser.h"
XMLParser &XMLParser::Instance()
{
static XMLParser instance;
return instance;
}
void XMLParser::readXML()
{
QNetworkAccessManager *manager = new QNetworkAccessManager(this);
connect(manager, SIGNAL(finished(QNetworkReply*)),
this, SLOT(replyFinished(QNetworkReply*)));
manager->get(QNetworkRequest(QUrl("http://qt-project.org")));
}
void XMLParser::replyFinished(QNetworkReply *reply)
{
QString text;
text.append(reply->readAll());
qDebug () << "Text: " << text; //Prints out emtpy string?
}

Qt C++ Slot is not called when Signal is sent

After debugging, I'm sure that the replyFinish() slot is not called when I call this->getNetReply(). These are my files, in the main() fumction I call the getNetReply this way: Networking a; a.getNetReply();
I did add QT+=network to my qmake.
Please help me. Thank you very much.
my networking.cpp file
#include "networking.h"
#include <QUrl>
#include <QNetworkRequest>
// constructor
void Networking::getNetReply(){
QNetworkAccessManager *man = new QNetworkAccessManager(this);
QObject::connect(man, SIGNAL(finished(QNetworkReply *)), this, SLOT(replyFinished(QNetworkReply *)));
qDebug() << "connected";
QNetworkRequest req;
req.setUrl(QUrl("http://www.google.com"));
man->get(req);
}
// this method not called
void Networking::replyFinished(QNetworkReply *reply){
QByteArray data = reply->readAll();
QString str = QString(data);
this->netRep = str;
code = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
}
my networking.h header file:
#ifndef NETWORKING_H
#define NETWORKING_H
#include <QObject>
#include <QNetworkAccessManager>
#include <QNetworkReply>
class Networking : public QObject
{
Q_OBJECT
public:
QString netRep;
int code;
explicit Networking(QObject *parent = 0);
void getNetReply();
public slots:
void replyFinished(QNetworkReply*);
};
#endif // NETWORKING_H
The get() function returns a QNetworkReply object. Connect to the error signal of that object and it will tell you if an error happens (and which).

Connect qnetworkaccessmanager to slot

Now I have this code:
requester.h
#ifndef REQUESTER_H
#define REQUESTER_H
#include <QtNetwork/QNetworkAccessManager>
#include <QtNetwork/QNetworkReply>
#include <QtCore/QtCore>
#include <QVector>
#include <QObject>
class Requester
{
Q_OBJECT
public:
Requester();
~Requester();
QString get_last_reply();
void send_request();
private:
QNetworkAccessManager *manager;
QVector<QString> replies;
public slots:
void get_reply(QNetworkReply *reply);
};
#endif // REQUESTER_H
requester.cpp
#include "requester.h"
Requester::Requester()
{
manager = new QNetworkAccessManager;
}
Requester::~Requester() {
delete manager;
}
void Requester::get_reply(QNetworkReply *reply) {
QByteArray res = reply->readAll();
QString data = res.data();
replies.push_back(data);
}
QString Requester::get_last_reply() {
QString res = replies.back();
replies.pop_back();
return res;
}
void Requester::send_request() {
QObject::connect(manager, SIGNAL(finished(QNetworkReply*)), this, SLOT(get_reply(QNetworkReply*)));
manager->get(QNetworkRequest(QUrl("http://google.com")));
}
And this error:
no matching function for call to 'QObject::connect(QNetworkReply*&, const char*, Requester* const, const char*)'
What's wrong? I've tried to use just connect instead of QObject::connect, but there was an error about the impossibility of converting QNetworkAccessmanager to socket.
The problem is that you are not inheriting QObject, so naturally: you cannot get slots handled in that class.
You should write something like this:
requester.h
class Requester : public QObject
{
Q_OBJECT
public:
explicit Requester(QObject *parent);
...
requester.cpp
#include "requester.h"
Requester::Requester(QObject *p)
: QObject(p)
, manager(new QNetworkAccessManager)
{
}
...
Also, there is little to no point in this case to construct the QNetworkAccessManager on the heap as opposed to the stack. You could just have a QNetworkAccessManager m_networkAccessManager; member without the allocation, construction, and deletion, but this is just an additional information for the future.

Calling slots from a Class in Qt

I am trying to program an App that fetches files from a server.
I have a 'Window' class(mainwindow.cpp, which is a widget class that would be the UI) and then I have a 'Backend' class(Backend.cpp).
The GUI has a push button and two radio buttons. If the radio button "remote" is seleted, then upon clicking the push button will lead to fetching files from server.
However, there is some problem in the 'connect' call in Backend.cpp which I can't figure out. The error I get is: no matching function call to 'QObject::connect(QNetworkReply*&), const char[13], Backend* const, const char[20])'
Here are the codes:
ANSWER: Avoid circular inclusions!!!!
Here are the updated codes:
mainwindow.h
#ifndef WINDOW_H
#define WINDOW_H
#include <QWidget>
#include <QRadioButton>
#include <QtNetwork/QTcpSocket>
#include <QtNetwork/QHostAddress>
#include <QFile>
#include <QUrl>
#include "Backend.h"
class QGroupBox;
class Window : public QWidget
{
Q_OBJECT
public:
Window(QWidget *parent = 0);
QTcpSocket *conn;
QFile *file;
QUrl url;
Backend backend_inst;
private:
QRadioButton *button_local;
QRadioButton *button_remote;
QGroupBox *createPushButtonGroup();
private slots:
void onClick_button1();
void onCheck_local();
void onCheck_remote();
};
#endif
mainwindow.c
#include <QtGui>
#include "mainwindow.h"
Window::Window(QWidget *parent)
: QWidget(parent)
{
QGridLayout *grid = new QGridLayout;
grid->addWidget(createPushButtonGroup(), 1, 1);
setLayout(grid);
setWindowTitle(tr("File-Fetch App"));
resize(480, 420);
}
QGroupBox *Window::createPushButtonGroup()
{
QGroupBox *groupBox = new QGroupBox();
QPushButton *pushButton1 = new QPushButton(tr("Fetch Files!!"));
button_local = new QRadioButton(tr("&Download Files from Local Storage"));
button_remote = new QRadioButton(tr("&Download Files from a Web-Server"));
button_local->setChecked(1);
connect(pushButton1,SIGNAL(clicked()), this, SLOT(onClick_button1()));
QVBoxLayout *vbox = new QVBoxLayout;
vbox->addWidget(pushButton1);
vbox->addSpacing(50);
vbox->addWidget(button_local);
vbox->addWidget(button_remote);
vbox->addStretch(1);
groupBox->setLayout(vbox);
return groupBox;
}
void Window::onClick_button1()
{
QTextStream out(stdout);
out << "fetch button clicked\n";
if (button_local->isChecked()){
onCheck_local();
}
else if (button_remote->isChecked()){
onCheck_remote();
}
}
void Window::onCheck_local()
{
QTextStream out(stdout);
out << "local update button checked\n";
}
void Window::onCheck_remote()
{
QTextStream out(stdout);
out << "remote update button checked\n";
QString pathname= "http://192.168.1.1:8000/example.txt";
QUrl webaddr = pathname;
backend_inst.FetchFile(webaddr);
}
Backend.h
#ifndef BACKEND_H
#define BACKEND_H
#include <QObject>
#include <QNetworkReply>
#include <QNetworkAccessManager>
#include <QUrl>
#include <QTextStream>
class Backend : public QObject
{
Q_OBJECT
public:
Backend(QObject* parent=0);
void FetchFile(QUrl fpath);
public slots:
void getBytesFromFile();
private:
QNetworkReply *reply;
QNetworkAccessManager qnam;
};
#endif // BACKEND_H
Backend.cpp
#include "Backend.h"
Backend::Backend(QObject* parent)
: QObject(parent)
{
}
void Backend::FetchFile(QUrl fpath)
{
reply = qnam.get(QNetworkRequest(fpath));
QObject::connect(reply, SIGNAL(readyRead()),this, SLOT(getBytesFromFile()));
//qnam = new QNetworkAccessManager;
//QObject::connect(&qnam, SIGNAL(finished(QNetworkReply*)), this, SLOT(getBytesFromFile()));
}
void Backend::getBytesFromFile(){
QByteArray downloadedData;
QTextStream out(stdout);
out << "we are loading data from URL\n";
downloadedData =reply->readAll();
out << downloadedData;
delete reply;
}
main.cpp
#include <QApplication>
#include "mainwindow.h"
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
Window window;
window.show();
return app.exec();
}
To use signals and slots, your classes (both signaling and slotting) must derive from QObject, i.e.
#include "mainwindow.h"
#include <QObject>
class Backend : public QObject
{
Q_OBJECT
public:
Backend(QObject* parent=0);
[...]
Backend::Backend(QObject* parent)
: QObject(parent)
{
}
You posted this:
class Backend
{
// Q_OBJECT
public:
Backend();
void FetchFile(QUrl fpath);
public slots:
void getBytesFromFile();
private:
QNetworkReply *reply;
QNetworkAccessManager qnam;
};
Q_OBJECT is still commented if yes remove it.. you are using signal and slots..
EDIT :
try to avoid circular inclusion:
you included Backend in mainwindow and viceversa..
The commented out lines:
qnam = new QNetworkAccessManager;
QObject::connect(&qnam, SIGNAL(finished(QNetworkReply*)), this, SLOT(getBytesFromFile()));
Were what's causing your issue. Connect excepts a pointer, not a pointer-to-pointer. qnam is a pointer was a pointer in the previous version of the code and using the address-of operator on it would turn it into a pointer-to-pointer. Second mistake is that you need to have the same signature for your signal and slot in order to get it called (otherwise you get a runtime error). So, correctly:
connect(qnam, SIGNAL(finished(QNetworkReply*)), this, SLOT(getBytesFromFile(QNetworkReply*)));
(and obviously, change the actual signature of the getBytesFromFile method).
As to why your error persists despite commenting the code out: I think you are running an old build and the new one is failing to build due to the vtable issue (as you described in the comment thread). My guess is that qmake is glitching out, which I have experienced when adding the Q_OBJECT macro to already existing classes. Go to your build folders and delete Makefile* everywhere. Then go back to Qt creator and rebuild the project, that should force qmake to generate the Makefiles again.
It seems you have some problems with build mechanism. With posted code and un-commented
QObject::connect(&qnam, SIGNAL(finished(QNetworkReply*)), this, SLOT(getBytesFromFile())); in Backend::FetchFile function, all your code works. Running and with checked "Download Files from Web-Server" it prints the "we are loading data from URL" from getBytesFromFile - isn't this the slot you want to be called ?