QtWebkits如何向QtWebEngine過渡


QtWebkits如何向QtWebEngine過渡

1. 前言

很遺憾,QtWebkits在Qt5.6以上版本被淘汰了,對於這個接口良且和其他類例如QWebFrame完美結合的組件就這么沒了,我只能表示惋惜。對於QtWebEngine新的組件,不得不承認它從Chromium繼承過來的強大的性能,但接口上還不是很豐富,和其他類的交互也不是很完美,期待Qt能夠對其進行進一步開發,我也會不斷的升級Qt,嘗試新的接口。

目前而言,QWebEngine有以下缺點:

  • MinGW版本的Qt不支持,即便是Qt5.6版本以上也是不支持的。僅僅支持MSVC版本。
  • 接口暫時不豐富
  • 無法和QWebFrame進行交互(使用了新的QWebChannel和QWebEnginePage組合進行交互)

基於我們的GPS定位項目,參考:[Qt開發北斗定位系統融合百度地圖API及Qt程序打包發布] ,我們在該項目中使用的是Qt5.5版本,在嵌入的瀏覽器作為加載地圖用的是QWebKits組件,我們將其升級使用QWebEngine進行加載地圖,和HTML和JS進行交互。我們以此為例,進行簡要的介紹。

2. 兩者的UI上面的區別

你剛剛升級到Qt5.6版本可能在UI設計界面時候在組件中找不到QWebEngineView這個組件,無法從這里拖拽這個組件到你的UI界面上。我查閱了很多資料,看到別人經常使用 ui->webEngineview->... 這樣,我甚至懷疑是否因為安裝了其他版本的Qt影響到了我,我卸載了包含5.6版本的所有Qt,又重新安裝了一遍,但是再重啟軟件后,依然沒有發現QWebEngineView這個鬼東西。在Qt5.5中你也能發現有這樣的組件QWebView,如圖1所示:

Qt舊版本中的WebKits項

QWebView組件可以通過QWebFrame來進行HTML和JS的通信,如果過渡到QWebEngineView,要是沒有這個UI組件的話,我如何把瀏覽器嵌入到軟件界面,實現網頁和軟件的混合編程呢。根據官方提供的一個例子中,cookiebrowser中找到了答案,這也是官方給的例子中,唯一一個嵌入到網頁中的!(不得不說,Qt給的例子很模糊很差!) 經過研究, QWebEngineView使用widget組件,拖拉出來是一個透明的組件,對着組件按右鍵->promote to.. ->選擇QWebEngineView,如圖2,完成操作。

把Widget promote to 成QWebEngineView組件

有了QWebEngineView這個UI組件,我們可以在程序中調用其成員、方法和函數完成操作了。

3. 使用方法區別

在使用方法上有很大的區別,可以說是兩個完全不同理念的東西,這里為了更通俗易懂,就不粘貼API文檔中函數解釋,就用最常用的!

#include <QtWebEngineWidgets>	// 基本組件
#include <QWebEnginePage>	    // HTML頁面
#include <QWebChannel>          // C++和JS/HTML雙向通信,代替了已淘汰的QtWebFrame的功能

在我們的項目中一開始就要引入這樣的組件,但在我們的項目中,沒有頻繁用到與JS的互相交互,所以這里暫時沒有關於QWebChannel的使用方法,只留下這個接口。

以下為區別:


  • 在WebKits中的初始化:
QUrl url(strMapPath);		// strMapPath為QString類,是你html文件的路徑
ui->webView->load(url);
ui->webView->setContentsMargins(0,0,0,0);
ui->webView->setTextSizeMultiplier(1);//設置網頁字體大小
connect(ui->webView->page()->mainFrame(), SIGNAL(javaScriptWindowObjectCleared()),
            this, SLOT(slotPopulateJavaScriptWindowObject()));

我們會使用load方法加載html所在的界面,使用QWebFrame類的mainFrame()中的SIGNAL和槽函數

void Widget::slotPopulateJavaScriptWindowObject()
{
    ui->webView->page()->mainFrame()->addToJavaScriptWindowObject("ReinforcePC", this);
}

進行響應。參考文獻1:《javascript調用qt》,可以解釋這個槽函數的重要性。

  • 在WebEngine中的初始化:
QWebEnginePage *page = new QWebEnginePage(this);  // 定義一個page作為頁面管理
QWebChannel *channel = new QWebChannel(this);     // 定義一個channel作為和JS或HTML交互
page->load(strMapPath);							// page上加載html路徑
page->setWebChannel(channel);					// 把channel配置到page上,讓channel作為其信使
ui->webEngine->setPage(page);					// 建立page和UI上的webEngine的聯系

如果你的 初始化程序寫到這里,當你運行程序的時候,無論是webKits里的WebView還是新版的webEngineView,你的UI界面上的那個組件區域就會顯示那個html文件了。

到此,我們完成了兩者的初始化。


  • WebKits組件中的運行JS:

我們以按鈕的槽函數為例,當點擊按鈕時,會向JS發送命令,運行JS腳本,我們這里發送的是將顯示變為衛星圖的JS命令:

void Widget::on_pushButtonStreetMap_clicked()
{
    QWebFrame *frame = ui->webView->page()->mainFrame(); // 定義一個QWebFrame負責交互
    QString cmd = QString("showStreetMap()"); // JS的命令
    frame->evaluateJavaScript(cmd);			  // 使用frame下的命令運行該命令
}

從這個例子中我們也可以看到,QWebFrame是JS交互的關鍵。

  • WebEngine組件中的運行JS:

還是以該槽函數為例:

void Widget::on_pushButtonSatelliteMap_clicked()
{
    QString cmd = "showSatelliteMap()";
    ui->webEngine->page()->runJavaScript(cmd);		// 直接page()下就可以運行
}

在JS單向通信中十分簡單,也不需要使用QWebChannel信使,但該方法runJavaScript()無法在構造函數中使用,原因不明。也可以這樣使用:

connect(ui->webEngine,&QWebEngineView::loadFinished,[=](int){
             ui->webEngine->page()->runJavaScript(cmd1);

第二個參數SIGNAL位置的,只能使用這樣的方式調用,如果使用SIGNAL(....loadFinished),報錯。

4. 總結

通過這樣的方法,我們就完成了一個初級的過渡。本人由於是研究嵌入式的程序員,只是上位機學習簡單的Qt做一點點當成輔助開發,並沒有什么高深的Qt技術,也正在學習中,歡迎討論。

參考文獻:

[1] 在水一方著.javascript調用Qt.CSDN博客.2011-07-18.

[2]Я!ńɡ著.QT5利用chromium內核與HTML頁面交互.CNBLOGS. 2015-11-17.

[3]liuyez123著.[實現QT與HTML頁面通信]. CSDN博客. 2016-01-13.


版權聲明:

1. 本文為MULTIBEANS團隊研發跟隨文章,未經允許不得轉載。

2· 文中涉及的內容若有侵權行為,請與本人聯系,本人會及時刪除。

3· 尊重成果,本文將用的參考文獻全部給出,向無私的工程師,愛好者致敬。


** 博文Markdown原版下載:http://pan.baidu.com/s/1qXGljC4 提取碼:uk3b **


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM