C++ 阻止等待异步Qt信号

C++ 阻止等待异步Qt信号,c++,qt,qt4,C++,Qt,Qt4,我知道,下面还有一些类似的问题,但我找不到一个具体的答案来帮助我。所以我的问题是: 我在一个应用程序上工作,该应用程序在启动时进行一些gui初始化。我必须做的事情之一就是打电话 NetworkConfigurationManager::updateConfigurations () 这是一个异步调用,完成后会发出updateCompleted()信号。问题是,我的所有其他gui初始化都必须等待updateConfigurations()完成 所以我能做的就是这样: MyApp::MyApp(Q

我知道,下面还有一些类似的问题,但我找不到一个具体的答案来帮助我。所以我的问题是:

我在一个应用程序上工作,该应用程序在启动时进行一些gui初始化。我必须做的事情之一就是打电话

NetworkConfigurationManager::updateConfigurations ()
这是一个异步调用,完成后会发出
updateCompleted()
信号。问题是,我的所有其他gui初始化都必须等待
updateConfigurations()
完成

所以我能做的就是这样:

MyApp::MyApp(QWidget *parent) : ....
{
   doSomeInits();
   //Now connect the signal we have to wait for
   connect(configManager, SIGNAL(updateCompleted()), this, SLOT(networkConfigurationUpdated()));
   configManager->updateConfigurations(); //call the async function
}

void MyApp::networkConfigurationUpdated()
{
   doSomething();
   doRemainingInitsThatHadToWaitForConfigMgr();
}
对我来说,分开初始化似乎不是一个好办法。我认为这会使代码更难阅读——init应该保持在一起。另一件事是:因为
updateConfiguration()
异步的,用户将能够使用GUI,它还没有给他任何信息,因为我们正在等待
updateCompleted()

那么,在应用程序继续之前,是否有办法等待
updateCompleted()
信号

比如:

在某些API中,有异步函数的阻塞替代方案,但在本例中没有


谢谢你的帮助。谢谢

实现这一点的方法是使用嵌套的事件循环。您只需创建自己的QEventLoop,将想要等待的任何信号连接到循环的
quit()
插槽,然后
exec()
循环。这样,一旦调用该信号,它将触发QEventLoop的
quit()
插槽,从而退出循环的
exec()

从的工作中,如果您要等待用户注意到的时间,您可能希望显示a(或者,可能是a)


另一个解决办法是使用。这个函数是在Qt5中引入的,它完全满足您的需要


我看到该类的唯一问题是它是在QtTest模块中提供的。在我的例子中,我发现它在测试代码时非常有用,但它可能不是生产代码的最佳解决方案

是的,这是有效的,这是“阻止等待而不阻止UI”的标准模式。如果可能的话,我会尽量避免。嵌套事件循环可能会导致严重的问题,例如,用户在loop.exec()时执行随机的不可见操作,退出应用程序等,在exec()返回后使应用程序处于不可见、不一致的状态。或者:一个(用户)事件打开另一个本地事件循环,等待一个需要第一个循环完成的事件,从而导致一种准死锁。这就是为什么我建议使用一个插槽并继续使用,即使这更详细。首先:感谢您的帮助。你的答案是正确的,尽管它在我的解决方案中不起作用。我想我遇到了Frank提到的问题之一,因为我的循环无法退出。尽管如此,我还是在诺基亚Wiki()中找到了您答案的证据。谢谢大家!根据Qt/Nokia,您不应该使用QEventloop,因为它会导致失控递归(请参阅)。这应仅用于测试。还是我误读了这篇文章?这个答案对于编写自动化测试用例很方便,谢谢!弗兰克是对的——QEventLoop方法是危险的。我好不容易才发现这一点。我有一个应用程序需要以正确的顺序获取多个网页,并且逻辑在状态机中从一个函数跳到另一个函数,因此我尝试使用QEventLoop。当我这样做的时候,如果用户在事件循环中移动窗口(或某些其他东西),窗口焦点就会丢失。整个应用程序都会冻结。所有的应用程序都会冻结!点击alt tab是恢复控制的唯一方法,然后它将再次正常运行。所以是的。。。这不是一个好的解决方案。内部似乎与
chalup
的答案相同。
MyApp::MyApp(QWidget *parent) : ....
{
   doSomeInits();
   //Now connect the signal we have to wait for
   connect(configManager, SIGNAL(updateCompleted()), this, SLOT(doSomething()));
   ???? //wait until doSomething() is done.
   doRemainingInitsThatHadToWaitForConfigMgr();
}
MyApp::MyApp(QWidget *parent) : ....
{
    doSomeInits();
    {
        QEventLoop loop;
        loop.connect(configManager, SIGNAL(updateCompleted()), SLOT(quit()));
        configManager->updateConfigurations(); 
        loop.exec();
    }
    doReaminingInitsThatHadToWaitForConfigMgr();
}
MyApp::MyApp(QWidget *parent) : ....
{
    doSomeInits();
    {
        QSpashScreen splash;
        splash.connect(configManager, SIGNAL(updateCompleted()), SLOT(close()));
        configManager->updateConfigurations(); 
        splash.exec();
    }
    doReaminingInitsThatHadToWaitForConfigMgr();
}