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);
Related
I've created a class called CSocket:
CSocket.h
#ifndef CSOCKET_H
#define CSOCKET_H
#include <QtCore/QObject>
#include <QtWebSockets/QWebSocket>
class CSocket : public QObject
{
Q_OBJECT
public:
explicit CSocket(QObject *parent = nullptr);
void onConnect(const QUrl &url);
void onSendMesssage(QString message);
signals:
void closed();
private slots:
void onConnected();
void onTextMessageReceived(QString message);
private:
QWebSocket m_webSocket;
QUrl m_url;
};
#endif // CSOCKET_H
CSocket.cpp
#include "csocket.h"
#include <QtCore/QDebug>
#include <QJsonObject>
#include <QJsonArray>
#include <QJsonDocument>
#include <QMessageBox>
QT_USE_NAMESPACE
CSocket::CSocket(QObject *parent) : QObject(parent)
{
}
void CSocket::onConnect(const QUrl &url)
{
m_url = url;
connect(&m_webSocket, &QWebSocket::connected, this, &CSocket::onConnected);
connect(&m_webSocket, &QWebSocket::disconnected, this, &CSocket::closed);
m_webSocket.open(QUrl(url));
}
void CSocket::onConnected()
{
connect(&m_webSocket, &QWebSocket::textMessageReceived, this, &CSocket::onTextMessageReceived);
}
void CSocket::onTextMessageReceived(QString message)
{
QMessageBox::information(nullptr, "Answer", message, QMessageBox::Ok);
}
void CSocket::onSendMesssage(QString message)
{
m_webSocket.sendTextMessage(message);
}
In main window (QWidget) i create a connection:
CSocket *socket = new CSocket;
socket->onConnect(QUrl(QStringLiteral("ws://localhost:8080")));
Now is the question: how can i share the connection to another QWidget or QDialog? I just don't want to reconnect in the new window. Does someone know how to do it?
Assuming that within your entire application you only want a connection as indicated, an appropriate pattern would be the singleton:
csocket.h
#ifndef CSOCKET_H
#define CSOCKET_H
#include <QObject>
#include <QWebSocket>
class CSocket : public QObject
{
Q_OBJECT
public:
static CSocket *instance();
void onConnect(const QUrl &url);
void onSendMesssage(QString message);
signals:
void closed();
private slots:
void onConnected();
void onTextMessageReceived(QString message);
private:
static CSocket* m_instance;
explicit CSocket(QObject *parent = nullptr);
QWebSocket m_webSocket;
QUrl m_url;
};
#endif // CSOCKET_H
csocket.cpp
#include "csocket.h"
#include <QMessageBox>
CSocket* CSocket::m_instance = nullptr;
CSocket::CSocket(QObject *parent) : QObject(parent)
{
}
CSocket *CSocket::instance()
{
if (m_instance == nullptr)
m_instance = new CSocket;
return m_instance;
}
void CSocket::onConnect(const QUrl &url)
{
m_url = url;
connect(&m_webSocket, &QWebSocket::connected, this, &CSocket::onConnected);
connect(&m_webSocket, &QWebSocket::disconnected, this, &CSocket::closed);
m_webSocket.open(QUrl(url));
}
void CSocket::onConnected()
{
connect(&m_webSocket, &QWebSocket::textMessageReceived, this, &CSocket::onTextMessageReceived);
}
void CSocket::onTextMessageReceived(QString message)
{
QMessageBox::information(nullptr, "Answer", message, QMessageBox::Ok);
}
void CSocket::onSendMesssage(QString message)
{
m_webSocket.sendTextMessage(message);
}
So instead of using the constructor you should use the instance() method:
//mainwindow
CSocket *socket = CSocket::instance();
socket->onConnect(QUrl(QStringLiteral("ws://localhost:8080")));
// another window
CSocket *socket = CSocket::instance();
As you can see there will only be one CSocket that is shared by all the windows.
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?
}
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);
}
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).
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.