作客戶端開發已經有好幾個年頭了,今天看到同事發了一篇關於富途牛牛的文章,核心思想就是想說,新版本的富途支持多進程架構了,效率大大提高啦,能夠更好的裏有多核CPU,提供軟件運行效率。微信
聽到這個消息,我不只感嘆,我靠,真的好牛逼。多線程
可是內心又在默默的想,這個東西到底有什麼好處,多進程寫界面!!!歷來沒這麼搞過呀,會不會有坑,到底比多線程好在了哪裏?帶着這個問題,從百度上看了幾篇相關文章,主要是講解了線程和進程的一些區別。固然了,最重要的仍是目前的多進程架構的客戶端已經開始變得多了起來。架構
其實很早之前就接觸過多進程,支持本身好想也沒有想那麼多,一直對多進程架構的概念不是那麼清晰。今天和同事聊了一些相關話題,感受本身的知識面豁然開朗,要學習的東西好像還挺多。函數
看下面這張圖,是任務管理器的應用截圖,之前還真是沒發現,竟然我本身用的這麼多應用都是多進程架構的。工具
咱們平時最經常使用的Chrome瀏覽器,客戶端版本微信,還有有道雲筆記等等
佈局
有了這麼多的多進程架構開發的客戶端軟件,難道說多進程開發已是勢在必行了?學習
說這麼多,還不如來點兒實際的乾貨,這篇文章是我初步開始使用多進程開發段產品的初步嘗試,有不對的地方歡迎你們指出,能夠給出更好建議測試
下面是我作的一個demo程序截圖,測試程序中一共包含了4個使用場景,分別是:ui
你們能夠先看看效果圖,若是覺着有價值的能夠繼續往下看,下面我會分章節把四個事例進行講解。
首先須要清楚,咱們是多進程界面開發,那麼咱們的exe啓動後,勢必是須要啓動其餘可執行程序的,而且把其餘進程的界面嵌入到咱們的窗口中來
啓動外部進程有多重方式,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);
外部進程啓動後,咱們能夠在任務管理器中找到啓動的進程
接着咱們須要使用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,並加入到咱們的程序中來。
外部進程被封裝成爲一個QWidget後,咱們只須要加入到本身的佈局中便可。
ui.verticalLayout_2->addWidget(widget);
接下來咱們分別講解不一樣場景下的多進程界面開發的簡單使用
第三小節已經把嵌入其餘程序的流程大體說了一遍,這裏我就不在詳細說明了,直接給出具體代碼。
代碼中比較關鍵的有2個地方
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一個地址以後,會把獲得的結果傳遞給主進程,主進程使用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); ··· }
雖然這個東西是最後講的,可是這個纔是重頭戲,有了這個實驗以後,咱們之後的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); } }
以上的內容,基本上就是本篇文章的內容全部內容啦!序列化和反序列化功能基本完成,但願能夠幫到你們。
很重要--轉載聲明