接続できるように、 qGetDownloadManager
を拡張してaの進行状況を出力し始めましTransferItem
た。TableView
で表示するモデルのセルに進行状況データを挿入していDelegate
ます。最後にデリゲートが進行状況バーを描画します。それは理論的には機能しますが、私は次のことに遭遇しています
問題:複数のダウンロードが並行して行われている場合、両方のシグナルから両方のセルへの進行状況の更新を取得します。
QModelIndex index
どちらの進行状況バーにも進行状況データが表示されますが、シグナルは混合されており、現在のインデックス ( / )に固有のものではありませんindex.row()
。
(UserRoles 間の小さな遷移の問題は無視してください (ダウンロード ボタンをクリックした後、"ActionCell" が表示され、"ProgressBar" が表示される前に "Install" が表示されます)。それはここでの主な問題ではありません。私の質問はインデックスに関するものです。問題です。) テキスト "112" と "113" は intindex.row
です。
質問:
- 複数の ProgressBars の進行状況データで 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); }
Delegate、doDownload(index)、および ProgressBarUpdater を含む TableView
QTableView
- を追加
QSortFilterProxyModel
(大文字と小文字を区別しないため) カスタムUserRoles
ColumnDelegate
に基づいて DownloadButton と ProgressBar をレンダリングします。デリゲートはボタンのクリックを処理しますdownloadButtonClicked(index)
。SIGNAL は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さん、ありがとうございました!! 私はあなたの提案に従い、それを修正しました: