Question

A quick overview of what's happening: I am trying to do a GET request using Qt's QNetworkAccessManager, but the callback function on my QObject::connect(..) function is not being called. My questions is can I call QObject::connect from one object, but connect to a slot of another object (given that I have a pointer to both the object and the slot) - See below for more details.

My ultimate goal is to POST the data (seeing as it's a login function), I had POST Request code that was ultimately suffering from the same issue - callback function not being called. So I would like to be able to do a simple GET request first, once I have that, I think I'll be fine on my own from there.

I currently have a QMainWindow LoginWindow, with a button that calls a slot doLogin() in the LoginWindow class. This all works as you would expect. LoginWindow also has a public slots function called loginResponse(QNetworkReply* response).

//---LoginWindow.h

...

public slots:
    void doLogin();
    void loginResponse(QNetworkReply* response)

...

//---LoginWindow.cpp

LoginWindow::LoginWindow(QWidget *parent) :
    QMainWindow(parent),
ui(new Ui::LoginWindow)
{
    ui->setupUi(this);
    ui->username_le->setFocus();
}

void LoginWindow::doLogin()
{
   MyProduct::Network network(this);
    qDebug() << "Logging in...";

    //Here I call network.login from LoginWindow and pass 
    //references to the Slot I want to use and the LoginWindow itself
    network.login(
        ui->username_le->text(), //username
        ui->password_le->text(), //password
        this,                    //reference to this object (LoginWindow*)
        SLOT(loginResponse(QNetworkReply*)) //loginResponse slot
    );
}

void LoginWindow::loginResponse(QNetworkReply* response)
{
    qDebug() << "Log in complete";
}

Next I have another class, under the MyProduct namespace, called Network. As you can see above, Network has a function called login. Here it is:

void MyProduct::Network login(QString username, QString password, QObject *receiver, const char *slot)
{
    QNetworkRequest request(QUrl(API_ROOT + LOGIN_PATH)); //"http://localhost/basic/login.php"
    request.setHeader(QNetworkRequest::ContentTypeHeader,"application/x-www-form-urlencoded");

    //nam = QNetworkAccessManager* declared in the constructor
    QObject::connect(nam,SIGNAL(finished(QNetworkReply*)), receiver, slot);

    qDebug() << "Posting login data...";
    nam->get(request);
}

The goal here is to create a login function in my Network class that can be used and connected in any number of windows (as users may log in from multiple places). But I'm getting no response - LoginWindow::loginResponse is not run.

I see "Logging in..." and "Posting login data" output in the console, but not "Log in complete".

Can anyone please point me in the right direction or tell me I'm crazy or that this is a bad idea?

Thanks in advance!

Was it helpful?

Solution

Note that QNetworkAccessManager operates asynchronously. The get() method does not block while the network operation occurs; it returns immediately. (See the Detailed Description section of the documentation for more info.)

This is pretty typical of Qt's network-related APIs, because you usually don't want your application to freeze while waiting for data to move across a network.

What this means is what your instance, nam, isn't alive long enough for the GET request to actually finish. Your instance of the Product::Network class is deleted immediately after the call to login() because it's allocated on the stack. Although I can't see the code, I'm guessing it cleans up the QNetworkAccessManager as well.

If you extend the lifetime of your network object, you may find that your slot will eventually be invoked.


Also, this is more a matter of preference, but I think it would be cleaner to avoid passing a receiver and a slot to your login() function. I'd recommend declaring your own signals in the Network class as part of its API, and to connect to those in the LoginWindow class.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top