Подтвердить что ты не робот

Заблокировано ожидание асинхронного сигнала 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();
}

Разделение инициализации не кажется мне хорошим способом. Я думаю, что это делает код намного сложнее читать - inits должны оставаться вместе. Другое дело: поскольку updateConfiguration() является асинхронным, пользователь сможет использовать 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 существует блокировка альтернатив асинхронным функциям, но не в этом случае.

Я ценю любую помощь. Спасибо!

4b9b3361

Ответ 1

Способ сделать это - использовать вложенные циклы событий. Вы просто создаете свой собственный 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();
}

Ответ 2

Работает из chalup , если вы собираетесь ждать заметного пользователя вы можете вместо этого отобразить индикатор выполнения (или заставка, возможно).

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

Ответ 3

Другим решением может быть использование QSignalSpy:: wait(). Эта функция была введена в Qt 5 и делает именно то, что вы хотите.

Единственная проблема, которую я вижу в этом классе, заключается в том, что она предоставляется в модуле QtTest. В моем случае я считаю это очень полезным при тестировании кода, но это может быть не лучшее решение для производственного кода.