一、概述
做客戶端開發已經有好幾個年頭了,今天看到同事發了一篇關於富途牛牛的文章,核心思想就是想說,新版本的富途支持多進程架構了,效率大大提升啦,可以更好的里有多核CPU,提供軟件運行效率。
聽到這個消息,我不僅感嘆,我靠,真的好牛逼。
但是心里又在默默的想,這個東西到底有什么好處,多進程寫界面!!!從來沒這么搞過呀,會不會有坑,到底比多線程好在了哪里?帶着這個問題,從百度上看了幾篇相關文章,主要是講解了線程和進程的一些區別。當然了,最重要的還是目前的多進程架構的客戶端已經開始變得多了起來。
其實很早以前就接觸過多進程,支持自己好想也沒有想那么多,一直對多進程架構的概念不是那么清晰。今天和同事聊了一些相關話題,感覺自己的知識面豁然開朗,要學習的東西好像還挺多。
看下面這張圖,是任務管理器的應用截圖,以前還真是沒發現,居然我自己用的這么多應用都是多進程架構的。
我們平時最常用的Chrome瀏覽器,客戶端版本微信,還有有道雲筆記等等

有了這么多的多進程架構開發的客戶端軟件,難道說多進程開發已經是勢在必行了?
說這么多,還不如來點兒實際的干貨,這篇文章是我初步開始使用多進程開發段產品的初步嘗試,有不對的地方歡迎大家指出,可以給出更好建議
二、效果展示
下面是我做的一個demo程序截圖,測試程序中一共包含了4個使用場景,分別是:
- Qt嵌入系統自帶計算機
- Qt嵌入系統自帶記事本
- Qt調用系統ping命令,並收集結果
- Qt嵌入其他Qt可執行程序

大家可以先看看效果圖,如果覺着有價值的可以繼續往下看,下面我會分章節把四個事例進行講解。
三、使用方法
首先需要清楚,我們是多進程界面開發,那么我們的exe啟動后,勢必是需要啟動其他可執行程序的,並且把其他進程的界面嵌入到我們的窗口中來
1、啟動外部進程
啟動外部進程有多重方式,Qt使用比較習慣的同學可以直接使用QProcess類,這個類是Qt封裝的一個跨平台的類。
啟動方式可能像下面這樣
QProcess * myProcess = new QProcess(this);
QStringList arguments;
myProcess->start("C:/Windows/System32/notepad.exe");
myProcess->waitForFinished(2000);
除過QProcess之外,Windows系統上我們還可以使用CreateProcess方法來創建進程。
QString cmd = "C:/Windows/system32/calc.exe";
STARTUPINFO si = { sizeof(si) };
PROCESS_INFORMATION pi;
si.dwFlags = STARTF_USESHOWWINDOW;
si.wShowWindow = true;
bool bRet = CreateProcess(
NULL,
(LPWSTR)cmd.toStdWString().c_str(),
NULL,
NULL,
FALSE,
CREATE_NEW_CONSOLE,
NULL,
NULL, &si, &pi);
2、創建Qt窗口
外部進程啟動后,我們可以在任務管理器中找到啟動的進程
接着我們需要使用SPY++工具進行查看外部進程的類名稱和窗口名稱,並使用FindWindow接口進程查找,找到這個進程的主窗口句柄后,嵌入到我們的程序中來。
類名和窗口名稱查找過程可以參考外部進程嵌入到Qt進程界面這篇文章中的內容。
WId wid = (WId)FindWindow(QStringLiteral("Notepad").toStdWString().c_str()
, QStringLiteral("無標題 - 記事本").toStdWString().c_str());
QWindow * window = QWindow::fromWinId(wid);
if (window)
{
window->setFlags(window->flags() | Qt::CustomizeWindowHint | Qt::WindowTitleHint); //這邊可以設置一下屬性
QWidget * widget = QWidget::createWindowContainer(window, this, Qt::Widget);
}
如上代碼所示,我們如果找到外部進程的主窗口句柄后,就可以使用Qt提供的createWindowContainer這個接口進行創建QWidget,並加入到我們的程序中來。
3、加入到主進程布局
外部進程被封裝成為一個QWidget后,我們只需要加入到自己的布局中即可。
ui.verticalLayout_2->addWidget(widget);
接下來我們分別講解不同場景下的多進程界面開發的簡單使用
四、嵌入NotePad
第三小節已經把嵌入其他程序的流程大致說了一遍,這里我就不在詳細說明了,直接給出具體代碼。
代碼中比較關鍵的有2個地方
- QProcess不能使用臨時變量,要不然函數執行完畢notepad.exe進程也就退出了。
- FindWindow的兩個參數,一個是類名,一個窗口標題欄名稱,這兩個信息都可以用個SPY++進行查找。
void EmbedCalculate::on_pushButton_2_clicked()
{
//創建進程
QString cmd = "C:/Windows/System32/notepad.exe";
QProcess * myProcess = new QProcess(this);
QStringList arguments;
myProcess->start(cmd);
myProcess->waitForFinished(2000);
WId wid = (WId)FindWindow(QStringLiteral("Notepad").toStdWString().c_str()
, QStringLiteral("無標題 - 記事本").toStdWString().c_str());
QWindow * window = QWindow::fromWinId(wid);
if (window)
{
window->setFlags(window->flags() | Qt::CustomizeWindowHint | Qt::WindowTitleHint); //這邊可以設置一下屬性
QWidget * widget = QWidget::createWindowContainer(window, this, Qt::Widget);
ui.verticalLayout_2->addWidget(widget);
}
}
五、調用Ping命令
ping命令使用場景主要是想展示主進程和外部進程是怎樣通信的,雖然這個事例比較簡單,但也算是兩者之間發生了信息交換
子進程在執行完ping一個地址之后,會把得到的結果傳遞給主進程,主進程使用readAll函數全部讀入到主進程中。
void EmbedCalculate::on_pushButton_3_clicked()
{
//創建進程
QProcess * myProcess = new QProcess(this);
connect(myProcess, static_cast<void (QProcess::*)(int)>(&QProcess::finished), this, [this, myProcess](int exitCode){
if (exitCode == 0) {
QTextCodec * gbkCodec = QTextCodec::codecForName("GBK");
QString result = gbkCodec->toUnicode(myProcess->readAll());
ui.textEdit->setText(result);
}
});
//myProcess->start("cmd.exe", QStringList() << "/c" << "ping www.baidu.com");
myProcess->start("cmd.exe", QStringList() << "/c" << "ping " + ui.lineEdit->text().trimmed());
myProcess->waitForFinished(2000);
···
}
六、嵌入其他QWidget窗體
雖然這個東西是最后講的,但是這個才是重頭戲,有了這個實驗之后,我們以后的Qt多進程界面開發也可以進行投入正式環境了。
如下所示,ChildWidget外部程序的主窗體被我們嵌入到了EmbedCalculate這個進程的主界面上,突然覺着好神奇,給自己點贊,哈哈哈哈。

由於我這里的ChildWidget外部程序和EmbedCalculate主程序在一個目錄中,因此cmd變量直接就指向了ChildWidget這個外部程序的名稱。
其他部分的代碼基本上就和前邊幾種使用場景差不多。
void EmbedCalculate::on_pushButton_4_clicked()
{
//創建進程
QString cmd = "ChildWidget.exe";
QProcess * myProcess = new QProcess(this);
QStringList arguments;
myProcess->start(cmd);
myProcess->waitForFinished(2000);
WId wid = (WId)FindWindow(QStringLiteral("Qt5QWindowIcon").toStdWString().c_str()
, QStringLiteral("ChildWidget").toStdWString().c_str());
QWindow * window = QWindow::fromWinId(wid);
if (window)
{
window->setFlags(window->flags() | Qt::CustomizeWindowHint | Qt::WindowTitleHint); //這邊可以設置一下屬性
QWidget * widget = QWidget::createWindowContainer(window, this, Qt::Widget);
ui.verticalLayout_3->addWidget(widget);
}
}
七、相關文章
以上的內容,基本上就是本篇文章的內容所有內容啦!序列化和反序列化功能基本完成,希望可以幫到大家。
![]() |
![]() |
很重要--轉載聲明
-
本站文章無特別說明,皆為原創,版權所有,轉載時請用鏈接的方式,給出原文出處。同時寫上原作者:朝十晚八 or Twowords
-
如要轉載,請原文轉載,如在轉載時修改本文,請事先告知,謝絕在轉載時通過修改本文達到有利於轉載者的目的。