|  | 
 
| 文章目录 1. QWebChannel
 2. 使用QWebEngine的示例
 2.1 C++端代码
 2.1.1 mainwindow.cpp
 2.1.2 mytestclass.h
 2.1.3 mytestclass.cpp
 2.2 Web端
 2.3 运行
 3. 使用WebSocket的示例
 3.1 C++端代码
 3.1.1 mainwindow.cpp
 3.2 Web端代码
 3.3 运行
 3.4 问题
 4. 代码
 1. QWebChannel
 QWebChannel类的作用是向远端HTML客户端暴露 QObject。
 
 QWebChannel填补了C++应用程序和HTML/JavaScript 应用程序之间的空白。通过将QObject派生对象发布到QWebChannel并在HTML中引入qwebchannel.js脚本可从此处获取。在HTML端,可以透明地访问QObject的属性、公共槽和方法。不需要手动消息传递和数据序列化,C++方面的属性更新和信号发射将自动传输到可能远程运行的HTML客户机。在客户端,将为任何发布的C++ QObject创建JavaScript对象。它反映了C++对象的API,因此可以直观地使用。
 
 但是,Web端与C++之间怎么进行通信能? 有两个方法:
 
 QWebEngine 提供一个 web 引擎,用于在 Qt 应用中嵌入任意的网页内容。Qt WebEngine 是基于 Chromium 项目实现的,提供了一个 js 的宿主环境,内部实现了js调用C++的环境;
 Websocket C++端建立websocket server,Web端连接,qwebchannel.js会获取到C++端所有的属性、槽函数等。
 2. 使用QWebEngine的示例
 2.1 C++端代码
 2.1.1 mainwindow.cpp
 // 要导出的类,此类供js调用
 m_myTestClass = new MyTestClass(this);
 
 // 创建QWebChannel,把创建的类注册到QWebChannel中,js才能调用此类的方法
 m_webChannel = new QWebChannel(this);
 m_webChannel->registerObject("mytestclass", m_myTestClass);
 
 // js与C++通信方式一、使用QWebEngineView加载网页,web端js与C++之间的通信
 QString strHtml = QApplication::applicationDirPath() + "/../../testWeb/test.html";
 // QWebEngineView 基于 Chromium 的 web 引擎
 m_webEngineView = new QWebEngineView(this);
 m_webEngineView->load(QUrl::fromLocalFile(strHtml));
 m_webEngineView->page()->setWebChannel(m_webChannel);
 ui->verticalLayout->addWidget(m_webEngineView);
 1
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 导出类 MyTestClass,供js调用
 
 2.1.2 mytestclass.h
 #ifndef MYTESTCLASS_H
 #define MYTESTCLASS_H
 
 #include <QObject>
 #include <QThread>
 
 class MyTestClass : public QObject
 {
 Q_OBJECT
 
 // 导出的属性
 Q_PROPERTY(QString navStatus MEMBER m_navStatus NOTIFY navStatusChanged)
 
 public:
 explicit MyTestClass(QObject *parent = nullptr);
 
 signals:
 // 导出的事件
 void navStatusChanged(const QString& navStatus);
 
 public slots:
 // 导出的槽函数
 void function1(const QString& str);
 
 
 private:
 void setNavStatus(const QString& status);
 
 QString m_navStatus;
 
 };
 
 #endif // MYTESTCLASS_H
 
 1
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 2.1.3 mytestclass.cpp
 #include "mytestclass.h"
 
 #include <QMessageBox>
 #include <QVariant>
 #include <QDebug>
 
 MyTestClass::MyTestClass(QObject *parent) : QObject(parent),
 m_navStatus("hello")
 {
 }
 
 void MyTestClass::function1(const QString& str)
 {
 setNavStatus(str);
 qDebug() << __FUNCTION__ << str;
 }
 
 void MyTestClass::setNavStatus(const QString &status)
 {
 m_navStatus = status;
 emit navStatusChanged(m_navStatus);
 }
 
 1
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 2.2 Web端
 <!DOCTYPE html>
 <html lang="en">
 <head>
 <meta charset="UTF-8">
 <meta http-equiv="X-UA-Compatible" content="IE=edge">
 <meta name="viewport" content="width=device-width, initial-scale=1.0">
 <title>Document</title>
 </head>
 <body>
 <button id="callcpp">callcpp</button>
 <button>getValue</button>
 
 <script src="qwebchannel.js"></script>
 
 <script type="text/javascript">
 var webObj;
 
 // 创建Webchannel,与C++端建立连接
 new QWebChannel(qt.webChannelTransport, function (channel) {
 
 // 获取类的对象
 webObj = channel.objects.mytestclass;
 
 // 类的事件
 webObj.navStatusChanged.connect(function(arg){
 alert("navStatusChanged: " + arg);
 });
 });
 
 function callcpp(){
 
 // 类的方法
 webObj.function1('this is a test');
 }
 
 function getValue(){
 
 // 类的属性值
 var status = webObj.navStatus;
 
 alert(status);
 }
 
 
 </script>
 </body>
 </html>
 1
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 其中,qwebchannel.js 取自 Qt安装目录的 Qt5.12.0\Examples\Qt-5.12.0\webchannel\shared 目录。
 
 2.3 运行
 
 QT UI加载了html页面,显示了其中的元素。
 
 (1)Web端的getValue获取C++对象的属性navStatus,属性初始值为 “hello”
 
 (2)Web端的 callcpp 调用 C++端的函数 function1,C++端function1函数中打出
 
 (3)Web端响应 navStatusChanged 事件
 
 
 
 3. 使用WebSocket的示例
 3.1 C++端代码
 3.1.1 mainwindow.cpp
 #include "mainwindow.h"
 #include "ui_mainwindow.h"
 
 MainWindow::MainWindow(QWidget *parent) :
 QMainWindow(parent),
 ui(new Ui::MainWindow)
 {
 ui->setupUi(this);
 
 // 要导出的类,此类供js调用
 m_myTestClass = new MyTestClass(this);
 
 // 创建QWebChannel,把创建的类注册到QWebChannel中,js才能调用此类的方法
 m_webChannel = new QWebChannel(this);
 m_webChannel->registerObject("mytestclass", m_myTestClass);
 
 // js与C++通信方式二、创建QWebsocketServer,web端与之建立连接
 startServer();
 
 }
 
 MainWindow::~MainWindow()
 {
 delete ui;
 }
 
 // 建立WebSocket服务
 void MainWindow::startServer()
 {
 m_websocketServer = new QWebSocketServer("testWebchannel", QWebSocketServer::NonSecureMode, this);
 
 if(!m_websocketServer->listen(QHostAddress::Any, 12345))
 {
 qDebug() << "websocket server listen failed, error: " << m_websocketServer->errorString();
 return;
 }
 
 connect(m_websocketServer, &QWebSocketServer::newConnection, this, &MainWindow:
  nNewConnection); qDebug() << "startServer";
 }
 
 void MainWindow:
  nNewConnection() {
 QWebSocket* client = m_websocketServer->nextPendingConnection();
 qDebug() << (QString("Homay robot server has new connection from %1.%2").arg(client->peerAddress().toString()).arg(client->localPort()));
 
 auto pTransport = new WebSocketTransport(client);
 // 可以不需要,这里只是为了调试打印js端的qwebchannel.js是怎么和C++端通信的,通信协议是什么样的
 connect(pTransport, &WebSocketTransport::messageReceived, this, &MainWindow:
  nTransportMessageReceived); 
 m_webChannel->connectTo(pTransport);
 }
 
 void MainWindow:
  nTransportMessageReceived(const QJsonObject &message, QWebChannelAbstractTransport *transport) {
 qDebug() << "onTransportMessageReceived: " << message;
 }
 
 1
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 导出类 MyTestClass,供js调用。
 代码中 WebSocketTransport 类代码,取自 Qt安装目录的 Qt5.12.0\Examples\Qt-5.12.0\webchannel\shared 目录下的 websockettransport.h websockettransport.cpp。
 此处省略。
 
 3.2 Web端代码
 <!DOCTYPE html>
 <html lang="en">
 <head>
 <meta charset="UTF-8">
 <meta http-equiv="X-UA-Compatible" content="IE=edge">
 <meta name="viewport" content="width=device-width, initial-scale=1.0">
 <title>Document</title>
 </head>
 <body>
 <button id="callcpp">callcpp</button>
 <button>getValue</button>
 
 <script src="qwebchannel.js"></script>
 
 <script type="text/javascript">
 var webObj;
 
 // 连接c++端的 Websocket
 var socket = new WebSocket('ws://127.0.0.1:12345');
 
 // 连接成功后
 socket.onopen = function(){
 alert("onopen");
 
 // 创建Webchannel
 new QWebChannel(socket, function (channel) {
 
 // 获取类的对象
 webObj = channel.objects.mytestclass;
 
 // 类的事件
 webObj.navStatusChanged.connect(function(arg){
 alert("navStatusChanged: " + arg);
 });
 });
 }
 
 function callcpp(){
 // 类的方法
 webObj.function1('this is a test');
 }
 
 function getValue(){
 // 类的属性值
 var status = webObj.navStatus;
 
 alert(status);
 }
 
 
 
 </script>
 </body>
 </html>
 1
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 
 
 与2.2中的Web端代码相比,此时,需要先创建WebSocket连接,把socket传入QWebChannel中。
 
 3.3 运行
 (1)运行C++, C++代码没有加载html, 此时为空界面;
 (2)使用Chrome浏览器,或者Edge浏览器打开Web测试网页,一打开就与C++端的websocket连接上了
 
 (3)接下来与2.3的演示一样。
 
 3.4 问题
 我这里端口用的12345,可能在有些电脑上此端口被占用了,会报错:
 
 
 
 改一下端口号就好了, 比如我改成:
 
 
 
 4. 代码
 所有代码详见:QWebChannel
 ————————————————
 版权声明:本文为CSDN博主「J_Xio」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
 原文链接:https://blog.csdn.net/Jay_Xio/article/details/122662697
 
 
 | 
 |