Заблокировано ожидание асинхронного сигнала 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 существует блокировка альтернатив асинхронным функциям, но не в этом случае.
Я ценю любую помощь. Спасибо!
Ответы
Ответ 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. В моем случае я считаю это очень полезным при тестировании кода, но это может быть не лучшее решение для производственного кода.