C++ Qt開發:QProcess程序管理模組

lyshark發表於2024-03-22

Qt 是一個跨平臺C++圖形介面開發庫,利用Qt可以快速開發跨平臺窗體應用程式,在Qt中我們可以透過拖拽的方式將不同元件放到指定的位置,實現圖形化開發極大的方便了開發效率,本章將重點介紹如何運用QProcess元件實現針對程序的控制管理等。

當你在使用Qt進行跨平臺應用程式開發時,經常需要與外部程序進行互動,這時就可以利用Qt的QProcess模組。QProcess模組提供了啟動和控制外部程序的功能,能夠執行外部命令、執行其他可執行檔案,以及與外部程序進行通訊。透過QProcess,可以方便地執行命令列命令、呼叫系統工具、執行指令碼等。QProcess還可以捕獲外部程序的輸出,以及監視外部程序的執行狀態,從而實現更靈活、高效的程序管理。

以下是QProcess類的一些常用函式及其解釋的表格:

函式 描述
start(const QString &program, const QStringList &arguments) 啟動一個新的程序,program引數指定要執行的程式,arguments引數指定傳遞給程式的引數列表。
startDetached(const QString &program, const QStringList &arguments) 啟動一個新的程序,但不會等待程序退出,也不會將輸出傳遞給呼叫程序。
waitForStarted(int msecs = 30000) 等待程序啟動,如果在指定時間內程序沒有啟動,將返回false。
waitForFinished(int msecs = 30000) 等待程序退出,如果在指定時間內程序沒有退出,將返回false。
readAllStandardOutput() 讀取程序的標準輸出,並返回為QByteArray
readAllStandardError() 讀取程序的標準錯誤輸出,並返回為QByteArray
write(const QByteArray &data) 向程序的標準輸入寫入資料。
closeWriteChannel() 關閉程序的標準輸入。
kill() 終止程序。
terminate() 終止程序。
start(const QString &program) 啟動一個新的程序,program引數指定要執行的程式。
setWorkingDirectory(const QString &dir) 設定程序的工作目錄。
state() 返回程序的當前狀態。
error() 返回程序的錯誤狀態。
pid() 返回程序的程序ID。
waitForBytesWritten(int msecs = 30000) 等待寫入到程序的資料已經被完全寫入。
waitForReadyRead(int msecs = 30000) 等待程序有資料可讀。
startDetached(const QString &program) 啟動一個新的程序,但不會等待程序退出,也不會將輸出傳遞給呼叫程序。
setProcessChannelMode(QProcess::ProcessChannelMode mode) 設定程序通訊模式,可選值包括QProcess::SeparateChannelsQProcess::MergedChannels

這些函式提供了控制程序的各種方法,可以實現啟動、監視、控制和與外部程序進行互動的功能。

程序控制模組可以實現對特定程序的啟動關閉,本章將以執行命令列為例,透過呼叫Start()可以拉起一個第三方程序。

QProcess類的start()函式有幾種不同的過載形式,但最常用的是以下形式:

bool QProcess::start(
    const QString &program, 
    const QStringList &arguments, 
    QIODevice::OpenMode mode = ReadWrite
)

函式用於啟動一個新的程序,並執行指定的程式(program引數)。arguments引數指定了傳遞給程式的引數列表,它是一個QStringList型別的引數,可以為空。mode引數指定了啟動程序時開啟的模式,預設為ReadWrite。函式返回一個bool型別的值,表示程序是否成功啟動。

當呼叫start()執行命令後,我們則可以透過readAllStandardOutput()函式從程序的標準輸出中讀取所有可用的資料,並將其返回為 QByteArray 物件。

QByteArray QProcess::readAllStandardOutput()

這個函式沒有引數,它會立即返回當前可用的標準輸出資料,並將輸出資料作為位元組陣列返回。如果沒有可用的輸出資料,它將返回一個空的位元組陣列。

當然了,與之對應的readAllStandardError()是函式,該函式可以用於從程序的標準錯誤輸出中讀取所有可用的資料,並將其返回為 QByteArray 物件。

QByteArray QProcess::readAllStandardError()

該函式同樣沒有引數,它會立即返回當前可用的標準錯誤輸出資料,並將輸出資料作為位元組陣列返回。如果沒有可用的錯誤輸出資料,它將返回一個空的位元組陣列。

1.1 獲取程序資訊

此處我們以輸出系統程序資訊為例,通常可以呼叫tasklist /FO CSV來獲取系統中的程序列表,並將其輸出為CSV格式,透過呼叫如下函式則可以獲取到系統程序資訊。

process.start("tasklist", QStringList() << "/FO" << "CSV");

此時透過呼叫readAllStandardOutput函式我們可以將緩衝區內的資料讀出並將其放入到一個QString型別變數內;

QString output = process.readAllStandardOutput();

當具備了這個列表後,就可以根據冒號來逐行讀入並切割,透過迴圈的方式將其追加到treeWidget元件內,並以此來實現展示的效果;

void MainWindow::on_pushButton_clicked()
{
    CallProcess();

    ui->treeWidget->clear();

    QProcess process;
    process.start("tasklist", QStringList() << "/FO" << "CSV");

    if (process.waitForFinished())
    {
        QString output = process.readAllStandardOutput();
        output.replace("\"", "");

        QStringList lines = output.split("\n");

        // 跳過第一行標題
        for(int i = 1; i < lines.size(); ++i)
        {
            QStringList fields = lines[i].split(",");

            // 確保至少有五個欄位
            if(fields.size() >= 5)
            {
                QStringList rowData;
                for(int j = 0; j < 5; ++j)
                {
                    rowData << fields[j].trimmed();
                }
                ui->treeWidget->addTopLevelItem(new QTreeWidgetItem(rowData));
            }
        }

        // 設定列標題
        ui->treeWidget->setHeaderLabels(QStringList() << "程序名稱" << "PID" << "會話名稱" << "Session"<< "記憶體佔用");
    } else
    {
        QTreeWidgetItem *item = new QTreeWidgetItem(ui->treeWidget);
        item->setText(0, "Failed to execute tasklist command.");
    }
}

執行後當點選輸出系統程序時則可以看到完整的程序輸出效果,如下圖所示;

使用此方法我們可以很好的讀取到系統中的各種資訊,只要能夠合理的過濾出想要的欄位即可,當需要輸出系統資訊時我們可以透過process.start("systeminfo")呼叫系統命令獲取到,如下程式碼所示;

void MainWindow::on_pushButton_2_clicked()
{
    ui->treeWidget->clear();

    // 獲取系統資訊
    QProcess process;
    process.start("systeminfo");

    if (process.waitForFinished())
    {
     QByteArray output = process.readAllStandardOutput();

     // 使用正確的文字編碼對輸出進行解碼
     QTextCodec *codec = QTextCodec::codecForName("GBK");
     QString text = codec->toUnicode(output);

     QStringList lines = text.split("\n");
     for (const QString &line : lines)
     {
         // 解析系統資訊,新增到 QTreeWidget 中
         QStringList fields = line.split(":", Qt::SkipEmptyParts);
         if (fields.size() >= 2)
         {
             QString property = fields[0].trimmed();
             QString value = fields[1].trimmed();

             QTreeWidgetItem *item = new QTreeWidgetItem(ui->treeWidget);
             item->setText(0, property);
             item->setText(1, value);
         }
     }

     // 設定列標題
     ui->treeWidget->setHeaderLabels(QStringList() << "系統資訊" << "數值");
    } else
    {
     QTreeWidgetItem *item = new QTreeWidgetItem(ui->treeWidget);
     item->setText(0, "Failed to execute systeminfo command.");
    }
}

執行後當使用者點選輸出系統資訊按鈕時,因systeminfo執行時間較長所以需要等待一段時間,輸出效果如下圖所示;

相關文章