Я начал расширять qGet DownloadManager
, чтобы исправить прогресс TransferItem
, так что я могу подключиться к нему. Я вставляю данные прогресса в ячейку модели TableView
для отображения с Delegate
, и, наконец, делегат рисует индикатор выполнения. Это работает в теории, но я бегу в следующемКак обновить TableView с данными прогресса для нескольких ProgressBars?
Проблема: при наличии нескольких загрузок параллельно, то я получить прогресс обновления от обоих сигналов в как клетки!
Оба прогресса столбики показывают данные о ходе работы, но сигнал вид смешивают и не является уникальным для текущего индекса (QModelIndex index
/index.row()
).
(Пожалуйста, игнорируйте небольшую проблему перехода между UserRoles (после нажатия кнопки загрузки «ActionCell» отображается, а затем «Install», до появления «ProgressBar».) Это не основная проблема. относится к проблеме индекса.) Текст «112» и «113» - это int index.row
.
Вопросы:
- Как обновить TableView с данными о ходе работы для нескольких индикаторов выполнения?
- Что я должен изменить, чтобы отобразить индикатор выполнения для каждой загрузки?
Источник
Испустите прогресс загрузки
я добавил следующие вещи переизлучались сигнал через классы, пока это не пузырится к наверх, где он становится подключаемым из GUI.
соединение с
QNetworkReply
-downloadProgress(qint64,qint64)
кTransferItem
-updateDownloadProgress(qint64,qint64)
void TransferItem::startRequest() { reply = nam.get(request); connect(reply, SIGNAL(readyRead()), this, SLOT(readyRead())); connect(reply, SIGNAL(downloadProgress(qint64,qint64)), this, SLOT(updateDownloadProgress(qint64,qint64))); connect(reply, SIGNAL(finished()), this, SLOT(finished())); timer.start(); }
функция SLOT
TransferItem
-updateDownloadProgress(qint64,qint64)
как приемник вычисляет прогресс и сохраняет его вprogress
(QMap<QString, QVariant>
). После расчета выдается сигналdownloadProgress(this)
.// SLOT void TransferItem::updateDownloadProgress(qint64 bytesReceived, qint64 bytesTotal) { progress["bytesReceived"] = QString::number(bytesReceived); progress["bytesTotal"] = QString::number(bytesTotal); progress["size"] = getSizeHumanReadable(outputFile->size()); progress["speed"] = QString::number((double)outputFile->size()/timer.elapsed(),'f',0).append(" KB/s"); progress["time"] = QString::number((double)timer.elapsed()/1000,'f',2).append("s"); progress["percentage"] = (bytesTotal > 0) ? QString::number(bytesReceived*100/bytesTotal).append("%") : "0 %"; emit downloadProgress(this); } QString TransferItem::getSizeHumanReadable(qint64 bytes) { float num = bytes; QStringList list; list << "KB" << "MB" << "GB" << "TB"; QStringListIterator i(list); QString unit("bytes"); while(num >= 1024.0 && i.hasNext()) { unit = i.next(); num /= 1024.0; } return QString::fromLatin1("%1 %2").arg(num, 3, 'f', 1).arg(unit); }
Когда новая загрузка будет помещён, я подключить излучаемого
downloadProgress(this)
к SlotDownloadManager
-downloadProgress(TransferItem*)
. (dl
-DownloadItem
, который распространяется наTransferItem
).void DownloadManager::get(const QNetworkRequest &request) { DownloadItem *dl = new DownloadItem(request, nam); transfers.append(dl); FilesToDownloadCounter = transfers.count(); connect(dl, SIGNAL(downloadProgress(TransferItem*)), SLOT(downloadProgress(TransferItem*))); connect(dl, SIGNAL(downloadFinished(TransferItem*)), SLOT(downloadFinished(TransferItem*))); }
Наконец, я вновь испускать прогресс загрузки еще раз:
void DownloadManager::downloadProgress(TransferItem *item) { emit signalProgress(item->progress); }
Теперь TableView с делегатом, doDownload (индекс) и ProgressBarUpdater
QTableView
- с добавлением
QSortFilterProxyModel
(для случая-нечувствительности) с добавлением
ColumnDelegate
, что делает DownloadButton и ProgressBar на основе пользовательских UserRoles. Делегат обрабатывает нажатие кнопки: СИГНАЛdownloadButtonClicked(index)
испускается из методаeditorEvent(event, model, option, index)
.actionDelegate = new Updater::ActionColumnItemDelegate; ui->tableView->setItemDelegateForColumn(Columns::Action, actionDelegate); connect(actionDelegate, SIGNAL(downloadButtonClicked(QModelIndex)), this, SLOT(doDownload(QModelIndex)));
doDownload
Метод получаетindex
и извлекает URL загрузки из модели. Затем URL-адрес добавляется в DownloadManager , и я создаю объект ProgressBarUpdater для установки данных прогресса в модель по данному индексу. Наконец, я подключаюdownloadManager::signalProgress
кprogressBar::updateProgress
и вызываюdownloadManager::checkForAllDone
, чтобы начать обработку загрузки.void UpdaterDialog::doDownload(const QModelIndex &index) { QUrl downloadURL = getDownloadUrl(index); if (!validateURL(downloadURL)) return; QNetworkRequest request(downloadURL); downloadManager.get(request); // QueueMode is Parallel by default ProgressBarUpdater *progressBar = new ProgressBarUpdater(this, index.row()); progressBar->setObjectName("ProgressBar_in_Row_" + QString::number(index.row())); connect(&downloadManager, SIGNAL(signalProgress(QMap<QString, QVariant>)), progressBar, SLOT(updateProgress(QMap<QString, QVariant>))); QMetaObject::invokeMethod(&downloadManager, "checkForAllDone", Qt::QueuedConnection); }
Обновление модели часть: ProgressBarUpdater принимает индекс и прогресс, и должен обновлять модель по данному индексу.
ProgressBarUpdater::ProgressBarUpdater(UpdaterDialog *parent, int currentIndexRow) : QObject(parent), currentIndexRow(currentIndexRow) { model = parent->ui->tableView_1->model(); } void ProgressBarUpdater::updateProgress(QMap<QString, QVariant> progress) { QModelIndex actionIndex = model->index(currentIndexRow, UpdaterDialog::Columns::Action); // set progress to model model->setData(actionIndex, progress, ActionColumnItemDelegate::DownloadProgressBarRole); model->dataChanged(actionIndex, actionIndex); }
Рендеринг часть: Я рендеринг поддельного ProgressBar от делегата; получение данных о ходе работы с помощью
index.model()->data(index, DownloadProgressBarRole)
.void ActionColumnItemDelegate::drawDownloadProgressBar(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const { QStyleOptionProgressBarV2 opt; opt.initFrom(bar); opt.rect = option.rect; opt.rect.adjust(3,3,-3,-3); opt.textVisible = true; opt.textAlignment = Qt::AlignCenter; opt.state = QStyle::State_Enabled | QStyle::State_Active; // get progress from model QMap<QString, QVariant> progress = index.model()->data(index, DownloadProgressBarRole).toMap(); QString text = QString::fromLatin1(" %1 %2 %3 %4 %5 ") .arg(QString::number(index.row())) .arg(progress["percentage"].toString()) .arg(progress["size"].toString()) .arg(progress["speed"].toString()) .arg(progress["time"].toString()); opt.minimum = 0; opt.maximum = progress["bytesTotal"].toFloat(); opt.progress = progress["bytesReceived"].toFloat(); opt.text = text; bar->style()->drawControl(QStyle::CE_ProgressBar,&opt,painter,bar); }
Я добавил QString::number(index.row()
текста на прогресс бар, так что каждый ProgressBar получает свой номер строки оказаны. Другими словами: рендеринг является уникальным для строки, но входящие данные прогресса каким-то образом смешаны.
Я застрял на проблеме индекса некоторое время. Спасибо заранее за вашу помощь.
Обновление: проблема решена!
Большое спасибо ddriver !! Я последовал за ваши предложения и установил его:
Ваша реализация излишне сложна, неудивительно, что вещи перепутались. Вы пытались на самом деле отлаживать или по крайней мере ставить несколько 'qDebug()' s, чтобы определить, что и где идет не так? – dtech
Я умышленно удалил строки отладки. «Ваша реализация излишне сложна». Не могли бы вы объяснить, как это упростить? –
Я в основном согласен с ddriver. Невозможно понять, что происходит не так, если посмотреть на этот большой незавершенный фрагмент кода. Вы должны предоставить минимальный полный пример или просто упростить его. Удалите делегат, задайте текст элемента непосредственно из объекта обновления, добавьте некоторую отладку, чтобы проверить, обновлены ли правильные элементы и т. Д. ... – hank