使用 QWebChannel 实现 JS 与 C++ 双向通信(超详细 + 踩坑总结 + Demo)

使用 QWebChannel 实现 JS 与 C++ 双向通信(超详细 + 踩坑总结 + Demo)

使用 QWebChannel 实现 JS 与 C++ 双向通信(超详细 + 踩坑总结 + Demo)

在基于 QWebEngine 的项目中,要让 前端 JavaScript 与 后端 C++ 互相通信,是非常关键的能力。 Qt 官方提供的方案就是 QWebChannel,它能让你像调用本地对象一样从 JS 访问 C++,并且支持信号/槽、异步回调等。

但实际项目中常见各种问题:

  • JS 侧无法拿到对象?
  • 信号不触发?
  • 跨线程导致闪退?
  • 对象销毁后 JS 仍然在调用?
  • Page/Page再创建导致 channel 失效?

本文将带你彻底搞懂 QWebChannel 的机制,避坑,并给出可运行的 Demo。

一、QWebChannel 的通信原理

JS 与 C++ 的交互流程如下:

C++ QObject ←→ WebChannel Transport (QWebEngine) ←→ JS 对象 

实际通信依赖两部分:

① C++ 侧:QObject + QWebChannel

  • QObject 必须继承自 QObject
  • 想暴露给 JS 的属性/方法必须加 Q_INVOKABLE 或 Q_PROPERTY
  • 信号可以直接给 JS 发送事件
  • 将 QObject 注册进 QWebChannel:
channel->registerObject("bridge", myBridgeObject); 

② JS 侧:qwebchannel.js

网页加载后必须初始化:

new QWebChannel(qt.webChannelTransport, function(channel) {     window.bridge = channel.objects.bridge; }); 

然后:

// 调用 C++ bridge.sendMessage("hello"); // 接收 C++ 信号 bridge.messageChanged.connect(function(msg){     console.log("C++ emit:", msg); }); 

二、一个可跑的双向通信 Demo(最小可运行)

1. C++ 端代码
bridge.h
#pragma once #include <QObject> class Bridge :public QObject {     Q_OBJECT public:     explicit Bridge(QObject* parent = nullptr) : QObject(parent) {}     // JS 调用 C++     Q_INVOKABLE void sendMessage(const QString& msg) {         qDebug() << "JS 调用 C++:" << msg;         emit messageChanged("C++ 收到:" + msg);     } signals:     // C++ → JS     void messageChanged(const QString& msg); }; 
mainwindow.cpp
#include "mainwindow.h" #include <QWebEngineView> #include <QWebEnginePage> #include <QWebChannel> MainWindow::MainWindow(QWidget* parent)     : QMainWindow(parent) {     auto* view = new QWebEngineView(this);     auto* page = new QWebEnginePage(this);     view->setPage(page);     setCentralWidget(view);     // 创建 C++ 对象     auto* bridge = new Bridge(this);     // 创建 QWebChannel     auto* channel = new QWebChannel(this);     channel->registerObject("bridge", bridge);     page->setWebChannel(channel);     view->load(QUrl("qrc:/index.html"));     // 模拟 3 秒后给 JS 发消息     QTimer::singleShot(3000, [bridge]() {         emit bridge->messageChanged("来自 C++ 的问候!");     }); } 

2. 前端:index.html

<!DOCTYPE html> <html> <head>     <meta charset="UTF-8" />     <script src="qrc:///qtwebchannel/qwebchannel.js"></script> </head> <body>     <h2>QWebChannel Demo</h2>     <input id="msg" placeholder="发送给 C++ 的消息">     <button onclick="callCpp()">发送</button>     <p id="log"></p>     <script>         new QWebChannel(qt.webChannelTransport, function (channel) {             window.bridge = channel.objects.bridge;             // C++ → JS             bridge.messageChanged.connect(function (msg) {                 log("收到 C++:" + msg);             });         });         function callCpp() {             const msg = document.getElementById("msg").value;             bridge.sendMessage(msg);         }         function log(msg) {             document.getElementById("log").innerHTML += msg + "<br>";         }     </script> </body> </html> 

这个 Demo 能实现:

  • JS 调 C++
  • C++ 调 JS(信号)
  • 异步通信
  • 页面加载自动初始化 WebChannel

三、QWebChannel 常见问题与避坑指南(非常重要)

1. JS 侧总是拿不到对象(undefined)

典型错误:

console.log(bridge); // undefined 

正确做法:所有 JS 调用必须在 QWebChannel 初始化之后

new QWebChannel(qt.webChannelTransport, function(channel){     window.bridge = channel.objects.bridge; }); 

⚠ 不要在 window.onload 或顶层就调用 bridge。

2. 跨线程访问导致崩溃(最常见)

若你把 Bridge 放到子线程,会直接崩溃。

原因: QWebChannel 通信必须在 UI / WebEngine 所在线程使用,否则 QObject 会被跨线程访问。

正确方案:

  • bridge 必须在主线程
  • 如果你需要跨线程,可在 Bridge 中封装信号转发:
Q_INVOKABLE void updateDataFromWorkerThread(const QString& msg) {     emit messageChanged(msg); // 仍然在主线程发 } 

Qt 会自动通过 queued connection 切回主线程。

3. 页面重新加载后 channel 失效

当你 reload()、load() 新页面后: 之前的 JS 对象全部失效。

必须在每次页面加载后重新建立 WebChannel

示例:

connect(page, &QWebEnginePage::loadFinished, this, [=](bool ok){     if(ok) {         page->setWebChannel(channel);     } }); 

⚠ Qt 5 必做,Qt 6 已自动处理但建议仍写上。

4. C++ 信号没有触发 JS 回调

常见原因:

  • Bridge 对象被销毁
  • 信号签名不匹配
  • JS 回调写在 WebChannel 初始化外部
  • 信号参数为自定义类型但未 qRegisterMetaType
排查顺序:
  • C++ 打印信号是否发出
  • JS log 是否有回调
  • 参数类型是否是 QVariant 能转的基本类型
  • Bridge 是否挂靠在 MainWindow(不要让其随 WebPage 销毁)

5. 复杂参数(对象/数组)导致 JS 不接收

支持:

  • QString
  • int/double/bool
  • QVariantList(JS Array)
  • QVariantMap(JS Object)

但不支持 C++ 自定义结构体。

解决:
QVariantMap obj; obj["name"] = "Tom"; obj["age"] = 12; emit messageChanged(obj); 

JS:

bridge.messageChanged.connect(function (obj) {     console.log(obj.name); }); 

五、总结

QWebChannel 是 Qt WebEngine 中最可靠、最强大的前后端通信方式,但需要注意:

  • Bridge 必须在主线程
  • JS 必须在初始化回调后才能使用对象
  • 参数使用 QVariant 可序列化
  • 页面刷新后必须重新 setWebChannel
  • 跨线程调用需谨慎(信号转发)

往期精彩回顾

☞QWebEngine 实战:自定义右键菜单、文件下载、Cookie 管理与 User-Agent 设置

☞ QWebEngine 常用 API 全面梳理

图片

☞ QWebEngine 系列组件全关系梳理

Read more

OpenClaw 完整部署指南:安装 + 三大 Coding Plan 配置 + CC Switch + 飞书机器人

OpenClaw 完整部署指南:安装 + 三大 Coding Plan 配置 + CC Switch + 飞书机器人

OpenClaw 完整部署指南:安装 + 三大 Coding Plan 配置 + CC Switch + 飞书机器人 * 📋 文章目录结构 * 1.3 一键安装 OpenClaw(推荐) * 1.4 通过 npm 手动安装 * 1.5 运行 Onboard 向导 * 1.6 验证安装 * 步骤二:配置 Coding Plan 模型 * 🅰️ 选项 A:阿里百炼 Coding Plan * A.1 订阅与获取凭证 * A.2 在 OpenClaw 中配置 * A.3 可用模型列表

Java 大视界 -- Java 大数据在智能家居能源消耗趋势预测与节能策略优化中的应用(433)

Java 大视界 -- Java 大数据在智能家居能源消耗趋势预测与节能策略优化中的应用(433)

Java 大视界 -- Java 大数据在智能家居能源消耗趋势预测与节能策略优化中的应用(433) * 引言: * 正文: * 一、智能家居能源管理的核心痛点与 Java 大数据的价值 * 1.1 行业核心痛点(基于《2024 中国智能家居行业白皮书》) * 1.2 Java 大数据的核心价值(实战验证适配性) * 二、技术架构设计实战(纵向架构图) * 2.1 核心技术栈选型(生产压测验证版) * 2.2 关键技术亮点(博主实战总结) * 三、核心场景实战(附完整可运行代码) * 3.1 场景一:能耗趋势预测(线性回归 + LSTM 融合模型) * 3.1.1 业务需求 * 3.1.

Rokid 手势识别技术深度解析:解锁 AR 无接触交互的核心秘密

Rokid 手势识别技术深度解析:解锁 AR 无接触交互的核心秘密

引言 在聊手势识别前,咱们先搞清楚:Rokid是谁?它为啥能把AR手势做得这么自然? Rokid是国内AR(增强现实)领域的“老兵”了,从2014年成立就盯着一个目标——让AR走进日常。你可能见过它的产品:能戴在脸上的“AR眼镜”Max Pro、能揣在兜里的“AR主机”Station 2、适合专业场景的“Station Pro”,这些设备不是用来“炫技”的,而是想让咱们摆脱手机、手柄的束缚,直接用手“摸”虚拟东西。 而手势识别,就是Rokid给AR设备装的“最自然的遥控器”——比如调大虚拟屏幕像捏橡皮一样捏合手指,翻页像翻书一样挥手。但不同设备、不同开发需求,需要搭配不同版本的SDK(软件开发工具包),这就像“不同型号的手机要装对应版本的APP”。 一、基础认知:先选对版本,避免开发走弯路 Rokid手势识别技术随SDK版本迭代持续优化,不同版本适配的Unity(开发工具)

基于深度学习YOLO算法+qwen deepseek大模型的无人机河道巡检系统平台 支持AI对话与文档生成分析

基于深度学习YOLO算法+qwen deepseek大模型的无人机河道巡检系统平台 支持AI对话与文档生成分析

YOLO+DeepSeek河道环境检测系统 项目简介 基于改进YOLO深度学习模型与DeepSeek大语言模型的河道环境智能检测与分析系统。本系统采用先进的计算机视觉技术,结合自然语言处理能力,实现对河道环境中各类目标的高精度检测与智能分析。系统支持单张图片、批量图片、视频文件及实时摄像头等多种输入方式,提供从环境检测到智能建议的完整解决方案,为河道治理、环境保护与水资源管理提供智能化技术支持。 ✨ 核心亮点 • 多场景检测支持:全面覆盖单张图片、图片文件夹、视频文件、实时摄像头四种输入方式 • 改进YOLO模型:基于YOLOv5/v8/v11/v12的优化版本,专注河道环境目标检测 • AI智能分析:集成DeepSeek/Qwen大模型,生成专业的河道环境分析与治理建议 • 实时处理反馈:前端实时展示检测进度与结果,支持实时视频流处理 • 完整技术栈:PyTorch深度学习 + SpringBoot后端 + Vue3前端 + Flask中台的完整架构 • 开箱即用:提供完整源码、预训练模型与详细部署文档,快速上手使用 🌊 检测对象范围 系统可精准识别河道