LINUX.ORG.RU

[Qt] Подскажите алгоритм


0

2

Пишу код на основе примера из самого Qt - даунлоадера (в примерах называется http). Он по-умолчанию качает файл по ссылке, которую берет из lineEdit.

Сам код:

void HttpWindow::startRequest(QUrl url)
{
    reply = qnam.get(QNetworkRequest(url));
    connect(reply, SIGNAL(finished()),
            this, SLOT(httpFinished()));
    connect(reply, SIGNAL(readyRead()),
            this, SLOT(httpReadyRead()));
    connect(reply, SIGNAL(downloadProgress(qint64,qint64)),
            this, SLOT(updateDataReadProgress(qint64,qint64)));
}

void HttpWindow::downloadFile()
{
    url = urlLineEdit->text();

    QFileInfo fileInfo(url.path());
    QString fileName = fileInfo.fileName();
    if (fileName.isEmpty())
        fileName = "index.html";

    if (QFile::exists(fileName)) {
        if (QMessageBox::question(this, tr("HTTP"), 
                                  tr("There already exists a file called %1 in "
                                     "the current directory. Overwrite?").arg(fileName),
                                  QMessageBox::Yes|QMessageBox::No, QMessageBox::No)
            == QMessageBox::No)
            return;
        QFile::remove(fileName);
    }

    file = new QFile(fileName);
    if (!file->open(QIODevice::WriteOnly)) {
        QMessageBox::information(this, tr("HTTP"),
                                 tr("Unable to save the file %1: %2.")
                                 .arg(fileName).arg(file->errorString()));
        delete file;
        file = 0;
        return;
    }


    progressDialog->setWindowTitle(tr("HTTP"));
    progressDialog->setLabelText(tr("Downloading %1.").arg(fileName));
    downloadButton->setEnabled(false);

    // schedule the request
    httpRequestAborted = false;
    startRequest(url);
} 

Как видно из кода - после создания файла он запускат функцию StartRequest, передавая ей в качестве параметра ссылку. В теле этой функции запускается сам реквест и приконнекчиваются слоты и сигналы. Дальше работа идет уже по генерации сигналов, генерируемыми самим реквестом reply.

А мне надо сделать по-другому. У меня есть листбокс и чекабельными элементами, за каждым элементом хранится ссылка на файл. При нажатии кнопки Download нужно скачать все файлы, которые выделены чекбоксами. Собственно вопрос - как это сделать правильно? Уже два дня в голову ничего почему-то не приходит.

В чем трабла - если в обработчике сигнала кликед кнопки сделать простой перебор всех элементов листбокса, и, если он отмечен чекбоксом, запускать нужный алгоритм (из кутешного примера), то получается, что он это делает мгновенно, не давая закончить закачку предыдущего файла. Все виснет. Как сделать так, чтобы он начинал качать следующий элемент (приостанавливал цикл) пока не скачается предыдущий файл?

★★★★★

Походу дела сегодня ты откроешь для себя конечные автоматы.

pathfinder ★★★★ ()

Инициировать закачку следующего в коде обработки завершения закачки предыдущего файла? Или все-таки написать простенькую обертку (включив внутрь все сигналы и слоты и высунув наружу только один метод download) и качать файлы параллельно?

amomymous ★★★ ()
Ответ на: комментарий от amomymous

>Инициировать закачку следующего в коде обработки завершения закачки предыдущего файла?

Хм.. Т.е. прервать цикл в первом, запомнить переменную, как закачается - токнуть цикл снова, начиная с ее состояния, закончившегося перед этим?

Или все-таки написать простенькую обертку (включив внутрь все сигналы и слоты и высунув наружу только один метод download) и качать файлы параллельно?


Тоже вариант...

Zhbert ★★★★★ ()
Ответ на: комментарий от amomymous

>качать файлы параллельно?

Тогда скорость упадет порядочно.

Zhbert ★★★★★ ()
Ответ на: комментарий от Zhbert

Хм.. Т.е. прервать цикл в первом, запомнить переменную, как закачается - токнуть цикл снова, начиная с ее состояния, закончившегося перед этим

Почему вместо того, чтобы сделать простой и интуитивно понятный конечный автомат, людей тянет сделать тот же самый конечный автомат, но в не очевидной форме. Такой код тяжело переделывать. Если понадобится сделать кнопку «Отмена» или что-то ещё, то можно запутаться в этих не очевидных состояниях.

pathfinder ★★★★ ()
Ответ на: комментарий от pathfinder

>Почему вместо того, чтобы сделать простой и интуитивно понятный конечный автомат, людей тянет сделать тот же самый конечный автомат, но в не очевидной форме. Такой код тяжело переделывать. Если понадобится сделать кнопку «Отмена» или что-то ещё, то можно запутаться в этих не очевидных состояниях.

Люблю я ректальные методы.

Zhbert ★★★★★ ()
Ответ на: комментарий от reader

http://doc.qt.nokia.com/4.7/network-downloadmanager.html

Ужос. Похоже, что в Qt со временем будут классы для любых задач. И на вопрос «Как реализовать такую-то фигню?» можно не задумываясь давать ответ «Использую класс QФигня.»

pathfinder ★★★★ ()
Ответ на: комментарий от Chaser_Andrey

Причем здесь это? По сцылке всего лишь пример, который следует верным правилам ООП.

Все верно. Мне надо было по ссылкам ходить. :(

pathfinder ★★★★ ()
Ответ на: комментарий от Zhbert

Я имел в виду что-то вроде создания очереди из имен файлов для загрузки. Когда файл загружен(т.е. в методе downloadFile()), то он удаляется из очереди, и если очередь пуста - это конец. Если не пуста, ставим на загрузку следующий файл (вызовом startRequest).

Параллельная загрузка тормозит? А как в вашем любимом браузере качаются файлы? Тем более, если размер файлов не очень большой (скажем, до 1 мб), то параллельная/последовательная загрузка одинаково хорошии..

amomymous ★★★ ()
Ответ на: комментарий от reader

неосилятор

Кто может объяснить, чем обусловлено такое поведение QTimer::singleShot.

По ссылке, файл downloadmanager.cpp

 void DownloadManager::append(const QStringList &urlList)
 {
     foreach (QString url, urlList)
         append(QUrl::fromEncoded(url.toLocal8Bit()));

     if (downloadQueue.isEmpty())
         QTimer::singleShot(0, this, SIGNAL(finished()));
 }

 void DownloadManager::append(const QUrl &url)
 {
     if (downloadQueue.isEmpty())
         QTimer::singleShot(0, this, SLOT(startNextDownload())); //ТУТ

     downloadQueue.enqueue(url);
     ++totalCount;
 }
По какой причине он не сразу вызывает указанный слот, а только после того, как заполнится очередь (после нескольких вызовов этой функции)?

anonymous ()
Ответ на: неосилятор от anonymous
$ ./downloadmanager http://localhost/
append list
append
startNextDownload
dequeue
Downloading http://localhost/...

$ ./downloadmanager http://localhost/ http://localhost/index.php
append list
append
append
startNextDownload
dequeue
Downloading http://localhost/...

Ты имеешь ввиду двойной append во втором случае, ожидая ситуацию как ниже?

append list
append
startNextDownload
dequeue
Downloading http://localhost/...
append

rival ★★ ()
Ответ на: комментарий от anonymous

http://doc.qt.nokia.com/latest/qtimer.html#details

As a special case, a QTimer with a timeout of 0 will time out as soon as all the events in the window system's event queue have been processed.

Очевидно, что управление не возвращается в event queue, пока выполняются функции append. Но это можно исправить с помощью:
http://doc.trolltech.com/latest/qcoreapplication.html#processEvents

rival ★★ ()
Ответ на: комментарий от rival

Большое спасибо за пояснение. Буду знать.

anonymous ()

Мой тебе совет - используй очередь. Нашел что-то для скачивания - добавь в очередь. При добавлении посмотри, уже качается что-то или нет. Если нет - начни качать. Как только скачал, посмотри, пуста очередь или нет.

Как-то так.

P.S. тред не читал

trex6 ★★★★★ ()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.