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::SeparateChannels 和QProcess::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
執行時間較長所以需要等待一段時間,輸出效果如下圖所示;