web-dev-qa-db-ja.com

非同期Qtシグナルの待機をブロック

次のような質問がいくつかありますが、具体的な答えが見つかりませんでした。だからここに私の問題があります:

私は起動時にいくつかの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は一緒に残しておく必要があります。もう1つは、updateConfiguration()asynchronousであるため、ユーザーはまだ情報を提供していないGUIを使用できるようになります。これは、updateCompleted()

アプリケーションを続行する前に、updateCompleted()シグナルを待つ方法はありますか?

お気に入り:

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

一部のAPIには、非同期関数の代替ブロッキングがありますが、この場合はありません。

私はどんな助けにも感謝します。ありがとう!

22
cyphorious

これを行う方法は、ネストされたイベントループを使用することです。独自のQEventLoopを作成し、待機したい信号をループのquit()スロットに接続してから、exec()ループに接続するだけです。このように、シグナルが呼び出されると、QEventLoopのquit()スロットがトリガーされるため、ループのexec()が終了します。

MyApp::MyApp(QWidget *parent) : ....
{
    doSomeInits();
    {
        QEventLoop loop;
        loop.connect(configManager, SIGNAL(updateCompleted()), SLOT(quit()));
        configManager->updateConfigurations(); 
        loop.exec();
    }
    doReaminingInitsThatHadToWaitForConfigMgr();
}
23
chalup

chalup 's answer から作業している場合、ユーザーが気付く時間を待つ場合は、 プログレスバー を表示することをお勧めします。代わりに(または スプラッシュ画面 、おそらく)。

MyApp::MyApp(QWidget *parent) : ....
{
    doSomeInits();
    {
        QSpashScreen splash;
        splash.connect(configManager, SIGNAL(updateCompleted()), SLOT(close()));
        configManager->updateConfigurations(); 
        splash.exec();
    }
    doReaminingInitsThatHadToWaitForConfigMgr();
}

別の解決策は、 QSignalSpy :: wait() を使用することです。この機能はQt5で導入され、まさにあなたが望むことをします。

そのクラスで私が見る唯一の問題は、それがQtTestモジュールで提供されることです。私の場合、コードをテストするときに非常に便利ですが、本番コードには最適なソリューションではない可能性があります。

1
piponazo