有的时候我们需要在自己程序运行过程中调用其他进程,那么就需要用到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_NAMESPACEclass QProcess;
class MainWindow : public QMainWindow {Q_OBJECTpublic: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命令: