Qt-Web混合开发-QtWebChannel实现Qt与Web通信交互-进阶功能(6) 原创
Qt-Web混合开发-QtWebChannel实现Qt与Web通信交互-进阶功能🥬
更多精彩内容 |
---|
👉个人内容分类汇总 👈 |
👉Qt - Web混合开发👈 |
1、概述🌽
-
Qt版本:V5.12.5
-
注意:windows下
webenginewidgets
只支持MSVC编译器,不支持MinGW(mingw好像需要自己编译); -
当使用QWebEngineView实现Qt + html混合开发时经常遇见的问题就是Qt自身有信号槽,但是和web网页怎么通信,web里又没有信号槽,第一时间想到的是socket通信,但是Qt其实封装了更加简单便捷的通信方式,可使用
QtWebChannel
和qwebchannel.js
实现Qt和web通信;
QWebChannel支持的功能:
- 将JavaScript函数【绑定到Qt的信号】(类似Qt信号槽);
- 在JavaScript中异步调用
QWebChannel::registerObject()
注册的对象对象的【槽函数】(必须是public slots:
声明的);- 在JavaScript中调用
QWebChannel::registerObject()
注册的对象中带【返回值的槽函数】,并通过回调函数获取Qt槽函数的返回值;- 在JavaScript中指定读取/修改
QWebChannel::registerObject()
注册的对象中使用Q_PROPERTY定义的【属性值】;- 在JavaScript中指定读取
QWebChannel::registerObject()
注册的对象中使用Q_ENUM标记的【枚举】。前面讲了Qt使用
QWebChannel
实现与Web中的javascript通信的简单示例,但是如果需要传递复杂数据该怎么实现呢,总不能所有数据都用字符串吧;其实可以转换为JSON的数据类型QWebChannel都支持,而JSON支持下列6种数据类型,对应到Qt中可以使用5种类型,其它各种类型的数据,例如QByteArray,QImage、自定义结构体等数据类型都需要自己转换为JSON数据格式再通过QWebChannel传递;
JSON支持类型 Qt中对应的数据类型 逻辑值(true 或 false) bool 数字(整数或浮点数) int、int64、double等数字类型都可以 字符串(在双引号中) QString 数组(在中括号中) QJsonArray 对象(在大括号中) QJsonObject null
2、实现效果🍆
3、实现功能🍒
- 构建后将html、css、js文件自动拷贝到可执行程序路径下;
- web界面和qt界面实现双向通信;
- 由于QWebChannel传递数据只有可以转换为【JSON的数据类型】才可以传递,其它类型无法传递,例如QByteArray这些JSON不支持的数据类型,这里演示了可以传递的所有数据类型的使用方式;
- Web界面中javascript直接读取Qt中注册对象使用Q_PROPERTY定义的【属性值】;
- Web界面中javascript直接读取Qt中注册对象使用使用Q_ENUM标记的【枚举】;
- 定义一个带有返回值的槽函数,javascript调用该函数后可以获取【返回值】;
4、关键代码🥝
- pro文件:INSTALLS 用法
QT += webenginewidgets webchannel # 使用QWebEngineView和QWebchannel需要加载模块
# 程序编译后需要使用nmake install(msvc)或make install (linux)将web2文件夹拷贝到当前路径下,或者自己手动拷贝
webFile.path = $$path
webFile.files = $$PWD/web2
INSTALLS += webFile # 将web文件夹拷贝到path路径下,需要配置Custom Process Step: nmake install才生效
- webClient.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Web客户端</title>
<!-- qwebchannel.js文件一般在Qt安装路径下 D:\Qt\Qt5.12.5\Examples\Qt-5.12.5\webchannel\shared\qwebchannel.js-->
<script src="qwebchannel.js"></script>
<script src="main.js"></script>
<link rel="stylesheet" type="text/css" href="main.css">
</head>
<body>
<h1 align="center">Web客户端程序 </h1>
<div align="center">
<textarea id="textAreaId" name="textArea"></textarea> </br>
<button id="but_bool" class="button" onclick="butClick_bool()">bool类型</button>
<button id="but_double" class="button" onclick="butClick_double()">double类型</button>
<button id="but_str" class="button" onclick="butClick_str()">string类型</button>
<button id="but_arr" class="button" onclick="butClick_arr()">array类型</button>
<button id="but_obj" class="button" onclick="butClick_obj()">object类型</button> </br>
<button id="but_Property" class="button" onclick="butClick_Property()">读取并修改Qt对象中的属性</button>
<button id="but_enum" class="button" onclick="butClick_enum()">读取Q_ENUM标记的枚举</button>
<button id="but_return" class="button" onclick="butClick_return()">调用带返回值的Qt函数</button>
</div>
</body>
</html>
- main.js
/**
* 程序启动立即初始化
*/
window.onload = function()
{
if(typeof qt != "undefined")
{
window.channel = new QWebChannel(qt.webChannelTransport, function(channel)
{
// 获取Qt注册的对象,Qt中registerObject注册的字符串
window.core = channel.objects.CoreId;
// 将函数showText和Qt信号toWeb***()绑定
core.toWebBool.connect(function(msg)
{
showText(msg);
});
core.toWebDouble.connect(function(msg)
{
showText(msg);
});
core.toWebString.connect(function(msg)
{
showText(msg);
});
core.toWebJsonArray.connect(function(msg)
{
showText(msg);
});
core.toWebJsonObject.connect(function(msg)
{
showText(msg);
});
});
}
else
{
alert("qt对象未获取到!");
}
}
/**
* 显示Qt发给Web的信息
* @param {*} msg
*/
function showText(msg)
{
var textEdit = document.getElementById("textAreaId");
if(textEdit)
{
// 由于typeof 不能分辨出数组和对象,所以这里使用构造器来判断
if(msg.constructor === Array) // 数组类型
{
textEdit.value = textEdit.value + "Array:" + msg+ '\n'; // 追加信息
}
else if(msg.constructor === Object) // 对象类型
{
var str = msg.key1 + " " + msg.key2+ " " + msg.key3;
textEdit.value = textEdit.value + "Object:" + str+ '\n'; // 追加信息
}
else
{
textEdit.value = textEdit.value + typeof msg + ":" + msg+ '\n'; // 追加信息
}
textEdit.scrollTop = textEdit.scrollHeight; // 滚动条一直再最下方
}
}
/**
* html中按键点击时调用这个函数将信号发送给Qt
*/
function butClick_bool()
{
core.on_toQtBool(true);
}
function butClick_double()
{
core.on_toQtDouble(123.321);
}
function butClick_str()
{
core.on_toQtString("Web 按键点击");
}
function butClick_arr()
{
var arr = [1, 2, "123"];
core.on_toQtJsonArray(arr);
}
function butClick_obj()
{
var obj = {
key1 : 123,
key2 : 321.1,
key3 : "abc"
};
core.on_toQtJsonObject(obj);
}
/**
* 点击按键后直接读取Qt中注册对象Core中使用Q_PROPERTY定义的属性值并修改
*/
function butClick_Property()
{
var textEdit = document.getElementById("textAreaId");
if(textEdit)
{
textEdit.value = textEdit.value + "Qt对象属性:" + core.value + '\n'; // 读取Qt中使用Q_PROPERTY定义的属性值
textEdit.scrollTop = textEdit.scrollHeight; // 滚动条一直再最下方
core.value++; // 修改Qt中使用Q_PROPERTY定义的属性值
}
}
/**
* 直接访问Qt中使用Q_ENUM标记的枚举
*/
function butClick_enum()
{
var textEdit = document.getElementById("textAreaId");
if(textEdit)
{
textEdit.value = textEdit.value + "Qt枚举值:" + core.CoreEnum.Value1 + '\n';
textEdit.scrollTop = textEdit.scrollHeight; // 滚动条一直再最下方
}
}
/**
* 在javascript中调用Qt函数后【获取返回值】
*/
function butClick_return()
{
core.on_returnValue(123, function(returnValue) // 这里使用回调函数获取返回值
{
var textEdit = document.getElementById("textAreaId");
if(textEdit)
{
textEdit.value = textEdit.value + "Qt函数返回值:" + returnValue + '\n';
textEdit.scrollTop = textEdit.scrollHeight; // 滚动条一直再最下方
}
});
}
- widget.h:注意,这里的 Core 类是Qt和Js通信的关键;
#ifndef WIDGET_H
#define WIDGET_H
#include <QJsonArray>
#include <QJsonObject>
#include <QWidget>
QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE
class Widget : public QWidget
{
Q_OBJECT
public:
Widget(QWidget *parent = nullptr);
~Widget();
private:
void showText(QString str);
private slots:
void on_toQtBool(bool value) ;
void on_toQtDouble(double value) ;
void on_toQtString(QString value) ;
void on_toQtJsonArray(QJsonArray value) ;
void on_toQtJsonObject(QJsonObject value);
void on_but_bool_clicked();
void on_but_double_clicked();
void on_but_str_clicked();
void on_but_array_clicked();
void on_but_object_clicked();
private:
Ui::Widget *ui;
};
/**
* @brief Qt和Web端交互的中介单例类
*/
class Core : public QObject
{
Q_OBJECT
Q_PROPERTY(int value READ value WRITE setValue NOTIFY valueChanged) // 定义一个属性,javascript可以读取属性值
public:
enum CoreEnum
{
Value1 = 100,
Value2
};
Q_ENUM(CoreEnum) // 使用Q_ENUM标记的枚举,javascript可以直接访问
public:
static Core* getInstance()
{
static Core core;
return &core;
}
int value() {return m_value;}
void setValue(int v) {m_value = v;}
signals:
void valueChanged();
/**
* @brief Qt发送给Web的信号
* @param str
*/
void toWebBool(bool value);
void toWebDouble(double value);
void toWebString(QString value);
void toWebJsonArray(QJsonArray value);
void toWebJsonObject(QJsonObject value);
/**
* @brief Web发送给Qt的信号
* @param str
*/
void toQtBool(bool value);
void toQtDouble(double value);
void toQtString(QString value);
void toQtJsonArray(QJsonArray value);
void toQtJsonObject(QJsonObject value);
public slots:
/**
* @brief Web端需要调用Qt槽函数来传递,必须声明为public slots,否则web找不到
* @param str
*/
void on_toQtBool(bool value) {emit toQtBool(value);}
void on_toQtDouble(double value) {emit toQtDouble(value);}
void on_toQtString(QString value) {emit toQtString(value);}
void on_toQtJsonArray(QJsonArray value) {emit toQtJsonArray(value);}
void on_toQtJsonObject(QJsonObject value) {emit toQtJsonObject(value);}
/**
* @brief 定义一个带有返回值的槽函数,javascript调用该函数后可以获取返回值
* @param value
* @return
*/
QString on_returnValue(int value);
private:
int m_value = 10;
};
#endif // WIDGET_H
- widget.cpp
#include "widget.h"
#include "ui_widget.h"
#include <QJsonDocument>
#include <QTime>
#include <qdir.h>
#include <qwebchannel.h>
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
this->setWindowTitle(QString("使用QtWebChannel实现Qt与Web通信交互(2),进阶功能 - V%1").arg(APP_VERSION)); // 设置窗口标题
QWebChannel* channel = new QWebChannel(this);
channel->registerObject("CoreId", Core::getInstance()); // 向QWebChannel注册用于Qt和Web交互的对象。
ui->webEngineView->page()->setWebChannel(channel); // 将与webEngineView要使用的web通道实例设置为channel
ui->webEngineView->setUrl(QDir("./web2/webClient.html").absolutePath());
// 绑定槽函数,接收web界面中javascript传递过来的信号
connect(Core::getInstance(), &Core::toQtBool, this, &Widget::on_toQtBool);
connect(Core::getInstance(), &Core::toQtDouble, this, &Widget::on_toQtDouble);
connect(Core::getInstance(), &Core::toQtString, this, &Widget::on_toQtString);
connect(Core::getInstance(), &Core::toQtJsonArray, this, &Widget::on_toQtJsonArray);
connect(Core::getInstance(), &Core::toQtJsonObject, this, &Widget::on_toQtJsonObject);
}
Widget::~Widget()
{
delete ui;
}
/**
* @brief 显示发送的数据
* @param str
*/
void Widget::showText(QString str)
{
ui->textEdit->append(QString("发送:%1").arg(str));
}
/**
* @brief 显示Web发送给Qt的数据
* @param value
*/
void Widget::on_toQtBool(bool value)
{
ui->textEdit->append(QString("Bool类型数据:%1").arg(value ? "true" : "false"));
}
void Widget::on_toQtDouble(double value)
{
ui->textEdit->append(QString("double类型数据:%1").arg(value));
}
void Widget::on_toQtString(QString value)
{
ui->textEdit->append(QString("QString类型数据:%1").arg(value));
}
void Widget::on_toQtJsonArray(QJsonArray value)
{
QJsonDocument doc;
doc.setArray(value);
ui->textEdit->append(QString("QJsonArray类型数据:%1").arg(doc.toJson().data()));
}
void Widget::on_toQtJsonObject(QJsonObject value)
{
QJsonDocument doc;
doc.setObject(value);
ui->textEdit->append(QString("QJsonArray类型数据:%1").arg(doc.toJson().data()));
}
/**
* @brief 发送Bool类型数据
*/
void Widget::on_but_bool_clicked()
{
static bool value = true;
value = !value;
emit Core::getInstance()->toWebBool(value);
showText(QString("%1").arg(value ? "true" : "false"));
}
/**
* @brief 发送double类型数据
*/
void Widget::on_but_double_clicked()
{
double value = QTime::currentTime().msec() / 50.0;
emit Core::getInstance()->toWebDouble(value);
showText(QString("%1").arg(value));
}
/**
* @brief 发送字符串类型数据
*/
void Widget::on_but_str_clicked()
{
double value = QTime::currentTime().msec() / 50.0;
emit Core::getInstance()->toWebString(QString("%1").arg(value));
showText(QString("%1").arg(value));
}
/**
* @brief 发送Json数组类型数据
*/
void Widget::on_but_array_clicked()
{
double value = QTime::currentTime().msec() / 50.0;
QJsonArray array = {value, value / 10.0, QString("%1").arg(value / 20.0)};
emit Core::getInstance()->toWebJsonArray(array);
QJsonDocument doc;
doc.setArray(array);
showText(QString("%1").arg(doc.toJson().data()));
}
/**
* @brief 发送json对象类型数据
*/
void Widget::on_but_object_clicked()
{
double value = QTime::currentTime().msec() / 50.0;
QJsonObject obj;
obj.insert("key1", value);
obj.insert("key2", value / 30.0);
obj.insert("key3", QString("%1").arg(value / 40.0));
emit Core::getInstance()->toWebJsonObject(obj);
QJsonDocument doc;
doc.setObject(obj);
showText(QString("%1").arg(doc.toJson().data()));
}
/**
* @brief 带返回值的槽函数,将返回值传递给javascript
* @param value
* @return
*/
QString Core::on_returnValue(int value)
{
qDebug() << "调用Qt槽函数,并返回值";
return QString("调用成功:%1").arg(value);
}
5、源代码🥔
🌙`、、`ヽ`ヽ`、、ヽヽ、`、ヽ`ヽ`ヽヽ`
ヽ`、`ヽ`、ヽ``、ヽ`ヽ`、ヽヽ`ヽ、ヽ
`ヽ、ヽヽ`ヽ`、``ヽ`ヽ、ヽ、ヽ`ヽ`ヽ
、ヽ`ヽ`、ヽヽ``、ヽ`、ヽヽ 🚶♀ ヽ``ヽ`