1. 前言最近,,C++和WEB本地混合應(yīng)用開發(fā)模式逐漸流行起來,個人也認為標記語言描述的界面是界面開發(fā)的一個發(fā)展趨勢,。WPF,、Java FX,當然也少不了Html,?;贖tml的界面在開發(fā)效率,可移植性上都十分有優(yōu)勢,,所以也被很多程序采用 隨著HTML5技術(shù)風生水起,,Qt開發(fā)團隊用近一年的時間開發(fā)了一個全新的基于Chromium的瀏覽器引擎Qt WebEngine,以支持面向未來的Hybrid應(yīng)用開發(fā),,并完全支持桌面和嵌入式平臺,。此外,Qt WebEngine不僅提供了易于使用的跨平臺API,,還完全集成了Qt的圖形庫,,允許網(wǎng)頁內(nèi)容進行疊加,并與Qt用戶界面或OpenGL圖形效果混合,。Qt 5.4仍然包含老舊的Qt WebKit模塊,,但在其后發(fā)布的版本中將停止對于WebKit的支持,對此,,Qt團隊建議開發(fā)者將項目統(tǒng)一從WebKit遷移至Qt WebEngine,,而對于需要Web能力的新項目,最好直接采用Qt WebEngine開發(fā),。在現(xiàn)在下載的QT5.6 beta預(yù)編譯版本中已經(jīng)沒有了Qt WebKit模塊,。
目前QT官方的文檔中對如何從原來的WebKit遷移至QtWebEngine沒有提供足夠豐富的文檔和指導(dǎo)。 本文記錄一些從WebKit遷移至QtWebEngine,,實現(xiàn)C++與HTML和JS交互的一些經(jīng)驗和例子,。 2. 使用Qt WebEngine和WebChannel模塊在官方提供的Porting from QtWebKit to QtWebEngine---https://wiki./Porting_from_QtWebKit_to_QtWebEngine文檔中給出了從WebKit遷移至QtWebEngine的一些建議和指導(dǎo),其中提到QWebFrame 已經(jīng)被合并到QwebEnginePage中,,Qt WebEngine不能和QnetworkAccessManager交互等,。 原來在Webkit中使用的交互集成的類和方法也不能使用了,原來Webkit中常用的交互方式如下: 1) 在Qt代碼中加載并顯示該頁面
官方推薦的使用方式:
2) 在Qt對象中訪問web頁面元素
官方推薦的使用方式:
3) 在web頁面中訪問Qt對象
官方推薦的使用方式:
在QT5.5和QT5.6中,,利用Qt的Qt WebEngine和WebChannel模塊,,你完全可以進行本地桌面與web混合應(yīng)用開發(fā),你可以自由地混合JavaScript,,樣式表,Web內(nèi)容和Qt組件,?;?a target="_blank" href="http://www./">Chromium的 Qt WebEngine是一個非常成熟的web瀏覽引擎。你可以在C++ 中執(zhí)行JavaScript,,或者在網(wǎng)頁中集成C++對象,,并且通過JavaScript和這些對象進行交互。 一個現(xiàn)代的HTML渲染引擎只是混合開發(fā)的一半,,另一半就是本地應(yīng)用和渲染對象的交互,。QT的Chromium的 Qt WebEngine 集成提供了這種解決方案,當然目前還不是很完善,。 從QT5.4開始就新增了Qt WebChannel模塊,,該模塊提供了在QML/C++ 和 HTML/Javascript之間的一個簡單、易用的橋接,,從而使得開發(fā)能夠使用Qt和Web技術(shù)進行混合開發(fā),,目前QT官方也推薦是用QtWebChannel來橋接C++和HTML,參見Qt WebChannel – bridging the gap betweenC++/QML and the web------https://www./watch?v=KnvnTi6XafA,,這是2014年Qt開發(fā)者大會上的一段視屏演講,。 通過QtWebChannel能夠?qū)崿F(xiàn)C++/QML和HTML/javascript客戶端之間進行無縫橋接,目前主要支持兩種方式的橋接,。
在官方演進路線中提到將來的集成解決方案將支持以下特性:
3. QtWebChannel實現(xiàn)C++和HTML/javascript頁面之間通信實例在實例中在一個界面里實現(xiàn)集成QT C++組件和QWebEnginePage中嵌入的HTML頁面通信,左邊的lineedit組件中輸入的內(nèi)容通過一個document對象又QtWebChannel傳到web頁面,,并又js解析在HTML頁面上顯示,,右邊HTML頁面中的INPUT標簽中輸入的內(nèi)容也由document對象通過QtWebChannel傳到QT C++界面。通過QtWebChannel使得JS能夠接收到QT C++中傳出的對象,,及由C++發(fā)出的信號,,并與相對應(yīng)的方法關(guān)聯(lián),C++也能介紹到由JS傳來的對象,,并調(diào)用相應(yīng)的槽函數(shù),。
工程清單如下:
首先,定義一個document對象用于在C++和JS之間傳遞,,該對象實現(xiàn)了信號和槽:
Document.h內(nèi)容:
#ifndefDOCUMENT_H
#defineDOCUMENT_H #include<QObject> #include<QString> #include"ui_mainwidget.h" namespaceUi{ classMainWidget; } classDocument:publicQObject { Q_OBJECT Q_PROPERTY(QStringtextMEMBERs_textNOTIFYsendText) public:
explicitDocument(QObject*parent=nullptr):QObject(parent){} voidsetSendTextText(constQString&text); voidsetUi(Ui::MainWidget*ui); publicslots: voidreceiveText(constQString&r_text); signals:
voidsendText(constQString&text); private:
voiddisplayMessage(constQString&message); QStrings_text; QStringrecieve_text; Ui::MainWidget*mainUi; }; #endif//DOCUMENT_H
Document.cpp內(nèi)容:
#include"document.h" voidDocument::setSendTextText(constQString&text) { s_text=text; emitsendText(s_text); } voidDocument::displayMessage(constQString&message) { mainUi->editor->appendPlainText(message); } /*!
ThisslotisinvokedfromtheHTMLclientsideandthetextdisplayedontheserverside. */
voidDocument::receiveText(constQString&r_text) { displayMessage(QObject::tr("Receivedmessage:%1").arg(r_text)); } voidDocument::setUi(Ui::MainWidget*ui) { mainUi=ui; }
用QT Designer設(shè)計主界面,,并實現(xiàn)主界面MainWidget類,內(nèi)容如下:
mainwidget.h內(nèi)容:
#ifndefMAINWIDGET_H
#defineMAINWIDGET_H #include"document.h" #include<QWidget> #include<QString> namespaceUi{ classMainWidget; } classMainWidget:publicQWidget { Q_OBJECT public:
explicitMainWidget(QWidget*parent=0); ~MainWidget();
//publicQ_SLOTS: // voidsetEnabled(bool); privateslots: voidon_pushButton_clicked(); private:
boolisModified()const; Ui::MainWidget*ui; Documentm_content; }; #endif//MAINWIDGET_H
mainwidget.cpp內(nèi)容:
#include"mainwidget.h" #include"ui_mainwidget.h" #include"previewpage.h" #include"document.h" #include<QFile> #include<QWebChannel> MainWidget::MainWidget(QWidget*parent): QWidget(parent), ui(newUi::MainWidget) { ui->setupUi(this); PreviewPage*page=newPreviewPage(this); ui->preview->setPage(page); m_content.setUi(ui); QWebChannel*channel=newQWebChannel(this); channel->registerObject(QStringLiteral("content"),&m_content); page->setWebChannel(channel);
ui->preview->setUrl(QUrl("qrc:/index.html")); ui->editor->setPlainText("hello...\n"); } MainWidget::~MainWidget()
{ deleteui; } boolMainWidget::isModified()const { returnui->editor->document()->isModified(); } voidMainWidget::on_pushButton_clicked() { m_content.setSendTextText(ui->lineEdit->text()); }
再定義一個PreviewPage類用于加載HTML頁面,,在主界面MainWidget類初始化的時候,,將他主界面中的WebEngineView初始化為該實例對象,主要初始化代碼如下: PreviewPage*page=newPreviewPage(this); //創(chuàng)建實例對象 ui->preview->setPage(page); //將對象設(shè)置到主界面 ui->preview->setUrl(QUrl("qrc:/index.html")); //設(shè)置載入的HTML頁面
previewpage.h內(nèi)容:
#ifndefPREVIEWPAGE_H
#definePREVIEWPAGE_H #include<QWebEnginePage> classPreviewPage:publicQWebEnginePage { Q_OBJECT public:
explicitPreviewPage(QObject*parent=nullptr):QWebEnginePage(parent){} protected:
boolacceptNavigationRequest(constQUrl&url,NavigationTypetype,boolisMainFrame); }; #endif//PREVIEWPAGE_H
previewpage.cpp內(nèi)容:
#include"previewpage.h"
#include<QDesktopServices>
boolPreviewPage::acceptNavigationRequest(constQUrl&url, QWebEnginePage::NavigationType/*type*/, bool/*isMainFrame*/) { //Onlyallowqrc:/index.html. if(url.scheme()==QString("qrc")) returntrue; QDesktopServices::openUrl(url); returnfalse; }
使用的web頁面index.html內(nèi)容如下:
<!DOCTYPEhtml> <html> <head> <metahttp-equiv="Content-Type"content="text/html;charset=utf-8"/> <scripttype="text/javascript"src="./qwebchannel.js"></script> <scripttype="text/javascript"> //BEGINSETUP functionoutput(message) { varoutput=document.getElementById("output"); output.innerHTML=output.innerHTML+message+"\n"; } window.onload=function(){
output("settingupQWebChannel."); newQWebChannel(qt.webChannelTransport,function(channel){ //makedialogobjectaccessibleglobally varcontent=channel.objects.content;
document.getElementById("send").onclick=function(){ varinput=document.getElementById("input"); vartext=input.value; if(!text){ return; }
output("Sentmessage:"+text); input.value=""; content.receiveText(text); }
content.sendText.connect(function(message){ output("Receivedmessage:"+message); });
content.receiveText("Clientconnected,readytosend/receivemessages!"); output("ConnectedtoWebChannel,readytosend/receivemessages!"); }); }
//ENDSETUP </script> <styletype="text/css"> html{ height:100%; width:100%; } #input{ width:400px; margin:010px00; } #send{ width:90px; margin:0; } #output{ width:500px; height:300px; } </style> </head> <body> <textareaid="output"></textarea><br/> <inputid="input"/><inputtype="submit"id="send"value="Send"onclick="javascript:click();"/> </body> </html>
主程序main.cpp的內(nèi)容如下:
#include"document.h" #include"mainwidget.h" #include<QApplication>
intmain(intargc,char*argv[]) { QApplicationa(argc,argv); MainWidgetw; w.show();
returna.exec(); } 文中使用的例子可以到鏈接:http://download.csdn.net/detail/liuyez123/9402132地址下載,。 |
|