I'm trying to write a Qt app that calls a web service. This is a console app, and url will be passed in as a command line argument. I searched for example http programs in Qt and found this link:
http://qt-project.org/doc/qt-5/qnetworkaccessmanager.html
Here it has the following code example:
QNetworkAccessManager *manager = new QNetworkAccessManager(this);
connect(manager, SIGNAL(finished(QNetworkReply*)),
this, SLOT(replyFinished(QNetworkReply*)));
manager->get(QNetworkRequest(QUrl("http://qt-project.org")));
Now, if I take this and paste it into my console app, in main, I obviously get build errors because this does not exist. I get :
invalid use of 'this' in non-member function
Is there an equivalent QNetworkAccessManager for non-GUI/console type apps?
"this" is the this pointer of an object, so in main.cpp it causes errors, you should write some class where you will work with network and after that use this class in main function
It should be something like this. When you run app, you'll get html code of Qt site
It is just example, in future we can add here constructot, destructor, maybe signals(signals help us communicate with for example other classes if we need this)
*.h
#ifndef NET_H
#define NET_H
#include <QObject>
#include <QtCore>
#include <QNetworkAccessManager>
#include <QNetworkReply>
class Net : public QObject
{
Q_OBJECT
QNetworkAccessManager *manager;
private slots:
void replyFinished(QNetworkReply *);
public:
void CheckSite(QString url);
};
#endif // NET_H
*.cpp
#include "net.h"
void Net::replyFinished(QNetworkReply *reply)
{
qDebug() << reply->readAll();
}
void Net::CheckSite(QString url)
{
QUrl qrl(url);
manager = new QNetworkAccessManager(this);
connect(manager, SIGNAL(finished(QNetworkReply*)), this, SLOT(replyFinished(QNetworkReply*)));
manager->get(QNetworkRequest(qrl));
}
main
#include "net.h"
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Net handler;
handler.CheckSite("http://qt-project.org");
return a.exec();
}
Related
I'm trying to fetch some data from an API using QNetworkRequest following this video (https://youtu.be/G06jT3X3H9E)
I have a RoR server running on localhost:3000 and I'm trying to fetch something from it.
.h file:
#ifndef WORKER_H
#define WORKER_H
#include <QObject>
#include <QDebug>
#include <QNetworkAccessManager>
#include <QNetworkReply>
#include <QNetworkRequest>
#include <QAuthenticator>
#include <QNetworkProxy>
class Worker : public QObject
{
Q_OBJECT
public:
explicit Worker(QObject *parent = nullptr);
signals:
public slots:
void get(QString code);
private slots:
void readyRead();
void authenticationRequired(QNetworkReply *reply, QAuthenticator *authenticator);
void encrypted(QNetworkReply *reply);
void finished(QNetworkReply *reply);
void networkAccessibleChanged(QNetworkAccessManager::NetworkAccessibility accessible);
void preSharedKeyAuthenticationRequired(QNetworkReply *reply, QSslPreSharedKeyAuthenticator *authenticator);
void proxyAuthenticationRequired(const QNetworkProxy &proxy, QAuthenticator *authenticator);
void sslErrors(QNetworkReply *reply, const QList<QSslError> &errors);
private:
QNetworkAccessManager manager;
};
#endif // WORKER_H
.cpp file:
void Worker::get(QString code)
{
qInfo() << "Getting something from the server...";
QNetworkReply* reply = manager.get(QNetworkRequest(QUrl(QString("http://localhost:3000/api/v1/circle_gift_cards/scan?codes=" + code))));
connect(reply, &QNetworkReply::readyRead, this, &Worker::readyRead);
}
void Worker::readyRead()
{
qInfo() << "ReadReady";
QNetworkReply* reply = qobject_cast<QNetworkReply*>(sender());
if(reply) qInfo() << reply->readAll();
}
The result from:
Worker worker;
worker.get("abc");
is: "Getting something from the server..."
it should print "ReadReady" when the request is ready, but I don't think the request is being made, there's nothing in the console either.
[Edit 1]
What is calling the worker is this
void MainWindow::on_lineEditScanCard_textChanged(QString code) {
Worker worker(this->site);
worker.get(code);
}
It's an Edit field(where the user is supposed to type a code
[Edit 2]
I removed all app code and did this:
#include <QApplication>
#include "Forms/mainwindow.h"
#include "Requests/worker.h"
int main(int argc, char *argv[]) {
QApplication a(argc, argv);
Worker worker;
worker.get("abc");
return a.exec();
}
And it worked... Why it does not work when called when the Edit text is changed?
Remember the concepts of scope, life cycle, and local variables? In your case worker is a local variable that will be destroyed instantly so the slot is not invoked, use
Worker * worker = new Worker;
worker->get("abc"); //remember to delete the memory when you no longer use it
I'm trying to get a web page using Qt and print it on the screen.The problem is it always prints "". It won't make it to the done SLOT. I don't know if there's something wrong with the connect(). The code gets compiled with no errors.
Trying not to use event loops yet.
Here's the code:
net.h
#ifndef NET_H
#define NET_H
#include <QObject>
#include <QtNetwork>
#include <QString>
#include <QDebug>
class net : public QObject
{
Q_OBJECT
public:
explicit net(QObject *parent = 0);
void get_site(QString url);
QString data;
signals:
public slots:
void err(QNetworkReply *);
void done(QNetworkReply *);
private:
};
#endif // NET_H
net.cpp:
#include "net.h"
net::net(QObject *parent) :
QObject(parent)
{
}
void net::get_site(QString url) {
QNetworkAccessManager man;
QNetworkRequest request;
request.setUrl (QUrl(url));
connect (&man , SIGNAL(finished(QNetworkReply*)) ,this, SLOT(done(QNetworkReply*)));
connect (&man , SIGNAL(finished(QNetworkReply*)) ,this, SLOT(err(QNetworkReply *)));
man.get (QNetworkRequest(QUrl(url)));
}
void net::done(QNetworkReply * reply) {
data = QString(reply->readAll ());
}
void net::err(QNetworkReply * reply) {
data = QString(reply->errorString ());
}
And main.cpp:
#include <QCoreApplication>
#include "net.h"
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
net netobj;
netobj.get_site("http://stackoverflow.com");
qDebug() << netobj.data;
return a.exec();
}
There are some major problems in your code. First you should have the QNetworkAccessManager as a class member in .h file :
class net : public QObject
{
...
private:
QNetworkAccessManager nam;
};
Also you should not connect the finished signal to two different slots. Your get_site function should be like :
void net::get_site(QString url) {
QNetworkRequest request;
request.setUrl (QUrl(url));
connect (&man , SIGNAL(finished(QNetworkReply*)) ,this, SLOT(done(QNetworkReply*)));
man.get (QNetworkRequest(QUrl(url)));
}
And you should manage the returned reply in the following way :
void net::done(QNetworkReply * reply) {
if (reply->error() == QNetworkReply::NoError)
{
data = QString(reply->readAll ());
}
else
{
data = QString(reply->errorString ());
}
}
Your QNetworkAccessManager instance goes out of scope at the end of your get_site function. According to Qt docs, one QNetworkAccessManager should be enough for the whole Qt application. Your object should persist outside the scope of that function, since it's likely the response will take longer to receive than it will take for that function to end. Make the QNetworkAccessManager a member of your net class, instead of an automatic variable local to get_site.
Note that you also need to manage the lifetime of the QNetworkReply object, not by using delete, but by using deleteLater() or else you might leak memory.
i have flash player running on QWebkit , and on the flash player there are some web links
that needs to be open in external browser , what i did is :
m_webView->page()->setLinkDelegationPolicy(QWebPage::LinkDelegationPolicy::DelegateAllLinks);
connect(m_webView->page(),SIGNAL(linkClicked(const QUrl&)),
this,
SLOT(linkClickedHandler(const QUrl&)),Qt::DirectConnection);
void WebBroswerDeleget::linkClickedHandler(const QUrl& url)
{
QDesktopServices::openUrl(QUrl(url.toString(), QUrl::TolerantMode));
}
but its never triggered even of i change in the connect from m_webView->page() to m_webView
i overrided the QWebview::createWindow like this:
QWebView* MyAdWebview::createWindow (QWebPage::WebWindowType type)
{
QWebView* p = new QWebView(0);
connect(p->page()->networkAccessManager(), SIGNAL(finished(QNetworkReply*)), this, SLOT(newWindowLoadFinished(QNetworkReply*)), Qt::UniqueConnection);
return p;
}
void MyAdWebview::newWindowLoadFinished(QNetworkReply* reply) {
QDesktopServices::openUrl(reply->url().toString());
}
QDesktopServices::openUrl is a cutom function which opens the default system browser with this url
This is working for me on both 4.7.2 QtEmbedded and 4.8.1 on mac. What I don't understand is this:
m_webView->page()->setLinkDelegationPolicy(QWebPage::LinkDelegationPolicy::DelegateAllLinks);
Just do:
m_webView->page()->setLinkDelegationPolicy(QWebPage::DelegateAllLinks);
Something like this works for me:
#include <QWebPage>
#include <QWebView>
#include <QApplication>
#include "sigrec.h"
int main(int argc, char** argv)
{
QApplication a(argc, argv);
SigRec rec;
QWebView view;
view.page()->setLinkDelegationPolicy(QWebPage::DelegateAllLinks);
QObject::connect(view.page(), SIGNAL(linkClicked(const QUrl&)), &rec, SLOT(onLinkClicked(const QUrl&)),
Qt::DirectConnection);
view.show();
view.setUrl(QUrl("http://www.google.com"));
return a.exec();
}
Where SigRec is something like this:
#ifndef SIGREC_H
#define SIGREC_H
#include <QObject>
#include <QUrl>
class SigRec : public QObject
{
Q_OBJECT
public:
explicit SigRec(QObject *parent = 0);
public slots:
void onLinkClicked(const QUrl &url);
};
#endif // SIGREC_H
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 ?
I'm trying to write an application using QNetworkManager. I have simplified the code down to the problem. The following code hangs, and I have no idea why:
main.cpp:
#include <QApplication>
#include "post.h"
int main(int argc, char *argv[]) {
QApplication app(argc, argv);
post("http://google.com/search", "q=test");
return app.exec();
}
post.h:
#ifndef _H_POST
#define _H_POST
#include <QNetworkAccessManager>
#include <QNetworkRequest>
class post : public QObject {
Q_OBJECT
public:
post(QString URL, QString data);
public slots:
void postFinished(QNetworkReply* reply);
protected:
QNetworkAccessManager *connection;
};
#endif
post.cpp:
#include <QApplication>
#include <QUrl>
#include "post.h"
post::post(QString URL, QString data) {
connection = new QNetworkAccessManager(this);
connect(connection, SIGNAL(finished(QNetworkReply*)), this, SLOT(postFinished(QNetworkReply*)));
connection->post(QNetworkRequest(QUrl(URL)), data.toAscii());
}
void post::postFinished(QNetworkReply*) {
qApp->exit(0);
}
Some Googling shows it may be because I have everything on one thread, but I have no idea how to change that in Qt... none of the network examples show this.
I just tried it with the same results. The problem is that you are creating the post object by only calling the constructor. Since you are not specifying an object it is getting destroyed right away (to check this create a destructor and see when it gets called.)
try:
post p("http://google.com/search","q=test");
Then your slot gets called.