I'm pretty new to Qt
and programming and are facing a problem I can't find a solution for.
I want to read some information from an online XML file and send it to my main program.
To do so, I created a class XMLParser and added the following to the constructor:
XMLParser::XMLParser(QString searchstring)
{
QNetworkAccessManager *manager2 = new QNetworkAccessManager(this);
reply = manager2->get(QNetworkRequest(QUrl("http://www.boardgamegeek.com/xmlapi/search?search="+searchstring)));
XMLParser::connect(reply, SIGNAL(finished()),
this, SLOT(fileIsReady()) );
}
and fileIsReady
fills a QMap and stores it as a private class member.
In my second class, I call
XMLParser *xmlpars = new XMLParser(input_gamename->text());
QMap<QString, int> searchResults = xmlpars->getSearchList();
and getSearchList is a simple getter function.
The problem is, that getSearchList is executed before fileIsReady finished reading the XML file and returns an empty map.
From what I understand, the constructor should not be finished until fileIsReady()
finished its work. And thus, getSearchList() shouldn't be called early.
My two questions:
- Why does my programm progresses while the function didn't finish reading.
- How can I make the second call "getSearchList" wait?
Thanks a lot in advance!
You don't! Instead, just move any code that expect the
XML
file to be downloaded into thefileIsReady()
slot that you've already defined. That way your program won't lock up while it's waiting for the download to complete (which is the entire point of asynchronous programming.)So, I found a solution using QEventLoop. But as far as I read, this isn't recommendend. Are there any other solutions? And why is using QEventLoop bad habit (That's what I read from other answers here StackOverflow).
First, you need to understand the fundamental concept of signals and slots.
After you make a connection, the slot will get called every time the signal is emitted.
The
connect()
functions returns after connecting the signal to the slot. It doesn't wait for the signal to be emitted.In your XMLParser constructor, your
connect()
function registers this: "When thefinished()
signal is emitted, run thefileIsReady()
function".Now, to answer your questions.
Because in your constructor code, you asked the constructor to finish after you connect the signal to the slot. You did not ask it to wait for the download to finish.
And then, you call getSearchList() without waiting for the finished() signal. So, getSearchList() gets called before fileIsReady().
Like MrEricSir said, you shouldn't ask it to wait! (Think about it: What happens if you lose internet connection and can't finish downloading the file? The answer is, your program will freeze because it will wait forever. That's bad.)
Don't call
getSearchList()
immediately after constructing XMLParser. Instead, make XMLParser emit a "finishedParsing()" signal when it finishes parsing the XML file. Then, make another signal-slot connection: Connect the finishedParsing() signal to a slot that calls getSearchList().