多程式介面開發-Qt試玩兒

朝十晚八發表於2019-06-28

一、概述

做客戶端開發已經有好幾個年頭了,今天看到同事發了一篇關於富途牛牛的文章,核心思想就是想說,新版本的富途支援多程式架構了,效率大大提升啦,可以更好的適應多核CPU,提高軟體執行效率。

聽到這個訊息,我不僅感嘆,我靠,真的好牛逼。

但是心裡又在默默的想,這個東西到底有什麼好處,多程式寫介面!!!從來沒這麼搞過呀,會不會有坑,到底比多執行緒好在了哪裡?帶著這個問題,從百度上看了幾篇相關文章,其中一些是執行緒和程式的區別文章,而更多的還是關注多程式介面怎麼去開發。

資料真是少的可憐,而且都不是特別全面。所以自己打算深入的寫寫這方面的東西

其實很早以前就接觸過多程式,只是自己好像也沒有想那麼多,一直對多程式架構的概念不是那麼清晰。今天和同事聊了一些相關話題,感覺自己的知識面豁然開朗,要學習的東西好像還挺多。

看下面這張圖,是工作管理員的應用截圖,以前還真是沒發現,居然我自己用的這麼多應用都是多程式架構的。

我們平時最常用的Chrome瀏覽器,客戶端版本微信,還有有道雲筆記等等



多程式介面開發-Qt試玩兒


有了這麼多的多程式架構開發的客戶端軟體,難道說多程式開發已經是勢在必行了?

說這麼多,還不如來點兒實際的乾貨,這篇文章是我初步開始使用多程式開發端產品的嘗試,有不對的地方歡迎大家指出,可以給出更好建議

二、效果展示

下面是我做的一個demo程式截圖,測試程式中一共包含了4個使用場景,分別是:

  1. Qt嵌入系統自帶計算機
  2. Qt嵌入系統自帶記事本
  3. Qt呼叫系統ping命令,並收集結果
  4. Qt嵌入其他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個地方

  1. QProcess不能使用臨時變數,要不然函式執行完畢notepad.exe程式也就退出了。
  2. 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這個程式的主介面上,突然覺著好神奇,給自己點贊,哈哈哈哈。

多程式介面開發-Qt試玩兒

由於我這裡的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);
    }
}

七、相關文章

外部程式嵌入到Qt程式介面


以上的內容,基本上就是本篇文章的內容所有內容啦!初步完成了qt內嵌其他程式介面的功能,希望可以幫到大家。




很重要--轉載宣告

  1. 本站文章無特別說明,皆為原創,版權所有,轉載時請用連結的方式,給出原文出處。同時寫上原作者:朝十晚八 or Twowords

  2. 如要轉載,請原文轉載,如在轉載時修改本文,請事先告知,謝絕在轉載時通過修改本文達到有利於轉載者的目的。


相關文章