我的线程工作不好,它给出了所有结果,最后没有一个接一个,GUI 在线程运行期间挂起?

my thread is not working well it gives all result, together at last not one by one & GUI is got hanged during thread run?

本文关键字:线程 一个 挂起 运行期 有一个 GUI 最后 工作 我的 结果      更新时间:2023-10-16

我想在用户选择的特定位置按名称搜索文件。我想要在拿到文件后立即这样做。它必须并行放在QTreeWidget中,并在搜索过程中显示QMovie(":/images/img_searching.gif"),直到用户没有停止搜索。

ThreadSearch.h

#ifndef QTHREADSEARCH_H
#define QTHREADSEARCH_H
#include <QThread>
#include <QMutex>
#include <QWaitCondition>
#include <QFileInfoList>
class QThreadSearchFileName : public QThread
{
    Q_OBJECT
public:
    QThreadSearchFileName(QObject *parent = 0);
   ~QThreadSearchFileName();
    void run();
    void getAllfiles(QStringList, QDir);
signals:
    void fileInfoList(QFileInfo);
private:
    QMutex m_Mutex;
    QWaitCondition m_WaitCondition;

};
#endif

线程搜索.cpp

#include "ThreadSearch.h"
#include <QApplication>
#include <QThread>

QThreadSearchFileName::QThreadSearchFileName(QObject *parent):QThread(parent)
{
}
QThreadSearchFileName::~QThreadSearchFileName()
{
    m_WaitCondition.wakeOne();
    wait();
}
void QThreadSearchFileName::run()
{
    QMutexLocker locker(&m_Mutex); 
}
void QThreadSearchFileName::getAllfiles(QStringList targetStrList, QDir currentdir)
{
    for(long int i1=0; i1<targetStrList.size(); i1++) 
    {
        QString targetStr;
        targetStr = targetStrList[i1];
        QDirIterator it(currentdir, QDirIterator::Subdirectories);
        while (it.hasNext()) 
        {
            QString filename = it.next();
            QFileInfo file(filename);
            if (file.isDir()) 
            { // Check if it's a dir
                continue;
            }
            if (file.fileName().contains(targetStr, Qt::CaseInsensitive)) 
            {
                emit fileInfoList(file);
            }
        }
    }
}

主.cpp

#include <QCoreApplication>
#include <QDebug>
#include <QDirIterator>
   int main(int argc, char *argv[])
     {
       QCoreApplication a(argc, argv);
       QThreadSearchFileName *m_pSearchFileNameThread = new QThreadSearchFileName;
        for(int i=0; i<userSelectedpathList.size(); i++)
         {
           QDir dir(userSelectedpathList[i]);
           m_pSearchFileNameThread ->getAllfiles(stringListToBeSearch, dir);
           connect(m_pSearchFileNameThread,SIGNAL(fileInfoList(QFileInfo)),this,SLOT(searchFileNameResult(QFileInfo)));
          }   
       return a.exec();
      }

 void main::searchFileNameResult(QFileInfo file1)   //Now Making SearchFile Name Tree
  {
   QTreeWidgetItem *SearchTreeItem = new QTreeWidgetItem(m_psearchProgresswdgt->finalSearchList_treeWidget);
   SearchTreeItem->setCheckState(0,Qt::Unchecked);
   SearchTreeItem->setText(1,file1.baseName());
  }
最好将

此类操作与 GUI 对象分开。更重要的是,我建议QObject提供的更高级别的异步机制:

  • 例如,创建一些可以处理搜索的类搜索类

    class SearchingClass : public QObject {
        Q_OBJECT
    public:
        void setSomeSearchParametersOrSomething(QObject* something);
    public slots:
        void search();
    signals:
        void found(QObject* objectThatHasBeenFound);
    }
    
  • 创建此类的实例并将其移动到另一个线程中:

    auto searchingObject = new SearchingClass();
    searchingObject->setSomeSearchParametersOrSomething(...);
    auto thread = new QThread();
    searchingObject->moveToThread(thread);
    connect(this, SIGNAL(startSearchingSignal()), searchingObject, SLOT(search()));
    connect(searchingObject, SIGNAL(found(QObject*)), this, SLOT(someHandleFoundSlot(QObject*)));
    emit startSearchingSignal();
    
  • 确保每次搜索算法找到某些结果时都会发出找到的信号。

  • Ofc 你必须实现 someHandleFoundSlot 并在 GUI 类中声明 startSearchingSignal 信号。

我假设你几乎不了解Qt框架,所以你应该阅读信号和插槽以及Qt元对象系统,以完全理解整个代码。

编辑:我看到您已经编辑了您的问题。你的问题有几个解决方案,我会描述你,你做错了什么,与我在这里发布的内容相比。

  1. 不要延长QThread。改为扩展QObject。它使你可以调用moveToThread方法。创建 QThread 的实例并将其传递给此方法。它会导致稍后在您传递的线程中执行插槽。
  2. 不要在循环中建立相同的连接,直到您希望多次执行它。
  3. 将方法getAllfiles(或在我的示例中search)设置为插槽,不要手动调用它。手动调用方法时,它将始终在同一线程中执行。只需将其连接到某个信号,然后发出信号[就像您在找到匹配文件时发出信号一样 - 结果正在插槽对象线程中处理。
  4. 这是
  5. 您的决定,如果你想为每个userSelectedpathList元素都有线程。我建议您在一个工作线程中执行此操作(这是磁盘操作,我认为它不会更快)并在getAllfiles方法中迭代该列表。

之前我给了你关于"如何在Qt中进行异步工作"的通用答案。这是您的用例的简单实现(我希望您能学到一些东西)。

主.cpp

#include "mainwindow.h"
#include <QApplication>
int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    MainWindow w;
    w.show();
    return a.exec();
}

主窗口.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QFileInfo>
#include <QDirIterator>
#include <QThread>
#include <QDebug>
#include <QPushButton>
#include "filesearchingclass.h"
class MainWindow : public QMainWindow
{
    Q_OBJECT
public:
    MainWindow(QWidget *parent = 0){
        setCentralWidget(&pushButton);
        connect (&pushButton, SIGNAL(clicked(bool)), this, SLOT(main()));   //invoke this->main() in event loop when button is pressed
        qRegisterMetaType<QFileInfo>("QFileInfo");
        searchingThread.start();    //thread must be started
    }
    ~MainWindow(){
        searchingThread.quit();
        searchingThread.wait();
    }
public slots:
    void main() {
        //EXAMPLE PARAMETERS:
        QStringList pathList;
        pathList.append("/home");
        pathList.append("/var/log");
        QStringList stringListToBeSearch;
        stringListToBeSearch.append(".jpg");
        stringListToBeSearch.append(".log");
        //-------------------
        auto fileSearchingObject = new FileSearchingClass();    //dynamic as you can't destroy object when it is out of scope
        fileSearchingObject->moveToThread(&searchingThread);    //important!!!
        fileSearchingObject->setTargetStrList(stringListToBeSearch);
        fileSearchingObject->setPaths(pathList);
        connect(this,SIGNAL(startSearching()),fileSearchingObject,SLOT(search()));  //do not call fileSearchingObject->search() manually
        connect(fileSearchingObject,SIGNAL(foundFile(QFileInfo)),this,SLOT(searchFileNameResult(QFileInfo)));   //handle every result in event loop
        connect(fileSearchingObject, SIGNAL(searchFinished()), fileSearchingObject, SLOT(deleteLater()));   //no need to wory about deleting fileSearchingObject now
        emit startSearching();  //like calling fileSearchingObject->search() but in another thread (because of connection)
    }
signals:
    void startSearching();
public slots:
    void searchFileNameResult(QFileInfo fileInfo) {
        //do something
        qDebug() << "---FOUND---" << fileInfo.absoluteFilePath() << "n";
    }
private:
    QThread searchingThread;
    QPushButton pushButton;
};
#endif // MAINWINDOW_H

文件搜索类.h

#ifndef FILESEARCHINGCLASS_H
#define FILESEARCHINGCLASS_H
#include <QFileInfo>
#include <QDirIterator>
#include <QThread>
#include <QDebug>
class FileSearchingClass : public QObject {
    Q_OBJECT
public:
    ~FileSearchingClass(){}
    void setPaths (const QStringList &paths) {
        userSelectedPathList = paths;
    }
    void setTargetStrList(const QStringList &value) {
        targetStrList = value;
    }
public slots:
    void search() {
        for(int i=0; i<userSelectedPathList.size(); i++) {
            QDir currentDir(userSelectedPathList[i]);
            for(long int i1=0; i1<targetStrList.size(); i1++)
            {
                QString targetStr;
                targetStr = targetStrList[i1];
                QDirIterator it(currentDir, QDirIterator::Subdirectories);
                while (it.hasNext())
                {
                    QString filename = it.next();
                    QFileInfo file(filename);
                    if (file.isDir())
                    { // Check if it's a dir
                        continue;
                    }
                    if (file.fileName().contains(targetStr, Qt::CaseInsensitive))
                    {
                        emit foundFile(file);   //calling MainWindow::searchFileNameResult directly is possible, but bad idea. This thread is only focused in searching, not modifing widgets in GUI.
                    }
                }
            }
        }
        emit searchFinished();  //it's always good to know when job is done.
    }
signals:
    void foundFile(QFileInfo);
    void searchFinished();
private:
    QStringList userSelectedPathList;
    QStringList targetStrList;
};
#endif // FILESEARCHINGCLASS_H