Qt實現圖片拖拽上傳過濾資料夾內圖片自動搜尋列表展示

一字千金發表於2024-07-24

1.功能實現

支援圖片、或者資料夾拖拽上傳,會自動獲取資料夾中的圖片。對拖入的檔案做格式判斷,不符合格式要求的會不支援拖入,拖入後展示在list列表中,可以進行刪除,和上下滾動檢視;

#ifndef DRAGDROPPIC_H
#define DRAGDROPPIC_H

#include <QWidget>
#include "ui_DragDropPic.h"
#include<QDragEnterEvent>
#include <QDropEvent>
#include <QMimeData>
#include<QLabel>
#include "DirPicItem.h"
#include "SearchPicThread.h"
#include "HelpButton.h"
#include "AddPicHelp.h"
class DragDropPic : public QWidget
{
    Q_OBJECT

public:
    DragDropPic(QWidget *parent = 0);
    ~DragDropPic();
    void dragEnterEvent(QDragEnterEvent *event);
    void dropEvent(QDropEvent *event);
    
    void dragLeaveEvent(QDragLeaveEvent *event);
    void AddSelectedFile(QStringList listPath);
    void wheelEvent(QWheelEvent *e);
    void ClearContont();
    void CheckIsSystemPath(QStringList& listDir);
    void resizeEvent(QResizeEvent *event);
    bool IsReady() { return m_pSearchPicThread->isRunning() ? false : true; };
    QStringList GetNoRepeatPicPath();
    int GetNoRepeatPicNum();
    void CheckLeftPicNum(bool bAlarm=false);
    public slots:
    void UpdateFileList();
    void SlotSelectPicFile();
    void SlotSearchPicFinished(QVariantMap picData);
    void SetLeftPicNum(int left) { m_leftPicNum = left; };
    void SlotShowHelpWidget(bool show);
signals:
    void SignalError(int type, QString strContent);
    void SignalUpdateLeftPicNum(int num);
private:
    Ui::DragDropPic ui;
    QStringList m_strListFilePath;
    QMap<QString, QVariant>m_mapFilePathPic;
    SearchPicThread* m_pSearchPicThread;
    int m_leftPicNum = 0;//剩餘
    HelpButton* m_pHelpButton;
    AddPicHelp m_AddPicHelp;
};

#endif // DRAGDROPPIC_H

cpp檔案

#include "DragDropPic.h"
#include <QFileInfo>
#include <QScrollBar>
#include "MultiFileDirDialog.h"
#include "ConfigInfo.h"
#pragma execution_character_set("utf-8")
DragDropPic::DragDropPic(QWidget *parent)
    : QWidget(parent)
{
    ui.setupUi(this);
    ui.widgetRelease->hide();
    ui.widgetPic->hide();
    ui.listWidgetPic->verticalScrollBar()->setDisabled(true);
    connect(ui.vScrollBar, &QScrollBar::valueChanged, this, &DragDropPic::UpdateFileList);
    connect(ui.pBLibAddPic, &QPushButton::clicked, this, &DragDropPic::SlotSelectPicFile);
    m_pSearchPicThread = new SearchPicThread(this);
    connect(m_pSearchPicThread, &SearchPicThread::signalSearchPicResult, this, &DragDropPic::SlotSearchPicFinished);
    m_pHelpButton = new HelpButton(ui.widgetHelp);
    ui.horizontalLayoutHelp->addWidget(m_pHelpButton);
    connect(m_pHelpButton, &HelpButton::signalInHelpButton, this, &DragDropPic::SlotShowHelpWidget);
}

DragDropPic::~DragDropPic()
{

}
/*對拖入的圖片做格式判斷*/
void DragDropPic::dragEnterEvent(QDragEnterEvent *event)
{
    QStringList allowedExtensions;
    allowedExtensions << "jpg" << "jpeg" << "png" << "tiff"<<"JPG"<<"JPEG"<<"PNG"<<"TIFF";
    const QMimeData *mimeData = event->mimeData();
    int CountUnsurport = 0;
    QStringList listPath;
    if (mimeData->hasUrls())
    {
        QList<QUrl> urls = mimeData->urls();
        for (int i = 0; i < urls.size(); i++)
        {
            QString filePath = urls.at(i).toLocalFile(); // 通常只處理第一個url
            QFileInfo fileinfo(filePath);
            if (fileinfo.isDir())
            {
                listPath.push_back(filePath);
            }
            else
            {
                QString extension = fileinfo.suffix();
                if (allowedExtensions.contains(extension))
                {
                    listPath.push_back(filePath);
                }
                else
                {

                    CountUnsurport++;
                }
            }
        }
    }
    if (CountUnsurport>0)
    {
        event->ignore(); // 接受拖動
    }
    else
    {
        event->acceptProposedAction(); // 接受拖動
        ui.widget->hide();
        ui.widgetRelease->show();
        ui.widgetAddPic->setStyleSheet(QLatin1String("\n"
            "QWidget#widgetAddPic\n"
            "{\n"
            "    border: 1px dashed rgba(255, 255, 255, 0.3);\n"
            "    border-radius: 4px;\n"
            "    background:rgba(32, 128, 247, 0.16);\n"
            "}"));
    }
}

void DragDropPic::dropEvent(QDropEvent *event)
{
    // 允許的副檔名列表
    ui.widget->show();
    ui.widgetPic->show();
    ui.widgetRelease->hide();
    ui.widgetAddPic->setStyleSheet(QLatin1String("\n"
        "QWidget#widgetAddPic\n"
        "{\n"
        "    border: 1px dashed rgba(255, 255, 255, 0.3);\n"
        "    border-radius: 4px;\n"
        "    background: rgb(40, 40, 41);\n"
        "}"));
    QStringList allowedExtensions;
    allowedExtensions << "jpg" << "jpeg" << "png" << "tiff" << "JPG" << "JPEG" << "PNG" << "TIFF";
    const QMimeData *mimeData = event->mimeData();
    int CountUnsurport = 0;
    QStringList listPath;
    if (mimeData->hasUrls()) 
    {
        QList<QUrl> urls = mimeData->urls();
        for (int i = 0; i < urls.size(); i++)
        {
            QString filePath = urls.at(i).toLocalFile(); // 通常只處理第一個url
            QFileInfo fileinfo(filePath);
            if (fileinfo.isDir())
            {
                listPath.push_back(filePath);
            }
            else
            {
                QString extension = fileinfo.suffix();
                if (allowedExtensions.contains(extension))
                {
                    listPath.push_back(filePath);
                }
                else
                {
                    
                    CountUnsurport++;
                }
            }
        }
    }
    if (CountUnsurport>0)
    {
        emit SignalError(-3, QString("有%1個檔案不符合格式要求").arg(CountUnsurport));
        return;
    }
    AddSelectedFile(listPath);
}

void DragDropPic::dragLeaveEvent(QDragLeaveEvent *event)
{
    ui.widget->show();
    ui.widgetRelease->hide();
    ui.widgetAddPic->setStyleSheet(QLatin1String("\n"
        "QWidget#widgetAddPic\n"
        "{\n"
        "    border: 1px dashed rgba(255, 255, 255, 0.3);\n"
        "    border-radius: 4px;\n"
        "    background: rgb(40, 40, 41);\n"
        "}"));
}

void DragDropPic::AddSelectedFile(QStringList listPath)
{
    QStringList listDir;
    for (int i=0;i<listPath.size();i++)
    {
        //去除重複
        if (m_mapFilePathPic.find(listPath[i])== m_mapFilePathPic.end())
        {
            m_strListFilePath.push_back(listPath[i]);
            QFileInfo info(listPath[i]);
            if (info.isDir())
            {
                listDir.append(listPath[i]);
                QStringList listpic;
                m_mapFilePathPic.insert(listPath[i] , listpic);
            }
            else
            {
                m_mapFilePathPic.insert(listPath[i], "");
            }    
        }
    }
    if (listDir.size()>0)
    {
        m_pSearchPicThread->StartSearchPic(listDir);//用執行緒搜尋資料夾中的圖片
    }
    UpdateFileList();
    CheckLeftPicNum(true);
}
//滾輪滾動時,列表也跟著滾動
void DragDropPic::wheelEvent(QWheelEvent *e)
{
    int max = ui.vScrollBar->maximum();
    int current = ui.vScrollBar->value();
    if (ui.listWidgetPic->underMouse())
    {
        if (e->delta()<0)
        {
            current++;
            if (current>max)
            {
                current = max;
            }
        }
        else
        {
            current--;
            if (current<0)
            {
                current = 0;
            }
        }
        ui.vScrollBar->setValue(current);
    }
}

void DragDropPic::ClearContont()
{
    ui.listWidgetPic->clear();
    m_mapFilePathPic.clear();
    m_strListFilePath.clear();
    ui.vScrollBar->setValue(0);
    ui.widgetPic->hide();
}

void DragDropPic::UpdateFileList()
{
    
    int total = m_strListFilePath.size();
    if (total > 0)
    {
        ui.widgetPic->show();
    }
    else
    {
        ui.widgetPic->hide();
    }
    int pagesize = ui.listWidgetPic->height() / 28;
    if (total>pagesize)
    {
        ui.vScrollBar->setMaximum(total-pagesize);
        ui.vScrollBar->show();
    }
    else
    {
        ui.vScrollBar->setMaximum(0);
        ui.vScrollBar->hide();
    }
    int current = ui.vScrollBar->value();
    int listsize = ui.listWidgetPic->count();
    DirPicItem* pDirPicItem = NULL;
    QListWidgetItem* pItem=NULL;
    if (total <= pagesize)//總數不足一頁
    {
        if (listsize>=total)//列表中已有大於總數
        {
            //回收多餘的item
            for (int s = total; s < listsize; s++)
            {
                pItem = (QListWidgetItem*)ui.listWidgetPic->takeItem(0);//會刪除掉set上去的item
                if (pItem)
                {
                    pDirPicItem = (DirPicItem*)ui.listWidgetPic->itemWidget(pItem);
                    if (pDirPicItem)
                    {
                        delete pDirPicItem;
                        pDirPicItem = NULL;
                    }
                    delete pItem;
                    pItem = NULL;
                }
            }
        }
        else//已有少於總數插入不足
        {
            for (int s = listsize; s < total; s++)
            {
                pItem = new QListWidgetItem(ui.listWidgetPic);
                pDirPicItem = new DirPicItem(ui.listWidgetPic);
                connect(pDirPicItem->ui.pBClose, &QPushButton::clicked, this, [=] {
                    QString strFilePath = pDirPicItem->GetDirFile();
                    m_mapFilePathPic.remove(strFilePath);
                    for (int i = 0; i < m_strListFilePath.size(); i++)
                    {
                        if (m_strListFilePath[i] == strFilePath)
                        {
                            m_strListFilePath.removeAt(i);
                            break;
                        }
                    }
                    UpdateFileList();
                    CheckLeftPicNum();
                });
                ui.listWidgetPic->addItem(pItem);
                ui.listWidgetPic->setItemWidget(pItem,pDirPicItem);
            }    
        }
    }
    else//總數大於一頁
    {
        if (listsize< pagesize)
        {
            for (int s = listsize; s < pagesize; s++)
            {
                pItem = new QListWidgetItem(ui.listWidgetPic);
                pDirPicItem = new DirPicItem(ui.listWidgetPic);
                connect(pDirPicItem->ui.pBClose, &QPushButton::clicked, this, [=] {
                    QString strFilePath = pDirPicItem->GetDirFile();
                    m_mapFilePathPic.remove(strFilePath);
                    for (int i=0;i<m_strListFilePath.size();i++)
                    {
                        if (m_strListFilePath[i]==strFilePath)
                        {
                            m_strListFilePath.removeAt(i);
                            break;
                        }
                    }
                    UpdateFileList();
                    CheckLeftPicNum();
                });
                ui.listWidgetPic->addItem(pItem);
                ui.listWidgetPic->setItemWidget(pItem, pDirPicItem);
            }
        }
    }
    listsize = ui.listWidgetPic->count();
    for (int i= current,count=0;i<total&& count<listsize;i++, count++)
    {
        pItem = (QListWidgetItem*)(ui.listWidgetPic->item(count));
        if (pItem)
        {
            pDirPicItem = (DirPicItem*)ui.listWidgetPic->itemWidget(pItem);//會刪除掉set上去的item
            if (pDirPicItem)
            {
                pDirPicItem->SetDirFile(m_strListFilePath[i]);
                QFileInfo info(m_strListFilePath[i]);
                if (info.isDir())
                {
                    if (m_mapFilePathPic.find(m_strListFilePath[i])!=m_mapFilePathPic.end())
                    {
                        QStringList listpic = m_mapFilePathPic[m_strListFilePath[i]].toStringList();
                        if (listpic.size()>0)
                        {
                            pDirPicItem->SetDirPicNum(listpic.size());
                        }
                    }
                }
            }
        }
        
    }
}

void DragDropPic::SlotSelectPicFile()
{
    MultiFileDirDialog fileDialog(NULL);
    fileDialog.setWindowTitle("選擇資料夾或圖片");
    fileDialog.setOption(QFileDialog::ShowDirsOnly, false);
    fileDialog.setNameFilter("vedio(*.jpg *.jpeg *.png *.tiff *.JPG *.JPEG *.PNG *.TIFF)");

    if (fileDialog.exec() == QDialog::Accepted)
    {
        QStringList selectFiles = fileDialog.selectedFiles();
        if (selectFiles.size() > 0)
        {
            CheckIsSystemPath(selectFiles);
            //CheckIsNameTooLong(selectFiles);
            if (selectFiles.size() > 0)
            {
                AddSelectedFile(selectFiles);
            }
        }
    }
}

void DragDropPic::SlotSearchPicFinished(QVariantMap picData)
{
    for (auto it = picData.begin(); it!= picData.end(); it++)
    {
        if (m_mapFilePathPic.find(it.key())!=m_mapFilePathPic.end())
        {
            m_mapFilePathPic.insert(it.key(), it.value());
        }
    }
    UpdateFileList();
    CheckLeftPicNum(true);
}

void DragDropPic::SlotShowHelpWidget(bool show)
{
    if (show)
    {
        m_AddPicHelp.show();
        QPoint ppint =QCursor::pos();
        m_AddPicHelp.move(ppint.x() - 30, ppint.y() + 20);
    }
    else
    {
        m_AddPicHelp.hide();
    }
}

void DragDropPic::resizeEvent(QResizeEvent *event)
{
    UpdateFileList();
}

QStringList DragDropPic::GetNoRepeatPicPath()
{
    QStringList listpic;
    QMap<QString, QString> mapPic;
    for (auto it=m_mapFilePathPic.begin();it!=m_mapFilePathPic.end();it++)
    {
        QFileInfo info(it.key());
        if (info.isDir())
        {
            QStringList Items = it.value().toStringList();
            for (int i = 0; i < Items.size(); i++)
            {
                mapPic.insert(Items[i], Items[i]);
            }
        }
        else
        {
            mapPic.insert(it.key(), it.key());
        }
    }
    listpic = mapPic.keys();
    return listpic;
}
//獲取不重複圖片數量
int DragDropPic::GetNoRepeatPicNum()
{
    QMap<QString, QString> mapPic;
    for (auto it = m_mapFilePathPic.begin(); it != m_mapFilePathPic.end(); it++)
    {
        QFileInfo info(it.key());
        if (info.isDir())
        {
            QStringList Items = it.value().toStringList();
            for (int i = 0; i < Items.size(); i++)
            {
                mapPic.insert(Items[i], Items[i]);
            }
        }
        else
        {
            mapPic.insert(it.key(), it.key());
        }
    }
    return mapPic.size();
}
//判斷圖片數量是否超出上限
void DragDropPic::CheckLeftPicNum(bool bAlarm)
{
    int selectNum = GetNoRepeatPicNum();
    emit SignalUpdateLeftPicNum(m_leftPicNum - selectNum);
    if (m_leftPicNum== selectNum)
    {
        if (bAlarm)
        {
            emit SignalError(-3, QString("選擇的圖片數量已滿上限%1").arg(CConfig::instance()->GetLibPeopleLimit()));
        }
        
    }
    else if (m_leftPicNum<selectNum)
    {
        if (bAlarm)
        {
            emit SignalError(-3, QString("選擇的圖片數量超過上限%1,超出%2張").arg(CConfig::instance()->GetLibPeopleLimit()).arg(selectNum-m_leftPicNum));
        }
        
    }
}


//判斷是否系統盤
void DragDropPic::CheckIsSystemPath(QStringList& listDir)
{
    QStringList filelist;
    int count = 0;
    QString strError = "";
#ifdef WIN32
    for (int i = 0; i < listDir.size(); i++)
    {
        if (listDir[i].length() <= 3)
        {
            count++;
        }
        else
        {
            filelist.append(listDir[i]);
        }
    }
    strError = "不能選擇系統盤,請建立一個資料夾";
#else
    for (int i = 0; i < listDir.size(); i++)
    {
        if (listDir[i].length() <= 1)
        {
            count++;
        }
        else
        {
            filelist.append(listDir[i]);
        }
    }
    strError = "不能選擇根目錄,請建立一個資料夾";
#endif
    if (count > 0)
    {
        emit SignalError(-1, strError);
    }
    listDir = filelist;
}

遍歷查詢資料夾中圖片的執行緒

標頭檔案

#ifndef SEARCHPICTHREAD_H
#define SEARCHPICTHREAD_H

#include <QThread>
#include<QMap>
#include <QVariant>
#include<QVariantMap>
class SearchPicThread : public QThread
{
    Q_OBJECT

public:
    SearchPicThread(QObject *parent);
    ~SearchPicThread();
    void StartSearchPic(QStringList  list);
    void run();
    void stopSearch() { m_stoped = true; };
    void RecursiveInputDirFiles(QString strDir, QStringList& listPic);
signals:
    void signalSearchPicResult(QVariantMap picData);
private:
    QStringList m_listDir;
    bool m_stoped = false;
};

#endif // SEARCHPICTHREAD_H

cpp檔案

#include "SearchPicThread.h"
#include <QDir>

SearchPicThread::SearchPicThread(QObject *parent)
    : QThread(parent)
{

}

SearchPicThread::~SearchPicThread()
{

}

void SearchPicThread::StartSearchPic(QStringList list)
{
    m_listDir.append(list);
    if (this->isRunning()==false)
    {
        m_stoped = false;
        start();
    }
}

void SearchPicThread::run()
{
    QVariantMap mappic;
    while (m_listDir.size()>0)
    {
        if (m_stoped == true)//退出
        {
            break;
        }
        QString strDir = m_listDir.front();
        m_listDir.pop_front();
        QStringList listPic;
        RecursiveInputDirFiles(strDir, listPic);
        mappic.insert(strDir, listPic);
    }
    emit signalSearchPicResult(mappic);

}

void SearchPicThread::RecursiveInputDirFiles(QString strDir, QStringList& listPic)
{
    QDir dirFile(strDir);
    QDir dirDir(strDir);
    if (!dirDir.exists())
    {
        return;
    }
    dirFile.setSorting(QDir::Time);//優先顯示目錄
    dirDir.setSorting(QDir::Time);

    //列出dir(path)目錄檔案下所有檔案和目錄資訊,儲存到file_list容器
    QStringList fileNameFilter;
    //影片格式
    fileNameFilter << "*.jpg" << "*.jpeg" << "*.png" << "*.tiff";
    dirFile.setNameFilters(fileNameFilter);
    QFileInfoList file_list = dirFile.entryInfoList(QDir::Files | QDir::Hidden | QDir::NoSymLinks);
    //列出dir(path)目錄下所有子資料夾
    QFileInfoList folder_list = dirDir.entryInfoList(QDir::Dirs | QDir::Hidden | QDir::NoDotAndDotDot);
    if (file_list.size() == 0 && folder_list.size() == 0)
    {
        return;
    }
    //新增影片檔案到列表
    QString strfilepath = "";
    for (int i = 0; i < file_list.size(); i++)
    {
        strfilepath = file_list[i].absoluteFilePath();
        listPic.append(strfilepath);
    }

    //進行子資料夾folder_list遞迴遍歷,將內容存入file_list容器
    for (int i = 0; i != folder_list.size(); i++)
    {
        RecursiveInputDirFiles(folder_list.at(i).absoluteFilePath(), listPic);
    }
}

相關文章