Qt 中的异步函数调用

Asynchronous function calls in Qt

本文关键字:函数调用 异步 Qt      更新时间:2023-10-16

我对Qt和编程很陌生,面临着一个我找不到解决方案的问题。

我想从在线XML文件中读取一些信息并将其发送到我的主程序。

为此,我创建了一个类 XMLParser,并将以下内容添加到构造函数中:

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

fileIsReady填充 QMap 并将其存储为私有类成员。

在第二节课上,我打电话

  XMLParser *xmlpars = new XMLParser(input_gamename->text());
  QMap<QString, int> searchResults = xmlpars->getSearchList();

getSearchList是一个简单的getter函数。

问题是,getSearchList 是在 fileIsReady 完成读取 XML 文件并返回空映射之前执行的。据我了解,构造函数不应该在fileIsReady()完成其工作之前完成。因此,getSearchList() 不应该被提前调用。

我的两个问题:

  1. 为什么我的程序在函数没有完成读取时进行。
  2. 如何让第二个调用"getSearchList"等待?

提前非常感谢!

首先,您需要了解信号和插槽的基本概念。

建立连接后,每次发出信号时都会调用该插槽。

将信号连接到插槽后,connect()功能返回。它不会等待信号发出。

在 XMLParser 构造函数中,connect() 函数注册以下内容:"发出finished()信号时,运行 fileIsReady() 函数"。

现在,回答您的问题。

  1. 为什么我的程序在函数没有完成读取时进行。
因为在构造函数

代码中,您要求构造函数在将信号连接到插槽后完成。您没有要求它等待下载完成。

然后,你调用getSearchList(),而不等待done()信号。因此,getSearchList() 在 fileIsReady() 之前被调用。

  1. 如何让第二个调用"getSearchList"等待?

就像埃里克先生说的,你不应该要求它等待!(想一想:如果您失去互联网连接并且无法完成文件下载,会发生什么?答案是,你的程序会冻结,因为它会永远等待。这很糟糕。

不要在构造 XMLParser(getSearchList())后立即调用。相反,让 XMLParser 在完成解析 XML 文件时发出"finishParsing()"信号。然后,建立另一个信号槽连接:将完成的Parsing()信号连接到调用getSearchList()的时隙。

因此,我使用QEventLoop找到了解决方案。但据我所知,这不是推荐的。还有其他解决方案吗?以及为什么使用QEventLoop是坏习惯(这是我从StackOverflow的其他答案中读到的)。

XMLParser::XMLParser(QString searchstring)
{
QNetworkAccessManager *manager2 = new QNetworkAccessManager(this);
reply = manager2->get(QNetworkRequest(QUrl("http://www.boardgamegeek.com/xmlapi/search?search="+searchstring)));
QEventLoop loop;
XMLParser::connect(reply, SIGNAL(finished()),
                   this, SLOT(fileIsReady()) );
XMLParser::connect(this, SIGNAL(finishedReading()),
                   &loop, SLOT(quit()));
loop.exec();
}

如何在等待getSearchList进行第二次呼叫?

你没有!相反,只需将任何希望将XML文件下载到已定义的fileIsReady()槽的代码即可。这样,您的程序在等待下载完成时就不会锁定(这是异步编程的全部意义所在)。