有的時候我們需要在自己程序運行過程中調用其他進程,那么就需要用到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命令: