QNetworkAccessManager without show() freezes program
-
Hi,
I have a member function (let's say: functionA) of a QDialog class (GUI) in which QNetworkAccessManager is used, like this:
nam = new QNetworkAccessManager(this);
In main.cpp I create the QDialog object (let's say: dialog). And I'd like to use the member function without showing the dialog GUI.
However, calling the member function without first using show(), like this:dialog.functionA(); // function does execute, but then freezes at QNAM
results in the application hanging at the QNetworkAccessManager line.
What I do not understand is why I am able to solve the problem by showing and then hiding the GUI like this:
dialog.show(); // briefly shows the gui dialog.hide(); // hides the gui again dialog.functionA(); // now all of a sudden it does work
I suspect the problem has to do with threading but what does show() have to do with that?
Is there a more efficient way for me to accomplish my goal other than show() followed by hide()? Because there is a visible delay between showing and hiding when using this method.
Kind regards,
Sanchez -
Hi, welcome to the forum.
I don't think it has anything to do with threading or specifically showing/hiding a window.
You're probably just using QNAM wrong. See if usingqApp->processEvents()
instead of show/hide fixes the problem. If it does then you're definitely doing it wrong.
Show the code offunctionA
and specifically how you're handling the request and response so we can see what's going on. -
Hi,
The processEvents trick works. But I assume it would be unwise to use it?
functionA (with the actual parameters this time):
void dialog::functionA(const QString &username, const QString &uid) { QUrl url(m_someURL); QUrlQuery query; query.addQueryItem("username", username); query.addQueryItem("id", uid); url.setQuery(query.query()); QNetworkRequest request(url); request.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded"); if(nam != NULL) delete nam; // removing this has no effect on the problem qDebug() << "nam1"; // shown nam = new QNetworkAccessManager(this); qDebug() << "nam2"; // never shown QObject::connect(nam, SIGNAL(finished(QNetworkReply*)),this, SLOT(replyFinished(QNetworkReply*))); qDebug() << "NAM created, send POST"; QByteArray data; data.append(query.toString(QUrl::FullyEncoded).toUtf8()); nam->post(request,data); }
The nam in the dialog.h:
private: QNetworkAccessManager *nam{NULL};
After "nam1", the "nam2" debug output is never shown, so the code stops executing after the QNAM line.
-
But I assume it would be unwise to use it?
Yes, very. It won't work most of the time and neither the show/hide thing. Your request just happens to be real fast in your testing, but if it takes just a little bit longer and misses the call the app will hang just the same as without it.
The root of the problem is elsewhere. QNAM needs a running event loop to properly deliver signals. Your app seems to not have one or it is in some way blocked. Usually there's an
exec()
call somewhere in your app that runs the loop. Do you have one? -
Other than a single occurence in my main function, nope.
My main (main.cpp) function has 'return a.exec();' on the bottom, way below the section where I call functionA.
This was default when I began developing this application a while ago and I don't think that could be the event loop right? Since that would only start running when the program got to the end of the main function.Kind regards,
Sanchez -
@MrSanchez said:
I don't think that could be the event loop right? Since that would only start running when the program got to the end of the main function.
That's exactly it. If you just put a bunch of code before it it will all execute sequentially and no non-direct signal/slot connections will ever work until you get to that line. If you happen to wait on some queued signal before it your app is as good as dead because no signal will ever be delivered if you don't enter that loop (unless you cheat with the tricks above, but that's like running a car on pure luck instead of gasoline ;) ).
-
@Chris-Kawa
Ah, but now I am a bit lost on how to continue.
I don't think I can start the event loop right at the beginning of main, so it will only start when it hit the end of main. So I imagine I can't have anything blocking the main function and thus blocking the start of the main event loop.The problem is, I need that event loop running before I execute most of my code.
I did some searching, would putting most of my main function's code in a separate function and instead calling QTimer::singleShot work? The problem I see with that is that it needs a QObject, a class, and I'm dealing with this in main.cppAny kick in the right direction would be appreciated loads :)
Kind regards,
Sanchez -
would putting most of my main function's code in a separate function and instead calling QTimer::singleShot work?
You're missing the point. It doesn't matter if you put it before the loop starts or after it starts. The problem is that you're blocking, so there's nothing looping and nothing delivering queued signals/events.
So what you need to do is switch your thinking from this (in pseudocode):getUserInput(); processUserInput(); startSomeRequest(); waitForItToFinish(); processResponse(); finishProgram();
to something more like this:
connect(userInput, processUserInput); connect(userInputProcessed, startSomeRequest); connect(requestFinished, processResponse); loop();
-
@Chris-Kawa
Hi,Sorry for the late reply.
Thanks for the insight, you've shown me a way to change my mindset.
I'm relatively new to using connect (I know how to use it), I'll rewrite my functions to give it the fundamental role that it deserves :)
I'll post back when I get it working, once again cheers.Kind regards,
Sanchez -
I've rewritten my program so now it no longer blocks and thus uses connect() where applicable. I did have to use singleShot for functionA() to make sure it executes after the event loop starts. Atleast won't have to use some hacky workaround like qApp->processevents() :)
Thanks for the help.
Kind regards,
Sanchez