在线程中复制文件以防止冻结应用程序

时间:2016-06-27 07:07:38

标签: c++ multithreading qt copy freeze

我用"安装程序"写了 C ++ / QT应用程序。特征。一切都运行良好,但当我的程序处于"复制过程"时,我点击窗外,它以某种方式失去焦点并冻结,直到复制过程结束,然后一切都是正常显示, QProgressBar 值为100%。

我这样复制:

void Installer_C::copy(QString aSrcPath, QString aDstPath)
{    
  //handles
  hSrc = CreateFileW(..); //source file
  hDst = CreateFileW(..); //destination
  //copy
  ReadFile(...);
  LockFile(...);
  WriteFile(...); //->returnes bytesWritten
  UnlockFile(...);
  updateQProgressBar(bytesWritten); //updates progressbar in my application
  CloseHandle(...);
}

在foreach循环中调用此函数,遍历带有文件的QStringList(位于我的 launchInstall()函数中)。
由于我的问题,我考虑为此复制过程创建线程。为每个Installer_C::copy()调用创建一个新线程是否更有效,或者只创建一个线程来调用launchInstall()函数(我认为它不会有多大帮助)。
或者更好的问题:它甚至可以解决应用冻结的问题吗?我该如何做才能使ProgressBar仍然从这个线程更新?

2 个答案:

答案 0 :(得分:1)

我认为,解决问题的最佳方法是创建一个额外的线程来复制进程。您可以使用QThread(Qt文档:QThread)类来创建一个复制文件的线程。主线程将执行您的GUI,它将在文件复制期间可用。

复制线程的小例子:

class CopyThread : public QThread
{
    Q_OBJECT
private:
    QStringList oldfiles_;
    QStringList newfiles_;
public:
    CopyThread(const QStringList& oldfiles,
               const QStringList& newfiles,
               QObject * parent = 0)
        : QThread(parent)
        , oldfiles_(oldfiles)
        , newfiles_(newfiles)
    {}

    void run() Q_DECL_OVERRIDE 
    {
        int min = qMin(oldfiles_.count(), newFiles.count());
        for(int i=0; i<min; ++i)
        {
            copyFile(oldfiles_.at(i), newFiles_.at(i));
            emit signalCopyFile(oldfiles_.at(i), newFiles_.at(i));
        }
    }
signals:
    void signalCopyFile(const QString&, const QString&);
private:
    void copyFile(QString aSrcPath, QString aDstPath)
    {
        QFile::copy(aSrcPath, aDstPath);
    }
};

当然,您必须在窗口小部件上为signalCopyFile(const QString&, const QString&)实现插槽并建立连接。一小段代码(例如)开始复制线程并建立连接:

QStringList oldFiles;
oldfiles.append("C:/1.txt");
QStringList newFiles;
newFiles.append("C:/2.txt");
yourProgressBar.setMaximum(oldFiles.count());
yourProgressBar.setMinimum(0);
yourProgressBar.setValue(0);
CopyThread *copyThread = new CopyThread(oldFiles, newFiles, this);
connect(copyThread, &CopyThread::finished, copyThread, &QObject::deleteLater);
connect(copyThread, &CopyThread::signalCopyFile, youWidget, &YouWidget::yourSlot);
copyThread->start();

yourSlot中,您可以更新QProgressBar的价值:

void yourSlot(const QString& oldFile, const QString& newFile)
{
    // your actions when one file was copied
    yourProgressBar->setValue(yourProgressBar.value() + 1);
}

没有冻结,一切都会好的!

答案 1 :(得分:0)

据我所知,在Qt中有两种方法可以解决这个问题:

  1. 使用QCoreApplication::processEvents()。正如文档所说,这不是一个糟糕的解决方案,适合处理长期运营。我认为这对你有用。例如,您可以在复制每个文件(或几个文件)后调用它。
  2. 使用多线程。这是分离GUI线程和逻辑线程的好方法。你可以根据你的目标调整基里尔的solution
  3. 所以我的建议是:如果您需要简单快捷的工作解决方案,第一种方式适合您。

    如果您想要精心设计的和更复杂的应用程序,并且已准备好进行更多代码,请使用第二种方法