diff --git a/libimageviewer/service/commonservice.h b/libimageviewer/service/commonservice.h index 609fe897..16753c9f 100644 --- a/libimageviewer/service/commonservice.h +++ b/libimageviewer/service/commonservice.h @@ -5,12 +5,14 @@ #ifndef COMMONSERVICE_H #define COMMONSERVICE_H +#include "image-viewer_global.h" + #include #include #include #include #include -#include "image-viewer_global.h" +#include class LibCommonService : public QObject { @@ -35,7 +37,7 @@ class LibCommonService : public QObject public: QStringList m_listAllPath;//全部需要加载的 QStringList m_noLoadingPath;//没有加载的地址 - QStringList m_listLoaded;//已经加载的 + QSet m_listLoaded;//已经加载的 signals: void sigRightMousePress(); diff --git a/libimageviewer/service/imagedataservice.cpp b/libimageviewer/service/imagedataservice.cpp index 88417de3..ad8b6331 100644 --- a/libimageviewer/service/imagedataservice.cpp +++ b/libimageviewer/service/imagedataservice.cpp @@ -42,12 +42,14 @@ LibImageDataService::~LibImageDataService() bool LibImageDataService::add(const QStringList &paths) { QMutexLocker locker(&m_imgDataMutex); -// m_requestQueue.clear(); - for (int i = 0; i < paths.size(); i++) { - if (!m_AllImageMap.contains(paths.at(i))) { - m_requestQueue.append(paths.at(i)); + // FIXME: 虽然这样修改将后续的数据优先添加,但也会导致边缘变更单独更新的数据被优先读取,变成非中心加载而是偏向一侧加载。 + // 反向添加,尾部数据在之后添加,QList两侧都有预留分配,非共享差异不大 + std::for_each(paths.rbegin(), paths.rend(), [this](const QString &path){ + if (!m_AllImageMap.contains(path)) { + m_requestQueue.prepend(path); } - } + }); + return true; } @@ -56,7 +58,8 @@ bool LibImageDataService::add(const QString &path) QMutexLocker locker(&m_imgDataMutex); if (!path.isEmpty()) { if (!m_AllImageMap.contains(path)) { - m_requestQueue.append(path); + // 后添加的单一数据优先加载 + m_requestQueue.prepend(path); } } return true; @@ -83,26 +86,38 @@ int LibImageDataService::getCount() return m_AllImageMap.count(); } -bool LibImageDataService::readThumbnailByPaths(QString thumbnailPath, QStringList files, bool remake) +bool LibImageDataService::readThumbnailByPaths(const QString &thumbnailPath, const QStringList &files, bool remake) { - qDebug() << "------------files.size = " << files.size(); + Q_UNUSED(thumbnailPath) + Q_UNUSED(remake) LibImageDataService::instance()->add(files); - int needCoreCounts = static_cast(std::thread::hardware_concurrency()); - needCoreCounts = needCoreCounts / 2; - if (files.size() < needCoreCounts) { - needCoreCounts = files.size(); + int threadCounts = static_cast(readThreadGroup.size()); + // 调整占用线程数量 + int recommendThreadCounts = QThread::idealThreadCount() / 2; + int needCoreCounts = qBound(1, files.size(), recommendThreadCounts); + int curActivateThreads = 0; + + // 激活已有的线程 + for (int i = 0; i < threadCounts && i < needCoreCounts; ++i) { + auto thread = readThreadGroup.at(static_cast(i)); + if (!thread->isRunning()) { + thread->start(); + curActivateThreads++; + } } - if (needCoreCounts < 1) - needCoreCounts = 1; - for (int i = 0; i < needCoreCounts; i++) { + + // 当前激活的线程不满足文件加载,且当前线程仍有余量,创建更多线程处理 + int avaliableThreads = recommendThreadCounts - threadCounts; + int requesetThreads = needCoreCounts - curActivateThreads; + int addThreads = qMin(avaliableThreads, requesetThreads); + for (int i = 0; i < addThreads; ++i) { LibReadThumbnailThread *thread = new LibReadThumbnailThread; - thread->m_thumbnailPath = thumbnailPath; - thread->m_remake = remake; thread->start(); readThreadGroup.push_back(thread); } + return true; } diff --git a/libimageviewer/service/imagedataservice.h b/libimageviewer/service/imagedataservice.h index a0751d64..bfa1143a 100644 --- a/libimageviewer/service/imagedataservice.h +++ b/libimageviewer/service/imagedataservice.h @@ -31,8 +31,7 @@ class LibImageDataService: public QObject int getCount(); //读取缩略图到缓存map - bool readThumbnailByPaths(QString thumbnailPath, QStringList files, bool remake); -// bool readThumbnailByPath(QString file); + bool readThumbnailByPaths(const QString &thumbnailPath, const QStringList &files, bool remake); void addImage(const QString &path, const QImage &image); QImage getThumnailImageByPath(const QString &path); @@ -76,22 +75,23 @@ private slots: class LibReadThumbnailThread : public QThread { Q_OBJECT + public: - LibReadThumbnailThread(QObject *parent = nullptr); + explicit LibReadThumbnailThread(QObject *parent = nullptr); ~LibReadThumbnailThread() override = default; void readThumbnail(QString m_path); void setQuit(bool quit); - QString m_thumbnailPath = ""; - bool m_remake = false; //判断图片类型 imageViewerSpace::ImageType getImageType(const QString &imagepath); //判断路径类型 imageViewerSpace::PathType getPathType(const QString &imagepath); + protected: void run() override; + private: std::atomic_bool m_quit; - }; + #endif // IMAGEDATASERVICE_H diff --git a/libimageviewer/viewpanel/contents/bottomtoolbar.cpp b/libimageviewer/viewpanel/contents/bottomtoolbar.cpp index f67cfdae..a4f10350 100644 --- a/libimageviewer/viewpanel/contents/bottomtoolbar.cpp +++ b/libimageviewer/viewpanel/contents/bottomtoolbar.cpp @@ -587,6 +587,9 @@ void LibBottomToolbar::resizeEvent(QResizeEvent *event) emit sigResizeBottom(); m_imgListWidget->moveCenterWidget(); + + // 计算当前展示的Item数量是否变更 + estimatedDisplayCount(); } void LibBottomToolbar::showEvent(QShowEvent *event) @@ -878,3 +881,24 @@ void LibBottomToolbar::setButtonVisible(imageViewerSpace::ButtonType id, bool vi } } } + +/** + @return 返回当前缩略图栏显示的item计数,计数 = (显示控件宽度 / 显示的 Item 宽度) + 1, + 计数将至少为 1 + */ +int LibBottomToolbar::estimatedDisplayCount() +{ + int itemWidth = LibImgViewListView::ITEM_NORMAL_WIDTH + LibImgViewListView::ITEM_SPACING; + int estimate = ((m_imgListWidget->width() - LibImgViewListView::ITEM_CURRENT_WH) / itemWidth) + 1; + int curCount = qMax(1, estimate); + + bool growup = curCount > m_estimateDisplayCount; + if (curCount != m_estimateDisplayCount) { + m_estimateDisplayCount = curCount; + } + if (growup) { + Q_EMIT displayItemGrowUp(m_estimateDisplayCount); + } + + return curCount; +} diff --git a/libimageviewer/viewpanel/contents/bottomtoolbar.h b/libimageviewer/viewpanel/contents/bottomtoolbar.h index f7d4ec94..753e90e0 100644 --- a/libimageviewer/viewpanel/contents/bottomtoolbar.h +++ b/libimageviewer/viewpanel/contents/bottomtoolbar.h @@ -88,6 +88,9 @@ class LibBottomToolbar : public DFloatingWidget //限于目前的代码结构,这个设置仅能在设置隐藏的时候立即生效 void setButtonVisible(imageViewerSpace::ButtonType id, bool visible); + // 当前在缩略图展示的item统计(模糊计算结果) + int estimatedDisplayCount(); + signals: void resetTransform(bool fitWindow); void rotateClockwise(); @@ -114,6 +117,8 @@ class LibBottomToolbar : public DFloatingWidget void sigResizeBottom(); + // 当前展示的item增加 + void displayItemGrowUp(int estimatedCount); public slots: void updateCollectButton(); @@ -178,6 +183,8 @@ public slots: bool badaptScreenBtnChecked = false; QString m_currentpath = ""; bool m_ocrIsExists = false; + + int m_estimateDisplayCount = 0; }; #endif // BOTTOMTOOBAR_H diff --git a/libimageviewer/viewpanel/contents/imgviewwidget.h b/libimageviewer/viewpanel/contents/imgviewwidget.h index ddcf02f2..356634b5 100644 --- a/libimageviewer/viewpanel/contents/imgviewwidget.h +++ b/libimageviewer/viewpanel/contents/imgviewwidget.h @@ -63,6 +63,7 @@ class MyImageListWidget : public QWidget //获得当前 int getCurrentCount(); + signals: void openImg(int index, QString path); private: diff --git a/libimageviewer/viewpanel/viewpanel.cpp b/libimageviewer/viewpanel/viewpanel.cpp index e609129f..1572c8d0 100644 --- a/libimageviewer/viewpanel/viewpanel.cpp +++ b/libimageviewer/viewpanel/viewpanel.cpp @@ -316,6 +316,11 @@ void LibViewPanel::initConnect() m_topToolbar->update(); }); #endif + + // 展示的item增加时(拖拽、放大等),需要同步更新缩略图 + connect(m_bottomToolbar, &LibBottomToolbar::displayItemGrowUp, this, [this](int){ + loadThumbnails(m_currentPath); + }); } void LibViewPanel::initTopBar() @@ -1130,33 +1135,45 @@ void LibViewPanel::hideAnimationTopBottom() void LibViewPanel::loadThumbnails(const QString &path) { -// LibCommonService::instance()->m_listAllPath = pathList; -// LibCommonService::instance()->m_noLoadingPath = pathList; - int index = LibCommonService::instance()->m_listAllPath.indexOf(path); - int left = index; - int right = index; - if (index + 50 > LibCommonService::instance()->m_listAllPath.count()) { - right = LibCommonService::instance()->m_listAllPath.count(); - } else { - right = index + 50; - } - if (index - 50 > 0) { - left = index - 50; - } else { - left = 0; + if (-1 == index) { + return; } + + // 默认的缩略图加载数量 + static const int s_DefaultLoadThumbnails = 4; + // 通过当前显示的缩略图栏宽度计算待预加载的缩略图计数,适当调整宽度以预载部分未显示图片 + int imageCount = LibCommonService::instance()->m_listAllPath.count(); + int needLoadImages = qMax(m_bottomToolbar->estimatedDisplayCount() + 2, s_DefaultLoadThumbnails); + needLoadImages = qMin(needLoadImages, imageCount); + QStringList loadList; - for (int i = left; i < right; i++) { - QString loadPath = LibCommonService::instance()->m_listAllPath[i]; - if (LibCommonService::instance()->m_listLoaded.indexOf(loadPath) < 0) { - loadList << loadPath; - LibCommonService::instance()->m_listLoaded << loadPath; - LibCommonService::instance()->m_noLoadingPath.removeOne(loadPath); + auto appendFunc = [&](const QString &addPath){ + if (!LibCommonService::instance()->m_listLoaded.contains(addPath)) { + loadList.append(addPath); + LibCommonService::instance()->m_listLoaded.insert(addPath); + LibCommonService::instance()->m_noLoadingPath.removeOne(addPath); } + }; - + // 从中间向两侧扩散追加,若一侧已全加载,则另一侧继续添加 + int loadImageCount = 0; + int l = index; + int r = index + 1; + while (loadImageCount < needLoadImages) { + if (0 <= l) { + appendFunc(LibCommonService::instance()->m_listAllPath[l]); + loadImageCount++; + --l; + } + if (r < imageCount) { + appendFunc(LibCommonService::instance()->m_listAllPath[r]); + loadImageCount++; + ++r; + } } + + // 异步加载数据 ImageEngine::instance()->makeImgThumbnail(LibCommonService::instance()->getImgSavePath(), loadList, loadList.size()); }