user489152
user489152

Reputation: 907

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();
}

Upvotes: 0

Views: 4345

Answers (4)

milyaaf
milyaaf

Reputation: 136

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 ?

Upvotes: 0

Tam&#225;s Szelei
Tam&#225;s Szelei

Reputation: 23921

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.

Upvotes: 0

andrea.marangoni
andrea.marangoni

Reputation: 1499

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..

Upvotes: 2

Chris Browet
Chris Browet

Reputation: 4266

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)
{
}

Upvotes: 2

Related Questions