Qt5中创建临时的后台线程。
有个需求就是,GUI图形界面在上传文件到服务器的时候,需要用zip命令行打包,因为文件很多的时候,zip命令打包需要计算很长时间,所以把这样计算量大的任务分离到后台线程比较合适,然后任务完成,以信号槽机制来通知前台
UI线程处理结果。所以这个线程是需要销毁的,跟之前的一直在运行的后台线程接收网络数据的不一样。
压缩文件的任务类 H文件:
1 #include <QObject> 2 #include <QStringList> 3 4 class ZipUpdatePackageTask : public QObject 5 { 6 Q_OBJECT 7 8 public: 9 ZipUpdatePackageTask(); 10 ~ZipUpdatePackageTask(); 11 12 public slots: 13 void doZip(); 14 void beZipFiles(const QStringList& files); 15 signals: 16 void zipFinished(); 17 void zipPackageInfo(const QString& fileName, const QString& md5, const QString& size); 18 19 private: 20 bool beZipFilesIsEmpty(); 21 void deleteHistoryZip(const QString& targetPackage); 22 void toBeZipFilesArguments(QString &files); 23 void startZipTask(QString zipExePath, QString targetPackage, QString files); 24 QString getFileMD5(const QString& targetZipPackage); 25 QString getFileSize(const QString& targetZipPackage); 26 private: 27 QStringList m_files; 28 };
压缩任务类的 cpp文件:
1 #include <QCoreApplication> 2 #include <QFile> 3 #include <QFileInfo> 4 #include <QDir> 5 #include <QProcess> 6 #include <QCryptographicHash> 7 8 ZipUpdatePackageTask::ZipUpdatePackageTask() 9 { 10 } 11 12 ZipUpdatePackageTask::~ZipUpdatePackageTask() 13 { 14 } 15 16 void ZipUpdatePackageTask::doZip() 17 { 18 QString appDir = qApp->applicationDirPath(); 19 QString zipExePath = QString("%1/%2").arg(appDir).arg("zip.exe"); 20 if (QFile::exists(zipExePath) && !beZipFilesIsEmpty()) 21 { 22 23 QString targetZipPackage = QString("%1/%2").arg(appDir).arg("update.zip"); 24 QString beZipFiles; 25 26 toBeZipFilesArguments(beZipFiles); 27 deleteHistoryZip(targetZipPackage); 28 startZipTask(zipExePath, targetZipPackage, beZipFiles); 29 30 31 if (QFile::exists(targetZipPackage)) 32 { 33 QString size = getFileSize(targetZipPackage); 34 QString md5 = getFileMD5(targetZipPackage); 35 36 emit zipPackageInfo(targetZipPackage, md5, size); 37 38 } 39 40 41 } 42 43 emit zipFinished(); 44 } 45 46 void ZipUpdatePackageTask::beZipFiles(const QStringList& files) 47 { 48 m_files.clear(); 49 m_files = files; 50 } 51 52 bool ZipUpdatePackageTask::beZipFilesIsEmpty() 53 { 54 return m_files.isEmpty(); 55 } 56 57 void ZipUpdatePackageTask::deleteHistoryZip(const QString& targetPackage) 58 { 59 if (QFile::exists(targetPackage)) 60 { 61 QDir dir; 62 dir.remove(targetPackage); 63 } 64 } 65 66 void ZipUpdatePackageTask::toBeZipFilesArguments(QString &files) 67 { 68 for (auto file : m_files) 69 { 70 files.append(file); 71 files.append(" "); 72 } 73 } 74 75 void ZipUpdatePackageTask::startZipTask(QString zipExePath, QString targetPackage, QString files) 76 { 77 QProcess* zipProcesss = new QProcess; 78 //zip a [zip_package_path_name] [file1Path]...[fileNPath] 79 QString command = QString("%1 a %2 %3").arg(zipExePath).arg(targetPackage).arg(files); 80 zipProcesss->start(command); 81 zipProcesss->waitForFinished(-1); 82 } 83 84 QString ZipUpdatePackageTask::getFileMD5(const QString& targetZipPackage) 85 { 86 QString md5; 87 QFile file(targetZipPackage); 88 if (file.open(QFile::ReadOnly)) 89 { 90 QCryptographicHash hash(QCryptographicHash::Md5); 91 if (hash.addData(&file)) 92 { 93 md5 = QString(hash.result().toHex()); 94 } 95 96 file.close(); 97 } 98 return md5; 99 } 100 101 QString ZipUpdatePackageTask::getFileSize(const QString& targetZipPackage) 102 { 103 QFileInfo fileInf(targetZipPackage); 104 return QString::number(fileInf.size()); 105 }
以下是创建这个后台压缩线程的槽函数,当压缩上传的button点击,就调用以下这个槽函数:
1 void StatisticsWidget::slotUploadPackage() 2 { 3 QThread *zipThread = new QThread; 4 ZipUpdatePackageTask* task = new ZipUpdatePackageTask(); 5 6 7 QStringList beZipFiles; 8 for (int listRow = 0; listRow < ui->updateFileList->count(); ++listRow) 9 { 10 beZipFiles << ui->updateFileList->item(listRow)->text(); 11 } 12 13 task->beZipFiles(beZipFiles); 14 task->moveToThread(zipThread); 15 16 connect(zipThread, &QThread::started, task, &ZipUpdatePackageTask::doZip); 17 18 connect(task, SIGNAL(zipFinished()), zipThread, SLOT(quit())); 19 connect(task, &ZipUpdatePackageTask::zipPackageInfo, this, &StatisticsWidget::slotZipFinished,Qt::QueuedConnection); 20 21 //automatically delete thread and task object when work is done: 22 connect(zipThread, SIGNAL(finished()), task, SLOT(deleteLater())); 23 connect(zipThread, SIGNAL(finished()), zipThread, SLOT(deleteLater())); 24 zipThread->start(); 25 }
注意,以上代码都是临时任务和线程,当任务完成以后,由于设置了相应的信号槽,会自动删除。 任务线程做完该做的事儿,发出了一个zipPackageInfo的信号就销毁了。UI线程只用编写一个槽函数来接收做完的信号并处理就可以了。