Qt-Web混合开发-QWebSocket作为QWebChannel通信数据传输接口(10)

news2025/1/15 6:53:46

Qt-Web混合开发-QWebSocket作为QWebChannel通信数据传输接口💙🍓

文章目录

  • Qt-Web混合开发-QWebSocket作为QWebChannel通信数据传输接口💙🍓
    • 1、概述🐛🦆
    • 2、实现效果😅🙏
    • 3、实现功能🐮🐴
    • 4、Qt部分关键代码💳🛣️🍐
    • 5、Web部分关键代码👊👎😷🦠
    • 6、源代码🐍🉐

更多精彩内容
👉个人内容分类汇总 👈
👉Qt - Web混合开发👈

1、概述🐛🦆

  • Qt版本:V5.12.5
  • 关于WebSocket API可以看
  • QWebChannel基本使用
  1. QWebChannel默认使用的传输通道为WebChannelIPCTransportHost,内部的数据传输接口为qtwebchannel::mojom::WebChannelTransportRenderAssociatedPtr;
  2. WebChannelIPCTransportHost所在文件:D:\Qt\Qt5.12.5\5.12.5\Src\qtwebengine\src\core\renderer_host\web_channel_ipc_transport_host.h;
  3. QWebChannel默认情况下使用需要将QwebChannel传入QWebEnginePage::setWebChannel(),只支持Qt与嵌入Qt的Web界面进行通信,如果该web界面是使用浏览器打开的则无法找到qt.webChannelTransport对象;
  4. 为了解决这种问题,Qt也有考虑到,只需要继承QWebChannelAbstractTransport,使用QWebSocket作为数据传输接口,就可以实现Qt界面与嵌入Qt的web界面、浏览器打开的web界面进行通信了;
  5. 并且使用QWebSocket作为数据传输接口可以不需要使用QWebEnginePage::setWebChannel()设置。

2、实现效果😅🙏

在这里插入图片描述

3、实现功能🐮🐴

  1. 构建后将html、css、js文件自动拷贝到可执行程序A路径下;
  2. 使用QWebSocket作为QWebChannel通信接口;
  3. 通过QWebEngineView在Qt界面中嵌入Web网页;
  4. 一键调用浏览器打开html文件;
  5. 基于WebSocket、QWebChannel.js实现网页和Qt通信功能;
  6. 同时演示了Qt和嵌入网页界面、浏览器网页界面通信功能;
  7. 支持一个服务端与多个客户端Web界面进行通信交互,将WebSocket服务端封装在QWebChannel内部,一个WebChannel对应一个服务端、多个客户端。

4、Qt部分关键代码💳🛣️🍐

  • 工程文件结构

在这里插入图片描述

  • pro文件
QT += webchannel websockets webenginewidgets
  • widget.h
#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include "swebchannel.h"

QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE

class Widget : public QWidget
{
    Q_OBJECT

public:
    Widget(QWidget *parent = nullptr);
    ~Widget();

private slots:
    void on_but_send_clicked();
    void on_webButClicked(QString message);

    void on_but_openWeb_clicked();

private:
    Ui::Widget *ui;
    SWebChannel m_channel;
};

/**
 * @brief  Qt和Web端交互的中介单例类
 */
class Core : public QObject
{
    Q_OBJECT
public:
    static Core* getInstance()
    {
        static Core core;
        return &core;
    }

signals:
    /**
     * @brief     Qt发送给Web的信号
     * @param str
     */
    void qtButClicked(QString str);

    /**
     * @brief     Web发送给Qt的信号
     * @param str
     */
    void webButClicked(QString str);

public slots:
    /**
     * @brief     Web端需要调用Qt槽函数来传递,必须声明为public slots,否则web找不到
     * @param str
     */
    void on_webButClicked(QString str)
    {
        emit webButClicked(str);
    }
};

#endif // WIDGET_H

  • widget.cpp
#include "widget.h"
#include "ui_widget.h"
#include <QDesktopServices>
#include <qdir.h>
#include <qurl.h>

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
    this->setWindowTitle(QString("使用QWebSocket客户端作为QWebChannel通信数据传输接口 - V%1").arg(APP_VERSION));  // 设置窗口标题

    connect(Core::getInstance(), &Core::webButClicked, this, &Widget::on_webButClicked);

    m_channel.registerObject("CoreId", Core::getInstance());   // 向QWebChannel注册用于Qt和Web交互的对象。
    m_channel.listen(QHostAddress::AnyIPv4, 1234);             // 设置WebSocket服务端开始监听

//    ui->webEngineView->page()->setWebChannel(&m_channel);       // 将与webEngineView要使用的web通道实例设置为channel(使用QWebSocket作为数据传输接口可以不需要这一步)
    ui->webEngineView->setUrl(QDir("./web3/channelClient.html").absolutePath());
}

Widget::~Widget()
{
    delete ui;
}

/**
 * 发送数据
 */
void Widget::on_but_send_clicked()
{
    QString str = ui->lineEdit->text().trimmed();
    if(str.isEmpty()) return;
    emit Core::getInstance()->qtButClicked(str);
}

/**
 * @brief         显示接收到的web端信息
 * @param message
 */
void Widget::on_webButClicked(QString message)
{
    ui->textEdit->append(message);
}

/**
 * @brief 点击一次打开一个Web程序
 */
void Widget::on_but_openWeb_clicked()
{
    QDesktopServices::openUrl(QDir("./web3/channelClient.html").absolutePath());
}

  • swebchannel.h
/******************************************************************************
 * @文件名     swebchannel.h
 * @功能       通过继承QWebChannel,将创建管理WebSocket服务端功能,使用connectTo设置通信接口功能
 *            封装在类内部,简化外部操作连接,一个SWebChannel对应一个WebSocket服务端、多个客户端
 *
 * @开发者     mhf
 * @邮箱       1603291350@qq.com
 * @时间       2022/12/19
 * @备注
 *****************************************************************************/
#ifndef SWEBCHANNEL_H
#define SWEBCHANNEL_H

#include <QWebChannel>
#include "websockettransport.h"

class SWebChannel : public QWebChannel
{
    Q_OBJECT
public:
    explicit SWebChannel(QObject *parent = nullptr);


    bool listen(const QHostAddress &address = QHostAddress::Any, quint16 port = 0);

signals:

private slots:

private:
    WebSocketServer m_server;
    QHostAddress    m_address;
    quint16         m_port;
};

#endif // SWEBCHANNEL_H

  • swebchannel.cpp
#include "swebchannel.h"

SWebChannel::SWebChannel(QObject *parent) : QWebChannel(parent)
{
    // 将连接成功的通道传递给QWebChannel
    connect(&m_server, &WebSocketServer::newWebSocketTransport, this, &SWebChannel::connectTo);
}

/**
 * @brief          设置WebSocket服务端监听
 * @param address  监听的地址
 * @param port     监听的端口号
 * @return
 */
bool SWebChannel::listen(const QHostAddress &address, quint16 port)
{
    // 如果新设置的监听地址、端口和已经监听的相同,则直接返回
    if(m_address == address && m_port == port && m_server.isListening())
    {
        return true;
    }
    m_address = address;
    m_port = port;
    if(m_server.isListening())   // 如果已经在监听了则关闭已有监听,重新监听新的地址、端口
    {
        m_server.close();
    }

    return m_server.listen(address, port);
}

  • websockettransport.h
#ifndef WEBSOCKETTRANSPORT_H
#define WEBSOCKETTRANSPORT_H

#include <QWebChannelAbstractTransport>
#include <qwebsocketserver.h>

class QWebSocket;

/**
 * 通过继承QWebChannelAbstractTransport实现QWebChannel交互功能
 * 使用QWebSocket作为通信接口
 */
class WebSocketTransport : public QWebChannelAbstractTransport
{
    Q_OBJECT
public:
    explicit WebSocketTransport(QWebSocket *client = nullptr);
    ~WebSocketTransport() override;

public slots:
    void sendMessage(const QJsonObject &message) override;
    void on_textMessageReceived(const QString &message);

private:
    QWebSocket* m_client = nullptr;
};

/**
 * WebSocket服务端程序,用于监听webSocket客户端连接,将连接的客户端使用
 * WebSocketTransport包装后传递出去
 */
class WebSocketServer : public QWebSocketServer
{
    Q_OBJECT
public:
    explicit WebSocketServer(QObject *parent = nullptr);

signals:
    void newWebSocketTransport(WebSocketTransport* transport);

private slots:
    void on_newConnection();
};

#endif // WEBSOCKETTRANSPORT_H

  • websockettransport.cpp
#include "websockettransport.h"

#include <qjsondocument.h>
#include <qwebsocket.h>
#include <QJsonObject>

WebSocketTransport::WebSocketTransport(QWebSocket *client)
    : QWebChannelAbstractTransport(client)
    , m_client(client)
{
    // 当WebSocket收到信息后,将信息处理后并传递给QWebChannelAbstractTransport
    connect(m_client, &QWebSocket::textMessageReceived, this, &WebSocketTransport::on_textMessageReceived);
    // 当WebSocket断开连接后,释放当前对象
    connect(m_client, &QWebSocket::disconnected, this, &WebSocketTransport::deleteLater);
    connect(m_client, &QWebSocket::disconnected, [=]()
    {
        qDebug() << "Web端断开连接!";
    });
}

WebSocketTransport::~WebSocketTransport()
{
    if(m_client)
    {
        m_client->deleteLater();
    }
}

/**
 * @brief           QWebChannelAbstractTransport中定义的接口,当使用QChannel发送信息时,数据传递到这里
 *                  在这个函数中处理需要发送的数据,并通过WebSocket发送出去
 * @param message
 */
void WebSocketTransport::sendMessage(const QJsonObject &message)
{
    QJsonDocument doc(message);
    m_client->sendTextMessage(QString::fromUtf8(doc.toJson(QJsonDocument::Compact)));  // 将需要发送的JSON数据转成字符串发送
}

/**
 * @brief          通过WebSocket接收到网页javascript发来的信息时,
 *                 在这个函数中将字符串数据转换为JSON数据传递给QWebChannel
 * @param message
 */
void WebSocketTransport::on_textMessageReceived(const QString &message)
{
    QJsonParseError error;
    QJsonDocument doc = QJsonDocument::fromJson(message.toUtf8(), &error);
    if(error.error)  // 字符串转JSON成功,error为0,失败则error > 0
    {
        qWarning() << QString("%1 无法将文本消息解析为JSON对象:%2").arg(error.errorString()).arg(message);
        return;
    }
    if(!doc.isObject())
    {
        qWarning() << QString("收到的JSON消息不是JSON对象:%1").arg(QString(doc.toJson()));
    }

    emit messageReceived(doc.object(), this);    // 将收到的信息发送给QWebChannel
}



WebSocketServer::WebSocketServer(QObject *parent)
    : QWebSocketServer("QChannel通信接口服务", NonSecureMode, parent)
{
    connect(this, &QWebSocketServer::newConnection, this, &WebSocketServer::on_newConnection);
}

/**
 * @brief 当有新的客户端连接时,将连接的客户端通过WebSocketTransport类包装后传递出去
 */
void WebSocketServer::on_newConnection()
{
    qDebug() << "有新的连接";
    emit newWebSocketTransport(new WebSocketTransport(this->nextPendingConnection()));
}

5、Web部分关键代码👊👎😷🦠

  • channelClient.html
<!DOCTYPE html>
<html lang="zh">
<head>
    <meta charset="UTF-8">
    <title>QWebSocket客户端作为QWebChannel通信数据传输接口</title>
    <script src="./qwebchannel.js"></script>
    <script src="./channelClient.js"></script>
    <link rel="stylesheet" type="text/css" href="channelClient.css">
</head>
<body>
    <div>
        <h1>使用QWebSocket客户端作为<br/>QWebChannel通信数据传输接口</h1>
        <p>
            <textarea name="textShow" id="textShowId" cols="60" rows="10"></textarea>
        </p>
        <p>
            <input id="input"/> <button id="but_send" onclick="sendMessage()">发送</button>
        </p>
    </div>
</body>
</html>

  • channelClient.js
// 关于WebSocket的用法可以看【https://developer.mozilla.org/zh-CN/docs/Web/API/WebSocket】

/**
 * 创建一个程序加载时自动执行的函数
 * 注意:由于该函数执行时WebSocket会连接Qt中的WebSocket服务端,WebChannel会获取Qt中注册的对象
 *      所以需要先启动Qt程序,再启动当前web程序,否则无法连接(也可以写成手动调用)
 */
window.onload = function() 
{
    var url = "ws://localhost:1234";          // WebSocket服务端地址
    var client = new WebSocket(url);          

    /**
     * 连接关闭后的回调函数
     */
    client.onclose = function() 
    {
        showMessage("关闭连接");
    }

    /**
     * 连接失败后的回调函数。
     */
    client.onerror = function(err)
    {
        showMessage("连接失败:" + err.data);
    }

    /**
     * 连接成功后的回调函数
     */
    client.onopen = function()
    {
        showMessage("WebSocket连接成功");
        // 将创建的websocket客户端传递给QWebChannel,并绑定通信接口
        // 注意:这里默认情况传入的是qt.webChannelTransport,但是这里使用的是WebSocket通信,所以需要传入client
        window.channel = new QWebChannel(client, function(channel)  
        {
            // 获取Qt注册的对象,Qt中registerObject注册的字符串
            window.core = channel.objects.CoreId;  
            
            // 将Qt注册对象的qtButClicked信号绑定到readMessage函数
            core.qtButClicked.connect(readMessage);
            showMessage("初始化WebChannel完成");
        });
    }
}

/**
 * 显示接收到的信息
 */
function readMessage(message)
{
    showMessage("收到:" + message);
}

/**
 * 点击按键调用Qt注册对象中on_webButClicked槽函数将数据发送给Qt
 */
function sendMessage()
{
    var text = document.getElementById("input").value;
    if(!text)
    {
        return;
    }
    window.core.on_webButClicked(text);
}

/**
 * 将信息显示到文本框
 */
function showMessage(msg)
{
    var textShow = document.getElementById("textShowId");
    textShow.value += msg + "\n";              // 追加信息
    textShow.scrollTop = textShow.scrollHeight;    // 滚动条显示最下方
}

6、源代码🐍🉐

  • gitee
  • github

. ஓ๑⸜💗⸝‍๑ஓ
 ᕬ ᕬ   ∧ ∧
(˵ㅇ◡ㅇ˵) (ᓀ ֊ ᓂ˵ )
(つ☕O O🍵⊂)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/101169.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

m通过matlab实现遥测信道主要影响因素分析

目录 1.算法描述 2.仿真效果预览 3.MATLAB核心程序 4.完整MATLAB 1.算法描述 遥测技术是指被测对象的状态参数进行超远距离测量&#xff0c;并将测量的数据通过特殊的通信方式发送给地面接收站的一种技术。整个遥测发送接收系统称为遥测系统&#xff0c;而发送遥测信号所通…

LaTeX教程(一)——LaTeX介绍以及导言详解

文章目录1. Latex 介绍2. LaTeX基础2.1 导言区2.2 正文区3. 导言详解3.1 设置时间、作者、日期3.2 全局设置4. 文件组织1. Latex 介绍 什么是LATEX &#xff1f;LATEX 是一种格式。为免误会&#xff0c;初次接触这一概念的读者可以粗略地将 LATEX 理解成是对 TEX 的一层封装。…

【DELM回归预测】基于matlab松鼠算法改进深度学习极限学习机SSA-DELM数据回归预测【含Matlab源码 1904期】

⛄一、PSO-DELM简介 1 DELM的原理 在2004年&#xff0c;极限学习机&#xff08;extreme learning machine,ELM&#xff09;理论被南洋理工大学的黄广斌教授提出&#xff0c;ELM是一种单隐含层前馈神经网络&#xff08;single-hidden layer feedforward neural network,SLFN&am…

开发社交聊天APP需要注意什么?如何快速开发聊天功能

随着互联网的发展&#xff0c;人们的沟通方式也在悄悄发生变化&#xff0c;由原来的面对面沟通&#xff0c;发展为网上沟通。让大家日常生活的通讯越来越方便了&#xff0c;各种APP层出不穷。那么&#xff0c;想开发一款社交聊天并进行运营&#xff0c;需要注意哪些方面&#x…

【推荐】产品经理需求模板,案例等文档合集15篇

产品经理的职责描述仍然分歧很多&#xff0c;因人、因公司而异。即使是在相对较为一致的高科技行业&#xff0c;不同公司中的职位描述也是很不同的。但通常认为产品经理的职责主要包括&#xff1a;产品经理负责调查并根据用户的需求,确定开发何种产品, 选择何种技术、商业模式等…

【Python机器学习】过拟合及其抑制方法讲解及实战(图文解释 附源码)

需要源码请点赞关注收藏后评论区留言私信~~~ 欠拟合、过拟合与泛化能力 欠拟合 最简单的线性模型&#xff0c;它是用一条直线来逼近各个样本点&#xff0c;显然力不从心&#xff0c;这种现象称为欠拟合。欠拟合模型是由于模型复杂度不够&#xff0c;训练样本集容量不够&#…

哈希表题目:环形链表

文章目录题目标题和出处难度题目描述要求示例数据范围进阶解法一思路和算法代码复杂度分析解法二思路和算法代码复杂度分析题目 标题和出处 标题&#xff1a;环形链表 出处&#xff1a;141. 环形链表 难度 2 级 题目描述 要求 给你一个链表的头结点 head\texttt{head}h…

网易云VIP音乐NCM文件转MP3,C语言版本

前言网易云的Vip音乐下载下来,格式不是mp3/flac这种通用的音乐格式&#xff0c;而是经过加密的ncm文件。只有用网易云的音乐App才能够打开。于是想到可不可以把.ncm文件转换成mp3或者flac文件&#xff0c;上google查了一下&#xff0c;发现有不少人已经做了这件事&#xff0c;但…

go : 无法将“go”项识别为 cmdlet、函数、脚本文件或可运行程序的名称

先安装go环境 https://blog.csdn.net/csl12919/article/details/128372584?csdn_share_tail%7B%22type%22%3A%22blog%22%2C%22rType%22%3A%22article%22%2C%22rId%22%3A%22128372584%22%2C%22source%22%3A%22csl12919%22%7Dhttps://blog.csdn.net/csl12919/article/details/1…

C案例:最小覆盖圆问题

文章目录一、提出任务 - 最小覆盖圆&#xff08;一&#xff09;描述&#xff08;二&#xff09;输入&#xff08;三&#xff09;输出&#xff08;四&#xff09;样例输入输出二、完成任务&#xff08;一&#xff09;编程思路&#xff08;二&#xff09;编写代码&#xff0c;实现…

魔百和M401A刷入Armbian系统EMMC

魔百和M401A刷入Armbian系统 准备工具 1. 电视盒子、U盘、键盘、显示器、HDMI线 2. armbian系统镜像包&#xff1a; Armbian_23.02.0_amlogic_s905l3a_bullseye_5.15.82_server_2022.12.12.img.gz 3. U盘写入工具&#xff1a; refus/usbWriter/balenaEtcher文件链接&#xff…

阻塞队列的使用

&#x1f388;专栏链接:多线程相关知识详解 目录 一.阻塞队列的介绍 二.使用阻塞队列/生产者消费者模型的好处 1.使用阻塞队列,有利于代码"解耦合" 2.削峰填谷 三.阻塞队列的使用 四.模拟实现阻塞队列 一.阻塞队列的介绍 1.线程是安全的 2.当进行入队操作的时候…

[附源码]计算机毕业设计Node.js吃天下美食网站(程序+LW)

项目运行 环境配置&#xff1a; Node.js最新版 Vscode Mysql5.7 HBuilderXNavicat11Vue。 项目技术&#xff1a; Express框架 Node.js Vue 等等组成&#xff0c;B/S模式 Vscode管理前后端分离等等。 环境需要 1.运行环境&#xff1a;最好是Nodejs最新版&#xff0c;我…

【AI with ML】第 12 章 :TensorFlow Lite 简介

&#x1f50e;大家好&#xff0c;我是Sonhhxg_柒&#xff0c;希望你看完之后&#xff0c;能对你有所帮助&#xff0c;不足请指正&#xff01;共同学习交流&#x1f50e; &#x1f4dd;个人主页&#xff0d;Sonhhxg_柒的博客_CSDN博客 &#x1f4c3; &#x1f381;欢迎各位→点赞…

css浮动

浮动的顺序贴靠特性 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>浮动</title><style>.box{width: 250px;height: 100px;border: 1px solid #000;}.box .c1{width: 150px;height: 100p…

云上在野容器攻防战:“杀”不掉的挖矿木马

编者按 数字化浪潮蓬勃兴起&#xff0c;企业面临的安全挑战亦日益严峻。 腾讯安全近期将复盘2022年典型的攻击事件&#xff0c;帮助企业深入了解攻击手法和应对措施&#xff0c;完善自身安全防御体系。 本篇是第二期&#xff0c;讲述了国内某高端制造厂商遭遇云上在野容器攻…

将scss文件转换成css文件

大家平时做项目肯定都习惯了使用scss或者less去写样式&#xff0c;如果是使用工程化的项目我们可以借助插件很方便的将scss或者less转换成css。那如果我们没有使用工程化&#xff0c;比如简单的demo或者官网等项目又希望可以通过scss去编写文件应该怎么办呢&#xff0c;我们可以…

200 万年薪能拿多久?因 ChatGPT 爆红的「提示工程师」竟面临光速失业

【简介】ChatGPT大火后&#xff0c;“提示工程师”开始流行。然而&#xff0c;他们很可能被光速下岗&#xff1f; 最近爆发的ChatGPT真的让人上瘾。 但是&#xff0c;你只是在玩游戏&#xff0c;有些人已经在上面赚取了数百万的年薪&#xff01; 这位名叫莱利古德塞德的小弟最…

Codeforces Round #839 (Div. 3)题解

A. AB? 直接读入字符串然后把下标0和2的数字提取出来就行 // Problem: A. AB? // Contest: Codeforces - Codeforces Round #839 (Div. 3) // URL: https://codeforces.com/contest/1772/problem/A // Memory Limit: 512 MB // Time Limit: 2000 ms // // Powered by CP E…

还在堆人力处理工单?找准耗时源头才是关键!

对于提供企业级服务的公司来说&#xff0c;服务质量与效率日益受到关注。服务质量的本质是整体团队的效能&#xff0c;重中之重则是站在客户视角的工单解决效率。 当下很多这个领域的企业都会设立客户成功中心&#xff0c;其中就有专门对接客户工单处理的职责&#xff1b;而随…