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