Linux + Qt : QWebEngineView + QWebChannel 与 JS 交互传递信息
由于后期项目需要,主管安排我调研(学习)一下QT如何嵌入H5网页的应用。
刚开始我是调研“QT如何使用CEF3进行嵌入H5网页”的,但是自己孤身调研了3个星期,在windows环境下和Linux环境下,将编译好的cef动态库,嵌入到QT中去,使用会报错,会出现问题,而且还不知道怎么去解决…(如果有大佬知道怎么去使用,麻烦评论区告知一下我,谢谢!)
最后没办法,只能使用QT自身的控件QWebEngineView 进行学习如何嵌入。
这个嵌入的很简单,就几句代码,有点难度的就是如何与JS进行交互。
刚开始在网上找寻资料,讲的都是怎么互相调用各自的函数实现,但这就涉及一个如何传参的问题,这个问题很头疼。最后经过九牛二虎之力,大致上知道了这一套流程,现在记录下来,希望可以帮助更多人度过这个坑!
QT可以通过信号与槽的方式与JS进行交互,还可以直接调用JS的方法;而JS貌似只能通过调用QT的槽函数进行交互。(如果JS还有其它方式与QT进行交互通信,麻烦大佬在评论区告知一下,谢谢!)
当然,通信的这个桥梁是:qwebchannel.js。通过这个文件进行的!
这篇博客首先会讲QT使用信号与槽,将参数传给JS进行交互;JS调用QT函数,将参数传给QT的操作使用。
下一篇博客将会讲解,QT调用JS方法如何进行传参的问题!
Linux + Qt :探讨 QT调用JS方法传参 与 JS调用QT函数传参 的问题
当然,返回值的问题,我还没开始研究,如果后期自己研究到了,也就写下博客记录下来的!
项目代码在此,centos7 下 QT项目:
https://download.csdn.net/download/cpp_learner/74062364
ui文件:
按钮Click Me是下一篇博客需要使用的!
运行效果:
一、Html嵌入QT
.pro文件包含:QT += core gui webenginewidgets webchannel core
加上头文件:#include < QWebEngineView >
定义私有变量:
QWebEngineView *view; // 用于显示网页
最后在构造函数中写入一下代码即可:
view = new QWebEngineView(this);
// 设置显示的网页链接
view->setUrl(QUrl("qrc:/js.html"));
// 通过网格布局将QWebEngineView设置到QT界面上
QGridLayout *layout = new QGridLayout(this);
layout->addWidget(view);
ui->frame->setLayout(layout);
注意:js.html我是添加到资源中的,所以路径我是可以这样写,如果你的不是,那就文件在哪就写在哪的绝对路径吧!
还有一点特别重要:
在QT的安装路径下搜索qwebchannel.js文件,把他拷贝到与html同路径下!
qwebchannel.js是QT与JS交互的桥梁,没有他,他们俩就无法进行交互!
不出意外的话,编译运行就可以在QT中显示网页了!
这个js.html是自己需要显示的本地网页,当然你也可以直接显示百度的页面也是可以的!
二、Html代码
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title> JS together QT </title>
<script src="qwebchannel.js"></script>
</head>
<body>
<input id="add" type="button" value="传值给QT" onclick="fromWebToQT()"/>
<input id="input" />
<br /> <br />
<textarea id="output"></textarea><br />
<script>
new QWebChannel(qt.webChannelTransport, function(channel) {
// 注意:这个doc我不是乱写,是QT那边指定的是什么,这里就用什么
// 这个doc就相当于QT的一个对象了,可以调用QT那边的槽函数
window.doc = channel.objects.doc
// cpp通过signalToWeb信号给web传值:response
doc.signalToWeb.connect(function (response) {
//window.alert(response.header);
// response是QT传过来的Json格式数据,需要使用对应的键才能获取对应的值
var text = response["key"];
// 下面所作的操作就相当于尾部追加显示数据
var txt = document.getElementById('output').value; //获取textarea的值
document.getElementById('output').value = txt + "\n" + text; //设置textarea的值
})
})
function fromWebToQT() {
var input = document.getElementById("input");
var text = input.value;
// web调用cpp的 on_sendTextToQT 方法,并带上参数
doc.on_sendTextToQT(JSON.stringify({
key: text
}))
}
// 带参的js函数,QT也是可以调用的
function showAlert(str, count) {
var text = str + count;
alert(text);
}
</script>
</body>
</html>
三、QT 与 JS 交互
在项目中新建一个中间类,用于与QT和JS进行交互。即QT是通过它才能与JS进行交互,JS也是一样的。
我把它命名为:document.h 和 document.cpp 类名为:class Document { };
需要添加头文件:#include < QJsonObject >
定义public的函数,用于主程序调用给JS发送数据(我这里是发送Json格式数据),发送其它数据变量也是可以的,参考我下一篇博客!
public:
// 发送json数据给html
void sendJsonToWeb(const QJsonObject _obj);
定义两个信号,一个是JS给QT发送数据时使用,一个是QT给JS发送数据时使用!
signals:
void receiveTextFromWeb(const QString &test); // JS给QT发送数据
void signalToWeb(const QJsonObject &json); // QT给JS发送数据
定义一个publie的槽函数,这个槽函数是给传入JS的QT对象直接调用的(JS只能调用QT的槽函数)
public slots:
void on_sendTextToQT(const QString &test);
最后,在定义一个私有数据变量,用于存储Json数据
private:
QJsonObject obj;
在.cpp文件中,实现sendJsonToWeb函数
// 给JS发送Json数据
void Document::sendJsonToWeb(const QJsonObject _obj)
{
// 临时存储当前主程序发送给JS的数据,这里我还定义了一个函数用于返回obj的,只是没有写出来!
if (this->obj != _obj) {
obj = _obj;
}
// 通过信号带参的的形式进行发送
emit signalToWeb(_obj); // 这个是QT发送给JS
}
在.cpp文件中,实现槽函数on_sendTextToQT,
// JS调用此函数传参,带数据给QT
void Document::on_sendTextToQT(const QString &test)
{
// 发射信号,将数据传给主窗体
emit receiveTextFromWeb(test); // 这个是JS发送给QT
}
好了,到此,中间类Document已经编写完毕!
开始编写主程序的代码!
========
主程序类名为:Widget
需要添加头文件:
#include < QWebEngineView >
#include < QWebChannel >
#include < QJsonDocument >
#include " document.h "
定义一个public的函数用于自定义json数据返回
public:
// 自定义一个jsonObject返回
QJsonObject setUniqueJson(const QString &key, const QString &value);
定义Send按钮的槽函数和接收JS发送过来数据的槽函数
private slots:
// 使用信号方式传数据给html
void on_btnSend_clicked();
// 处理html传过来的数据
void on_receiveData(const QString &jsonString);
最后定义三个私有变量
private:
QWebEngineView *view; // 用于显示网页
QWebChannel *channel; // 用于和网页通讯
Document document; // QT和Html通信的中间商
好了,接下来到.cpp文件了
在构造函数中,写下如下代码:
channel = new QWebChannel(this);
// 向web客户端注册对象,使得web客户端可以通过该对象调用QT的槽函数
// 参数一:web端使用的标识(可以乱写,但必须与web中对应) 参数二:传送过去的QT对象
channel->registerObject(QString::fromLocal8Bit("doc"), &document);
view = new QWebEngineView(this);
// 设置显示的html没有上下文菜单
//view->setContextMenuPolicy(Qt::NoContextMenu);
// 设置QWebChannel,打通与JavaScript的联系
view->page()->setWebChannel(channel);
// 设置显示的网页链接
view->setUrl(QUrl("qrc:/js.html"));
// 通过网格布局将QWebEngineView设置到QT界面上
QGridLayout *layout = new QGridLayout(this);
layout->addWidget(view);
ui->frame->setLayout(layout);
ui->textEdit->setReadOnly(true);
// web调用document类的槽函数,在函数内部发射信号,主函数on_receiveData进行相应,处理接收到的数据
QObject::connect(&document, &Document::receiveTextFromWeb, this, &Widget::on_receiveData);
注意:qrc:/js.html,我写这个路径,是因为我的.html文件是放在QT的资源文件中,注意路径的问题!qwebchannel.js必须放在与.html同路径下!
实现setUniqueJson函数
// 自定义一个jsonObject返回
QJsonObject Widget::setUniqueJson(const QString &key, const QString &value)
{
// 定义json
QJsonObject json;
// 将数据绑定到json中
json.insert(key, value);
return json;
}
实现Send按钮的槽函数on_btnSend_clicked
void Widget::on_btnSend_clicked() {
// 获取用户输入的内容
QString str = ui->lineEdit->text();
ui->lineEdit->setText("");
if (str == "") {
return;
}
// 设置成json格式
QJsonObject json = setUniqueJson("key", str);
// 调用document的函数将数据传到那边,在那边进行发送给Html
document.sendJsonToWeb(json);
}
最后实现JS发送数据给QT所处理的槽函数on_receiveData
// 处理Html发送过来的数据
void Widget::on_receiveData(const QString &jsonString)
{
/* 这个字符串是Json类型的,不能直接使用,需要做转化 */
// 将字符串转换为QJsonDocument
QJsonDocument jsonDocument = QJsonDocument::fromJson(jsonString.toLocal8Bit().data());
// 判断是否转换成功,为NULL则转换失败
if(jsonDocument.isNull())
{
qDebug()<< "String NULL : "<< jsonString.toLocal8Bit().data();
}
// 获取根 { }
QJsonObject jsonObject = jsonDocument.object();
// 根据相同的键值获取数据,并显示到QTextEdit中
QJsonValue value = jsonObject.value("key");
ui->textEdit->append(value.toString());
}
到此,全部代码都已经写完,基本的通信应该不成问题,赶紧运行看看效果!
四、总结
这个具体我也不知道怎么去解释了,我也只是一知半解的新人!
对了,我这段代码把必须结合.html文件一起看才行,否则你会蒙的,不知道他们的调用流程!
我也是这样过来的,看着网上的博客,自己慢慢的一步一步的琢磨出来的,然后写下自己的理解!
更多推荐
所有评论(0)