有的时候我们需要在自己程序运行过程中调用其他进程,那么就需要用到QProcess。
首先可以了解一些关于进程的相关知识:线程与进程,你真得理解了吗_进程和线程的区别-CSDN博客
进程是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配的基本单位,是操作系统结构的基础。
如何查看系统中正在运行的进程以及如何杀死进程:
Windows:
启动进程:tasklist
杀死进程:taskkill /F /PID 4204(进程id)
Linux:
查看进程:ps -ef
杀死进程:kill -9 4341(进程id)
QProces的使用:
QProcess通过start和startDetached两个方法都可以启动进程,其中前者是一体式启动,即外部程序启动后,将随主程序的退出而退出。后者是分离式启动,即外部程序启动后,当主程序退出时并不退出,而是继续运行。
这次主要说start这个方法:
void
start(const QString &program, const QStringList &arguments, QIODevice::OpenMode mode = ReadWrite)
主要需要注意第一个参数和第二个参数,第一个参数是要执行的命令或者程序,第二个参数是这个程序的运行参数。关于这两个先看一个最简单的qt程序代码:
#include <QCoreApplication>
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
return a.exec();
}
这个代码大家再熟悉不过来,就是一个最简单的qt控制台程序,不知道大家有没有注意过main函数的两个参数argc和argv[]。
-
int argc
:代表命令行参数的数量,即传递给程序的参数个数。通常情况下,argc
至少为1,因为第一个参数通常是程序本身的名称。 -
char *argv[]
:是一个指向字符指针数组的指针,其中每个元素是一个指向表示一个命令行参数的C风格字符串的指针。argv[0]
通常是程序的名称,后续元素是传递给程序的其他参数。
试着打印一下:
#include <QCoreApplication>
#include <QDebug>
int main(int argc, char *argv[]) {
QCoreApplication a(argc, argv);
for (int i = 0; i < argc; ++i) {
qDebug() << argv[i];
}
return a.exec();
}
编译运行查看打印:
打印了一个参数,即程序的名称。试着给这个控制台程序启动时加几个参数:
使用QtCreator传入运行参数也可以这样设置:
运行查看结果:
也可以使用QCoreApplication::arguments()打印参数:
#include <QCoreApplication>
#include <QDebug>
int main(int argc, char *argv[]) {
QCoreApplication a(argc, argv);
for (int i = 0; i < argc; ++i) {
qDebug() << argv[i];
}
QStringList args = QCoreApplication::arguments();
for (const QString &arg : args) {
qDebug() << arg;
}
return a.exec();
}
编译运行查看:
QProcess使用start传入对应参数,这是要启动的程序:
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent), ui(new Ui::MainWindow) {
ui->setupUi(this);
for (const QString &arg : QCoreApplication::arguments()) {
ui->textEdit->append(arg);
}
}
MainWindow::~MainWindow() { delete ui; }
将程序参数显示到对应QTextEdit上:
#include <QCoreApplication>
#include <QDebug>
#include <QProcess>
int main(int argc, char *argv[]) {
QCoreApplication a(argc, argv);
QProcess *p = new QProcess;
QStringList args;
args << "1"
<< "2"
<< "3";
p->start("G:\\qtprojects\\ConsoleP\\debug\\ConsoleP.exe", args);
return a.exec();
}
编译查看运行结果:
QProcess通过processId来获取对应进程id。
关于QProcess的信号:
其中readyReadStandardError()与readyReadStandardOutput()收到对应信号后通过readAllStandardOutput()与readAllStandardError()来获取对应程序标准输出以及异常输出,进程运行完成后会触发finished()信号,进程状态改变会触发stateChanged信号。写一个例子:
头文件:
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
QT_BEGIN_NAMESPACE
namespace Ui {
class MainWindow;
}
QT_END_NAMESPACE
class QProcess;
class MainWindow : public QMainWindow {
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
private:
void appendLog(const QString &text);
private slots:
void on_open_clicked();
void on_cmd_clicked();
void on_clear_clicked();
private:
Ui::MainWindow *ui;
QProcess *m_Process;
};
#endif // MAINWINDOW_H
源文件:
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QDateTime>
#include <QFileDialog>
#include <QProcess>
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent), ui(new Ui::MainWindow) {
ui->setupUi(this);
m_Process = new QProcess;
connect(m_Process, &QProcess::readyReadStandardOutput, [=]() {
QByteArray output = m_Process->readAllStandardOutput();
QString outputString = QString::fromLocal8Bit(output);
appendLog("output:" + outputString);
});
connect(m_Process, &QProcess::readyReadStandardError, [=]() {
QByteArray output = m_Process->readAllStandardError();
QString outputString = QString::fromLocal8Bit(output);
appendLog("error:" + outputString);
});
connect(m_Process, &QProcess::stateChanged,
[=](QProcess::ProcessState newState) {
appendLog("stateChanged:" + QString::number(newState));
});
connect(m_Process, &QProcess::errorOccurred,
[=](QProcess::ProcessError error) {
appendLog("errorOccurred:" + QString::number(error));
});
connect(m_Process,
static_cast<void (QProcess::*)(int exitCode,
QProcess::ExitStatus exitStatus)>(
&QProcess::finished),
[=](int exitCode, QProcess::ExitStatus exitStatus) {
appendLog("finished:" + QString::number(exitCode) + ":" +
QString::number(exitStatus));
});
}
MainWindow::~MainWindow() {
delete ui;
}
void MainWindow::appendLog(const QString &text) {
ui->textEdit->append(QString("%1:program=%2:pid=%3:%4")
.arg(QDateTime::currentDateTime().toString(
"yyyy/MM/dd hh:mm:ss.zzz"))
.arg(m_Process->program())
.arg(m_Process->processId())
.arg(text));
}
void MainWindow::on_open_clicked() {
QString pragramName =
QFileDialog::getOpenFileName(nullptr, nullptr, QString());
ui->program->setText(pragramName);
}
void MainWindow::on_cmd_clicked() {
if (ui->program->text().isEmpty()) return;
m_Process->setProgram(ui->program->text());
QStringList arguments;
arguments << ui->arguments->text();
m_Process->setArguments(arguments);
m_Process->start();
}
void MainWindow::on_clear_clicked() {
ui->textEdit->clear();
}
ui:
编译运行然后再对应输入框输入程序路径以及对应参数,以刚刚写的例子为例:
然后关闭启动的进程:
可以看到关闭后触发了对应finished()信号,然后通过打印可以看到状态从打开到关闭的变化情况是:1(Starting)->2(Running)->0(NotRunning) 。并且触发finished()信号时由于进程已经关闭,所以获取不到对应的进程id,但是stateChanged(NotRunning)会先于finished(),并且这时进程没有完全关闭所有能获取到对应进程id。也可以输入一些cmd命令: