打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
实现QT与HTML页面通信
userphoto

2016.05.27

关注

1.前言

最近,C++和WEB本地混合应用开发模式逐渐流行起来,个人也认为标记语言描述的界面是界面开发的一个发展趋势。WPF、JavaFX,当然也少不了Html。基于Html的界面在开发效率,可移植性上都十分有优势,所以也被很多程序采用

随着HTML5技术风生水起,Qt开发团队用近一年的时间开发了一个全新的基于Chromium的浏览器引擎QtWebEngine,以支持面向未来的Hybrid应用开发,并完全支持桌面和嵌入式平台。此外,QtWebEngine不仅提供了易于使用的跨平台API,还完全集成了Qt的图形库,允许网页内容进行叠加,并与Qt用户界面或OpenGL图形效果混合。Qt5.4仍然包含老旧的QtWebKit模块,但在其后发布的版本中将停止对于WebKit的支持,对此,Qt团队建议开发者将项目统一从WebKit迁移至Qt
WebEngine,而对于需要Web能力的新项目,最好直接采用QtWebEngine开发。在现在下载的QT5.6beta预编译版本中已经没有了QtWebKit模块。



目前QT官方的文档中对如何从原来的WebKit迁移至QtWebEngine没有提供足够丰富的文档和指导。

本文记录一些从WebKit迁移至QtWebEngine,实现C++与HTML和JS交互的一些经验和例子。

2.使用QtWebEngine和WebChannel模块

在官方提供的PortingfromQtWebKittoQtWebEngine---https://wiki.qt.io/Porting_from_QtWebKit_to_QtWebEngine文档中给出了从WebKit迁移至QtWebEngine的一些建议和指导,其中提到QWebFrame已经被合并到QwebEnginePage中,Qt
WebEngine不能和QnetworkAccessManager交互等。

原来在Webkit中使用的交互集成的类和方法也不能使用了,原来Webkit中常用的交互方式如下:

1)在Qt代码中加载并显示该页面

QWebViewview;

view.load(QUrl("test.html"));

view.show();



官方推荐的使用方式:



QWebEngineView*view=newQWebEngineView(parent);
view->load(QUrl("http://qt-project.org/"));
view->show();



2)在Qt对象中访问web页面元素

//myPlugin指向的对象可在HTML中用名字myPluginObject进行访问
webView->page()->mainFrame()->addToJavaScriptWindowObject("myPluginObject",myPlugin);
//当信号signalEmitted被触发时,调用JavaScript的functionToCall函数
webView->page()->mainFrame()->evaluateJavaScript("myPluginObject.signalEmitted.connect(functionToCall);")



官方推荐的使用方式:

方法一:QWebEnginePage的runJavaScript(const
QString&scriptSource,FunctorOrLambdaresultCallback)
方法二:使用QtWebChannel方式,这是官方的推荐方式,他可以很方便的实现C++和HTML/JS的双向通信,同时实现C++和HTML/JS的解耦,方便开发人员的分工及系统集成,参见后面的例子。

3)在web页面中访问Qt对象

在web页面中可以通过类似于下的JavaScript代码访问Qt对象:
<ahref="javascript:document.getElementByIdx_x("myLabel").setText("通过JavaScript访问Qt对象");"mce_href="javascript:document.getElementByIdx_x("myLabel").setText("通过JavaScript访问Qt对象");">点击访问Qt对象</a>



官方推荐的使用方式:

使用QtWebChannel方式,这是官方的推荐方式,他可以很方便的实现C++和HTML/JS的双向通信,同时实现C++和HTML/JS的解耦,方便开发人员的分工及系统集成,参见后面的例子。

在QT5.5和QT5.6中,利用Qt的QtWebEngine和WebChannel模块,你完全可以进行本地桌面与web混合应用开发,你可以自由地混合JavaScript,样式表,Web内容和Qt组件。基于Chromium的
QtWebEngine是一个非常成熟的web浏览引擎。你可以在C++中执行JavaScript,或者在网页中集成C++对象,并且通过JavaScript和这些对象进行交互。

一个现代的HTML渲染引擎只是混合开发的一半,另一半就是本地应用和渲染对象的交互。QT的Chromium的QtWebEngine集成提供了这种解决方案,当然目前还不是很完善。

从QT5.4开始就新增了QtWebChannel模块,该模块提供了在QML/C++和HTML/Javascript之间的一个简单、易用的桥接,从而使得开发能够使用Qt和Web技术进行混合开发,目前QT官方也推荐是用QtWebChannel来桥接C++和HTML,参见Qt
WebChannel–bridgingthegapbetweenC++/QMLandtheweb------https://www.youtube.com/watch?v=KnvnTi6XafA,这是2014年Qt开发者大会上的一段视屏演讲。

通过QtWebChannel能够实现C++/QML和HTML/javascript客户端之间进行无缝桥接,目前主要支持两种方式的桥接。

l客户机可以是任何支持WebSockets的JavaScriptruntime机器和应用,客户机可以是独立的应用或浏览器。也就是说QtWebChannel是基于WebSockets协议之上。
l通过IPC的方式实现C++/QML和HTML/javascript客户端之间进行通信。在QT应用内嵌入HTML或JS页面的情况下使用基于IPC的WebChannel通信效率更高效。



在官方演进路线中提到将来的集成解决方案将支持以下特性:

l使用object标签嵌入QtWidgets组件。这可以让使用C++代码的Qt组件包含在网页中,作为网页的部分外观。
l在JavaScript中访问C++对象。你可以在JavaScript环境中插入C++对象,让网页脚本直接访问你的数据结构。
l在Qt中执行JavaScript。你可以在C++调用网页环境中的JavaScript函数,触发网页事件。
l共享客户端存储。在JavaScript和C++中你都具有访问数据库的能力,这样当下线时也能共享大量数据。



3.QtWebChannel实现C++和HTML/javascript页面之间通信实例

在实例中在一个界面里实现集成QTC++组件和QWebEnginePage中嵌入的HTML页面通信,左边的lineedit组件中输入的内容通过一个document对象又QtWebChannel传到web页面,并又js解析在HTML页面上显示,右边HTML页面中的INPUT标签中输入的内容也由document对象通过QtWebChannel传到QT
C++界面。通过QtWebChannel使得JS能够接收到QTC++中传出的对象,及由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;

}



用QTDesigner设计主界面,并实现主界面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地址下载。            
本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
QT
JQGRID 基本用法及示例、换肤等
十大前端开发框架
跨平台工具详解之十一:Qt(Nokia) | Web App Trend
原生开发与跨平台技术
C 图形用户界面开发框架Qt入门级教程 - 如何在QML中集成JS
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服