实现QT与HTML页面通信

1.前言

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

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

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

2.使用QtWebEngine和WebChannel模块

在官方提供的PortingfromQtWebKittoQtWebEngine---QWebEngineView*view=newQUrl("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);")



官方推荐的使用方式:

方法一: 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的QtWebChannel模块,该模块提供了在QML/C++和HTML/Javascript之间的一个简单、易用的桥接,从而使得开发能够使用Qt和Web技术进行混合开发,目前QT官方也推荐是用QtWebChannel来桥接C++和HTML,参见Qt
WebChannel–bridgingthegapbetweenC++/QMLandtheweb------

首先,定义一个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内容如下:



<!DOCTYPE
html >
<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.οnlοad=function(){

output("settingupQWebChannel.");
newQWebChannel(qt.webChannelTransport,function(channel){
//makedialogobjectaccessibleglobally
varcontent=channel.objects.content;

document.getElementById("send").οnclick=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"οnclick="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();
}
  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
### 回答1: Qt WebChannel是Qt提供的一种Web与本地应用程序通信的解决方案,它可以在Web应用程序和Qt应用程序之间建立一个桥梁,从而使得两者可以相互通信。 在使用Qt WebChannel时,需要将Web文档作为客户端,Qt应用程序则作为服务器。Qt WebChannel提供了一套API,以便在客户端和服务器之间进行通信。可以通过Qt WebChannel将Qt对象绑定到Web端的JavaScript对象上,实现在Web端调用Qt端的函数和访问Qt端的属性。 在Web应用程序中,需要引入qtwebchannel.js、qtloader.js两个脚本文件,并建立一个WebChannel对象。该对象需要指定服务器的URL,以便与服务器建立连接。 在Qt应用程序中,需要使用QWebChannel类将一个或多个Qt对象注册到WebChannel中。在注册完成之后,Web端的JavaScript代码就可以通过WebChannel调用这些Qt对象的函数和属性了。 Qt WebChannel提供了一种灵活、高效的通信机制,可以在Web应用程序和Qt应用程序之间实现方便的通信和数据交换。同时,由于WebChannel支持WebSocket和XHR两种网络传输方式,因此可以在各种不同的网络条件下进行使用,从而为开发者带来更多的便利性。 ### 回答2: Qt WebChannel是一种用于实现Qt应用程序和Web页面之间双向通信的框架。WebChannel可以将Qt的C++对象劫持并暴露给Web页面的JavaScript环境,从而实现JavaScript调用Qt中的方法、属性,并触发Qt信号槽。同样,Qt应用程序也可以通过该框架向Web页面发送信号、调用JavaScript方法。 Qt WebChannel的核心是Qt WebChannel服务器,它必须运行在Qt应用程序的主线程中。WebChannel服务器创建了一个WebSocket连接,在该连接上来回传输JSON消息。当Web页面需要访问Qt的对象时,它会通过WebSocket连接向WebChannel服务器发送一个注册消息,要求注册指定的对象。服务器将收到此请求后,会创建一个代表该对象的WebObject。这个WebObject成为了WebSocket服务器的一条新的通道。WebObject需要在Qt应用程序的主线程中创建,并提供一个QObject对象的任意子类。该QObject的方法、属性和信号都将通过WebChannel框架暴露给Web页面,以便使用JavaScript脚本访问这些属性和方法。 当Web页面与WebChannel服务器之间的WebSocket连接已准备好并且WebObject已注册时,Web页面上的JavaScript可以调用WebObject的方法、读取它的属性或连接其信号。从WebObject的角度来看,Web页面是一个观察者。当其中允许交互的JavaScript代码做出更改时,将通过WebSocket连接将这些更改通知WebChannel服务器。WebChannel服务器确保任何在Qt应用程序中发生的更改都将通过WebSocket连接传递到所有已订阅此对象的Web页面。 综上所述,Qt WebChannel使得在Web界面和Qt应用程序之间实现双向通信变得简单和可靠。应用程序可以使用WebChannel框架将对象暴露给Web页面使用,并监听来自Web页面的信号。同样,Web页面也可以访问Qt应用程序的对象和方法。这使得在许多情况下,Web页面可以作为Qt应用程序的一个合适的前端,同时不会丢失Qt应用程序的功能和性能。 ### 回答3: Qt WebChannel 是一个模块,它提供了一种简单易用的方式,让 HTML/JavaScript 页面和 C++ 后端进行通信。在此过程中,基于 WebSocket 协议,Qt WebChannel 在两端间建立了一座 “通道”,使得它们相互之间能做到即时通信。也就是说,在 HTML 页面上发生的事件,能够被 C++ 代码及时捕捉,反之亦然。 Qt WebChannel 通信涉及两个方面:一方面是 HTML 页面端,我们需要为它绑定一个构造 Qt WebChannel 对象的 JavaScript 函数;另一方面则是 C++ 后端,我们需要在其实例化后,将其封装成一个 QWebChannel 对象,并与 JavaScript 的 Qt WebChannel 对象通信。 在 HTML 页面上,我们可以通过 Qt WebChannel 的 createWebChannel() 方法来绑定一个全局函数。该函数接受一个 WebSocket URL 作为参数,在浏览器加载页面时进行调用。在该函数内部,我们还可以定义 JavaScript 对象及信号槽,并通过这些信号槽完成与 C++ 后端之间的通信。 在 C++ 后端,我们同样需要绑定一个 QWebChannel 对象,并进行消息的接收和发送。首先,我们需要在程序启动时创建一个 QWebChannel 对象,并将其在主界面线程上运行。其次,我们需要创建一个 QObject 子类,并将该子类的对象注册到 QWebChannel 中。 通信时,则需要使用 Qt 提供的 QObject 的信号槽机制。在 JavaScript 端调用 C++ 后端时,通过 QWebChannel 获得注册的 QObject 子类对象,并通过该对象的信号槽机制进行通信。在 C++ 后端接收到 JavaScript 端的函数调用时,同样可以通过 QObject 的信号槽机制进行数据响应和返回。 综上所述,Qt WebChannel 让 HTML 页面和 C++ 后端之间的通信变得十分简单直观。使用 Qt WebChannel,我们能够轻松完成前端页面与后端的数据传输和代码交互,弥补了前端 JavaScript 动态性较强但难以处理复杂业务逻辑的不足。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值