1. 前言最近,C++和WEB本地混合应用开发模式逐渐流行起来,个人也认为标记语言描述的界面是界面开发的一个发展趋势。WPF、Java FX,当然也少不了Html。基于Html的界面在开发效率,可移植性上都十分有优势,所以也被很多程序采用 随着HTML5技术风生水起,Qt开发团队用近一年的时间开发了一个全新的基于Chromium的浏览器引擎Qt WebEngine,以支持面向未来的Hybrid应用开发,并完全支持桌面和嵌入式平台。此外,Qt WebEngine不仅提供了易于使用的跨平台API,还完全集成了Qt的图形库,允许网页内容进行叠加,并与Qt用户界面或OpenGL图形效果混合。Qt 5.4仍然包含老旧的Qt WebKit模块,但在其后发布的版本中将停止对于WebKit的支持,对此,Qt团队建议开发者将项目统一从WebKit迁移至Qt WebEngine,而对于需要Web能力的新项目,最好直接采用Qt WebEngine开发。在现在下载的QT5.6 beta预编译版本中已经没有了Qt WebKit模块。
目前QT官方的文档中对如何从原来的WebKit迁移至QtWebEngine没有提供足够丰富的文档和指导。 本文记录一些从WebKit迁移至QtWebEngine,实现C++与HTML和JS交互的一些经验和例子。 2. 使用Qt WebEngine和WebChannel模块在官方提供的Porting from QtWebKit to QtWebEngine---https://wiki./Porting_from_QtWebKit_to_QtWebEngine文档中给出了从WebKit迁移至QtWebEngine的一些建议和指导,其中提到QWebFrame 已经被合并到QwebEnginePage中,Qt WebEngine不能和QnetworkAccessManager交互等。 原来在Webkit中使用的交互集成的类和方法也不能使用了,原来Webkit中常用的交互方式如下: 1) 在Qt代码中加载并显示该页面
官方推荐的使用方式:
2) 在Qt对象中访问web页面元素
官方推荐的使用方式:
3) 在web页面中访问Qt对象
官方推荐的使用方式:
在QT5.5和QT5.6中,利用Qt的Qt WebEngine和WebChannel模块,你完全可以进行本地桌面与web混合应用开发,你可以自由地混合JavaScript,样式表,Web内容和Qt组件。基于Chromium的 Qt WebEngine是一个非常成熟的web浏览引擎。你可以在C++ 中执行JavaScript,或者在网页中集成C++对象,并且通过JavaScript和这些对象进行交互。 一个现代的HTML渲染引擎只是混合开发的一半,另一半就是本地应用和渲染对象的交互。QT的Chromium的 Qt WebEngine 集成提供了这种解决方案,当然目前还不是很完善。 从QT5.4开始就新增了Qt WebChannel模块,该模块提供了在QML/C++ 和 HTML/Javascript之间的一个简单、易用的桥接,从而使得开发能够使用Qt和Web技术进行混合开发,目前QT官方也推荐是用QtWebChannel来桥接C++和HTML,参见Qt WebChannel – bridging the gap betweenC++/QML and the web------https://www./watch?v=KnvnTi6XafA,这是2014年Qt开发者大会上的一段视屏演讲。 通过QtWebChannel能够实现C++/QML和HTML/javascript客户端之间进行无缝桥接,目前主要支持两种方式的桥接。
在官方演进路线中提到将来的集成解决方案将支持以下特性:
3. QtWebChannel实现C++和HTML/javascript页面之间通信实例在实例中在一个界面里实现集成QT C++组件和QWebEnginePage中嵌入的HTML页面通信,左边的lineedit组件中输入的内容通过一个document对象又QtWebChannel传到web页面,并又js解析在HTML页面上显示,右边HTML页面中的INPUT标签中输入的内容也由document对象通过QtWebChannel传到QT C++界面。通过QtWebChannel使得JS能够接收到QT C++中传出的对象,及由C++发出的信号,并与相对应的方法关联,C++也能介绍到由JS传来的对象,并调用相应的槽函数。
工程清单如下:
首先,定义一个document对象用于在C++和JS之间传递,该对象实现了信号和槽:
Document.h内容:
#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内容:
#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设计主界面,并实现主界面MainWidget类,内容如下:
mainwidget.h内容:
#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内容:
#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); //创建实例对象 ui->preview->setPage(page); //将对象设置到主界面 ui->preview->setUrl(QUrl("qrc:/index.html")); //设置载入的HTML页面
previewpage.h内容:
#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内容:
#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内容如下:
<!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的内容如下:
#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地址下载。 |
|