前言:
笔者目前正在做一个桌面应用程序,该应用程序的某一个功能已有一个现成的exe很好地实现了,要求在项目中直接使用该exe文件;且因为该功能比较耗时,需要在子线程中进行,所以有这样一个需求:新建一个线程,在线程中新建一个进程调用该exe。
方案选择:
开启线程使用Qt官方推荐的QObject::moveToThread。
开启进程使用QProcess类,QProcess类用于启动外部程序并与它们通信。
建议阅读本文代码前先阅读Qt帮助文档的QThread类和QProcess类的Detailed Description部分。
代码实现:
compiler.h
#ifndef COMPILER_H
#define COMPILER_H
#include <QObject>
#include <QProcess>
#include <QThread>
class CompilerWorker : public QObject
{
Q_OBJECT
public slots:
void doWork(const QStringList &arguments);
private slots:
void compilerFinished(int exitCode, QProcess::ExitStatus exitStatus);
void readStandardOutput();
signals:
void resultReady(const QString &result);
};
class CompilerController : public QObject
{
Q_OBJECT
public:
explicit CompilerController();
~CompilerController();
void sendOperateSignal(const QStringList &);
signals:
void operate(const QStringList &);
void threadFinished();
private slots:
void handleResults(const QString &);
private:
QThread workerThread;
};
#endif // COMPILER_H
compiler.cpp
#include <QDebug>
#include <QThread>
#include <QProcess>
#include <QTextCodec>
#include <QCoreApplication>
#include "compiler.h"
void CompilerWorker::doWork(const QStringList &arguments)
{
qDebug() << "receive the execute signal" ;
qDebug() << "\tCurrent thread ID: " << QThread::currentThreadId();
//jz 调用编译器进程
QProcess *cmplProcess = new QProcess;
QString program = "C:/LdCmpl.exe";
connect(cmplProcess, &QProcess::readyReadStandardOutput,
this, &CompilerWorker::readStandardOutput);
connect(cmplProcess, SIGNAL(finished(int,QProcess::ExitStatus)),
this, SLOT(compilerFinished(int,QProcess::ExitStatus)));
cmplProcess->start(program, arguments);
qDebug() << "[Current process ID: " << cmplProcess->processId() << "]";
}
void CompilerWorker::readStandardOutput()
{
QProcess *process = qobject_cast<QProcess *>(sender());
QTextCodec *codec = QTextCodec::codecForLocale();
QString str = codec->toUnicode(process->readAllStandardOutput());
qDebug() << str;
}
void CompilerWorker::compilerFinished(int exitCode, QProcess::ExitStatus exitStatus)
{
qDebug() << "Ldcmpl.exe process finish." << exitCode << exitStatus;
qDebug() << "\tFinish the work and sent the result Ready signal\n" ;
emit resultReady("result...");
}
//---------------------------------------------------------------------------------------
CompilerController::CompilerController()
{
CompilerWorker *compiler = new CompilerWorker;
compiler->moveToThread(&workerThread); //jz △△
connect(&workerThread, &QThread::finished, compiler, &QObject::deleteLater);
connect(this, &CompilerController::operate, compiler, &CompilerWorker::doWork);
connect(compiler, &CompilerWorker::resultReady, this, &CompilerController::handleResults);
workerThread.start();
}
CompilerController::~CompilerController()
{
qDebug() << "!!!!!!~CompilerController()";
workerThread.quit();
workerThread.wait();
}
void CompilerController::sendOperateSignal(const QStringList &arguments)
{
//jz 发信号通知开始
qDebug() << "\nemit the signal to execute!" ;
qDebug() << "\tCurrent thread ID:" << QThread::currentThreadId() << '\n' ;
emit operate(arguments);
}
void CompilerController::handleResults(const QString &result)
{
qDebug() << "receive the resultReady signal" ;
qDebug() << "\tCurrent thread ID: " << QThread::currentThreadId();
qDebug() << "\tThe result is: " << result ;
emit threadFinished();
}
widget.h
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
class QPushButton;
class CompilerController;
class Widget : public QWidget
{
Q_OBJECT
public:
Widget(QWidget *parent = 0);
~Widget();
private slots:
void clickSlot();
private:
QPushButton *pushButton;
CompilerController *compilerController = NULL;
};
#endif // WIDGET_H
widget.cpp
#include "widget.h"
#include <QDebug>
#include <QPushButton>
#include <QCoreApplication>
#include "compiler.h"
Widget::Widget(QWidget *parent)
: QWidget(parent)
{
this->resize(400, 300);
pushButton = new QPushButton(this);
pushButton->setText("PushButton");
pushButton->show();
connect(pushButton, &QPushButton::clicked, this, &Widget::clickSlot);
}
Widget::~Widget()
{
if (compilerController != NULL)
{
delete compilerController;
}
}
void Widget::clickSlot()
{
qDebug() << "[main process ID: " << QCoreApplication::applicationPid() << "]\n";
compilerController = new CompilerController;
connect(compilerController, &CompilerController::threadFinished, this, [ = ]()
{
delete compilerController;
compilerController = NULL;
});
QStringList arguments;
arguments << "C:/src.LD2" << "C:/dest.LD2.txt";
compilerController->sendOperateSignal(arguments);
}
main.cpp
#include "widget.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Widget w;
w.show();
return a.exec();
}