Linux + Qt : QWebEngineView + QWebChannel 与 JS 交互传递信息

Posted cpp_learner

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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函数传参 的问题

当然,返回值的问题,我还没开始研究,如果后期自己研究到了,也就写下博客记录下来的!


ui文件

按钮Click Me是下一篇博客需要使用的!

运行效果:

一、html嵌入QT

.pro文件包含:QT += core gui webenginewidgets webchannel core

加上头文件:#include < QWebEngineView >

定义私有变量:

WebEngineView *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文件一起看才行,否则你会蒙的,不知道他们的调用流程!
我也是这样过来的,看着网上的博客,自己慢慢的一步一步的琢磨出来的,然后写下自己的理解!

以上是关于Linux + Qt : QWebEngineView + QWebChannel 与 JS 交互传递信息的主要内容,如果未能解决你的问题,请参考以下文章

QT4 Linux GUI应用程序如何把所需要的QT库一起打包,使其能在没有装QT4的Linux平台上运行??

嵌入式linux QT开发——QT简介

图解Qt安装(Linux平台)

Qt for Embedded Linux

Linux Qt 5.x 环境搭建

linux下安装qt