Russian Qt Forum

Qt => Общие вопросы => Тема начата: BredoGen от Июль 09, 2010, 15:48



Название: QNetworkReply. Нужна помощь в организации слотов.
Отправлено: BredoGen от Июль 09, 2010, 15:48
Приветствую. Возникли некоторые проблемы с организацией слотов.

Моя задача:
Имеется QTableWidget наполненный данными. Я должен:
  • в цикле считать каждую строчку по отдельности
  • используя строчку сформировать ссылку
  • Далее получить html страницу
  • выдернуть оттуда данные
  • и вписать их в соседний column (соседний к текущей взятой строчке)


Не было бы проблем, если бы я использовал только один метод получения данных. В этом случае я бы просто использовал:
Код:
connect(reply, SIGNAL(finished()),
             this, SLOT(httpFinished()));

Но мне нужно получить несколько страниц с использованием данной строки и выдернуть из них несколько данных.

Ну допустим вот так всё это будет:
Код:
void MainWindow::start() {
    for (int i=0; i < table->rowCount(); ++i) {
        //Тут я беру table->item(i, 0)->text() и должен получить страницы
        //Далее я должен их распарсить и получить свои данные
        
        //Далее присваиваю распарсенные данные соседнему столбцу
        QTableWidgetItem *newItem = new QTableWidgetItem(); //Новое значение
        
        table->setItem(i, 1, newItem);

        QTableWidgetItem *newItem1 = new QTableWidgetItem(); //Новое значение2
        
        table->setItem(i, 1, newItem1);
        
    }

}

Как лучше всё это организовать? Если использовать обычный метод, то данные я смогу получить в слоте httpFinished(), а мне они нужны в цикле, чтобы присвоить нужному столбцу полученные значения.

У меня есть пара вариантов:
1. Использовать функции извлечения параметров из страниц как слоты завершения запроса для QNetworkReply.
Например:
Код:
//Тут я формирую запрос
connect(reply, SIGNAL(finished()),
             this, SLOT(GetMyFirstValue()));

//Тут я формирую второй запрос
connect(reply, SIGNAL(finished()),
             this, SLOT(GetMySecondValue()));

Как только запрос закончиться - я получу исходник страницы в слоте GetMyNValue() тут я спарсю нужные данные. Но теперь тупик: я не знаю в какую строчку таблицы нужно вставить данные.
Может использовать для этих целей глобальную переменную, которая будет одновременно счетчиком цикла и числом текущей позиции, чтобы я смог в слоте вставить данные в нужную строку?
И еще я хотел бы вынести всю рутину по работе с сетью в отдельный класс (чтобы отделить работу с ГУИ от работы с сетью). Тогда вариант с глоб. переменной отпадает? Или всё таки обращаться к этой переменной из другого класса? (имхо вариант не очень).





2. Вариант с QEventLoop (начинать его до начала запроса и связать конец запроса с завершением QEventLoop). Проблем заметно убавляется (избавляюсь от перехода в другой слот после завершения запроса). Но как я понимаю, такой вариант не очень правильный и красивый.


Еще заметил интересный метод isFinished у QNetworkReply...

Заранее благодарен за помощь.




Название: Re: QNetworkReply. Нужна помощь в организации слотов.
Отправлено: SABROG от Июль 09, 2010, 16:32
Но теперь тупик: я не знаю в какую строчку таблицы нужно вставить данные.
Создай класс DownloadManager, где объяви очередь запросов QQueue. В качестве типа элементов списка определи свою структуру куда помести всю необходимую информацию, например:

Код
C++ (Qt)
struct MyRequest
{
   QRequest request;
   QString expectedMimeType;
   QModelIndex index;
   QNetworkReply* reply;
};
 

Когда вызывается слот finished() пробегаемся по очереди запросов и сравниваем reply с reply(). С помощью request.url() можно узнать URL который запрашивался изначально до редиректов (редиректы нужно организовывать самому дополнительным вызовом QNetworkAccessManager::get()). Соответственно QNetworkReply::url() может отличаться от QNetworkRequest::url(), но вот указатель reply будет один и тот же. Некоторые сайты не возвращают ошибку 404 если страница или файл не найден, поэтому если ожидается, что возвращаемый тип данных должен быть "application/x-rar-compressed" (.rar файл), а приходит "text/html", то либо файла не существует, либо сервер требует аутентификации, либо идут плановые работы и т.д. и т.п. Если данные приходят, то обрабатываем их и устанавливаем свои данные в index, которые автоматически обновят представление из модели.


Название: Re: QNetworkReply. Нужна помощь в организации слотов.
Отправлено: BredoGen от Июль 09, 2010, 17:22
Огромное спасибо за помощь!

Не думал правда, что придется залезть так далеко, но буду разбираться - пойдёт на пользу  :)

P.S. Получать буду только чистый HTML, редиректов не планируется.


Название: Re: QNetworkReply. Нужна помощь в организации слотов.
Отправлено: BredoGen от Июль 09, 2010, 21:17

Создай класс DownloadManager, где объяви очередь запросов QQueue. В качестве типа элементов списка определи свою структуру куда помести всю необходимую информацию, например:

Код
C++ (Qt)
struct MyRequest
{
   QRequest request;
   QString expectedMimeType;
   QModelIndex index;
   QNetworkReply* reply;
};
 

Когда вызывается слот finished() пробегаемся по очереди запросов и сравниваем reply с reply().

Тут еще один вопрос возник... Для наглядности приведу мою таблицу:
(http://s44.radikal.ru/i106/1007/2f/ffb61e4e71c9.png)

Я должен в цикле взять string, зайти на первый сайт, спарсить оттуда значение и внести в колонку Value 1.
Далее зайти на второй сайт, спарсить и внести в Value 2  и т.д.
Далее посчитать сумму всех значений и занести в Summ.

Так как у меня несколько сайтов (для каждого свой Value столбик) - я должен использовать несколько очередей?

Я так понял, используя правильные методы Кьюта, невозможно получить такую запись (ну или с более менее меньшими проблемами):
Код:
for (int i=0; i < table->rowCount(); ++i) {
        QString firstValue = getFirstValue(table->item(i, 0)->text()); //getFirstValue() должна выполнить запрос и в случае удачи вернуть контент
       
        QTableWidgetItem *newItem = new QTableWidgetItem(firstValue); //Новое значение
        table->setItem(i, 1, newItem); //Присваиваем
}


Название: Re: QNetworkReply. Нужна помощь в организации слотов.
Отправлено: SABROG от Июль 10, 2010, 09:56
Так как у меня несколько сайтов (для каждого свой Value столбик) - я должен использовать несколько очередей?
Если порядок заполнения колонок не важен, то в очередь можно поместить все запросы сразу и вычисление итоговых результатов произвести, когда очередь станет пуста.