Заблокировано ожидание асинхронного сигнала Qt - PullRequest
22 голосов
/ 24 августа 2010

Я знаю, что есть несколько подобных вопросов, но я не мог найти конкретный ответ, который мне помог бы.Итак, вот моя проблема:

Я работаю над приложением, которое запускает некоторые графические инициализации при запуске.Одна из вещей, которые я должен сделать, это вызвать

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

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

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

Ответы [ 3 ]

23 голосов
/ 24 августа 2010

Способ сделать это - использовать вложенные циклы событий. Вы просто создаете свой собственный QEventLoop, подключаете любой сигнал, который хотите ждать, к слоту quit() цикла, а затем exec() цикл. Таким образом, после вызова сигнала он активирует слот quit() QEventLoop, поэтому выходит из цикла exec().

.
MyApp::MyApp(QWidget *parent) : ....
{
    doSomeInits();
    {
        QEventLoop loop;
        loop.connect(configManager, SIGNAL(updateCompleted()), SLOT(quit()));
        configManager->updateConfigurations(); 
        loop.exec();
    }
    doReaminingInitsThatHadToWaitForConfigMgr();
}
7 голосов
/ 24 августа 2010

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

MyApp::MyApp(QWidget *parent) : ....
{
    doSomeInits();
    {
        QSpashScreen splash;
        splash.connect(configManager, SIGNAL(updateCompleted()), SLOT(close()));
        configManager->updateConfigurations(); 
        splash.exec();
    }
    doReaminingInitsThatHadToWaitForConfigMgr();
}
1 голос
/ 05 января 2017

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...