2014-11-19 2 views
1

Я довольно новый для Qt и программирования и сталкиваются с проблемой. Я не могу найти решение.Асинхронные вызовы функций в Qt

Я хочу прочитать некоторую информацию из онлайн-файла XML и отправить его в мою основную программу.

Для этого я создал класс XmlParser и добавил следующее конструктору:

и fileIsReady заполняет QMap и сохраняет его в качестве члена частного класса.

В моем втором классе, я называю

XMLParser *xmlpars = new XMLParser(input_gamename->text()); 
    QMap<QString, int> searchResults = xmlpars->getSearchList(); 

и getSearchList является простой функцией добытчика.

Проблема заключается в том, что getSearchList выполняется до того, как fileIsReady закончил чтение XML-файла и возвращает пустую карту. Из того, что я понимаю, конструктор не должен заканчиваться до тех пор, пока fileIsReady() не закончит свою работу. И таким образом, getSearchList() не следует вызывать раньше.

Мои два вопроса:

  1. Почему моя программа прогрессирует, пока функция не дочитать.
  2. Как я могу сделать второй вызов «getSearchList» ждать?

Большое спасибо!

ответ

3

Во-первых, вам необходимо понять основную концепцию сигналов и слотов.

После того, как вы установили соединение, слот будет вызываться каждый раз, когда выдается сигнал.

Функции connect() возвращаются после подключения сигнала к слоту. Он не дожидается, когда сигнал будет испускаться.

В вашем конструкторе XMLParser ваша функция connect() регистрирует это: «Когда выдается сигнал finished(), запустите функцию fileIsReady()».

Теперь, чтобы ответить на ваши вопросы.

  1. Почему моя программа прогрессирует, пока функция не дочитать.

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

И тогда вы вызываете getSearchList(), не дожидаясь окончания() сигнала. Итак, getSearchList() вызывается перед fileIsReady().

  1. Как я могу сделать второй вызов «getSearchList» ждать?

Как MrEricSir сказал, вы не должны попросить его подождать! (Подумайте об этом: что произойдет, если вы потеряете интернет-соединение и не сможете закончить загрузку файла? Ответ: ваша программа замерзнет, ​​потому что она будет ждать вечно. Это плохо.)

Не вызывайте getSearchList() сразу после построение XMLParser. Вместо этого заставить XMLParser выдавать сигнал «finishedParsing()», когда он заканчивает разбор XML-файла. Затем выполните другое соединение с сигнальным слотом: Подключите сигнал завершенной обработки() к слоту, который вызывает getSearchList().

+0

Большое спасибо за помощь! Помог понять, что происходит. Можно ли сказать: давайте подождем, пока не будут отправлены все сигналы (или список сигналов)? Я реализовал еще одно соединение, но это может задержать ту же проблему, вызвав проблемы в другом месте. Можно ли подключить возврат функции с таким сигналом «finishedReading»? – ARTcrime

1

Как сделать второй звонок getSearchList wait?

У вас нет! Вместо этого просто переместите любой код, который ожидает, что файл XML будет загружен в слот fileIsReady(), который вы уже определили. Таким образом, ваша программа не будет заблокирована, пока она ждет завершения загрузки (что является всей точкой асинхронного программирования.)

+0

Спасибо за ответ. Я не могу поместить getSearchList в функцию fileIsReady, поскольку я вызываю его извне, чтобы получить результат. Думаю, я не уточнил свой вопрос. Конструктор ожидает, что XML-файл будет готов, но во втором классе getSearchList будет выполнен до завершения конструктора. По крайней мере, это то, что я думаю. – ARTcrime

1

Итак, я нашел решение с помощью QEventLoop. Но, насколько я читал, это не рекомендуется. Есть ли другие решения? И почему используется плохая привычка QEventLoop (вот что я читаю из других ответов здесь StackOverflow).

XMLParser::XMLParser(QString searchstring) 
{ 

QNetworkAccessManager *manager2 = new QNetworkAccessManager(this); 
reply = manager2->get(QNetworkRequest(QUrl("http://www.boardgamegeek.com/xmlapi/search?search="+searchstring))); 

QEventLoop loop; 
XMLParser::connect(reply, SIGNAL(finished()), 
        this, SLOT(fileIsReady())); 
XMLParser::connect(this, SIGNAL(finishedReading()), 
        &loop, SLOT(quit())); 
loop.exec(); 

} 
Смежные вопросы