Qt和JavaScript使用QWebChannel交互一——和Qt内嵌网页交互
2021/10/1 17:11:05
本文主要是介绍Qt和JavaScript使用QWebChannel交互一——和Qt内嵌网页交互,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
Qt和JavaScript使用QWebChannel交互一——和Qt内嵌网页交互
目录- Qt和JavaScript使用QWebChannel交互一——和Qt内嵌网页交互
- 前言
- 一、效果
- 二、实现过程
- 1. Qt端
- 2. 网页端
- 三、过程中出现的问题
- 问题一
- 问题二
- 四、项目完整源码
- 五、总结
前言
Qt
提供了QWebChannel
来和网页进行通信,只需要注册自定义对象一下,就可以直接绑定信号槽来进行Qt程序和网页之前的通信,非常方便
下面使用一个案例来学习QWebChannel
环境
:vs2017+Qt5.11.2 写Qt
代码,vsCode写js
代码
一、效果
直接上图
二、实现过程
1. Qt端
- 新建一个
Qt Gui
项目,取名WebChannelDemo
- 一路下一步,最后选择
QWidget
基类
- 得到一个这样结构的项目
- 使用
Qt Designer
打开webchanneldemo.ui
,拖一个界面
- 这个时候再来创建一个用于通过
WebChannel
通信的WebTransport
类,基类选择QObject
- 为了方便,不用每次使用都创建一个
WebTransport
对象,我们将这个类写成单例
类,然后定义和js交互的信号的槽函数,最近定义一个宏来使用实例
#pragma once #include <QObject> class WebTransport : public QObject { Q_OBJECT WebTransport(QObject *parent = nullptr); ~WebTransport(); public: // 获取实例 static WebTransport* instance(); signals: // 向js发送信号 void msgToJs(const QString& msg); // 将从js接收的数据发送出去 void receviedJsMsg(const QString& msg); public slots: // js调用此函数,接收js传入的数据 void msgToQt(const QString& msg); }; // 定义一个宏 #ifndef WEB_TRSPT #define WEB_TRSPT WebTransport::instance() #endif // !WEB_TRSPT
- 最后,我们到
WebChannelDemo
类中来初始化一下,主要做了以下几件事:- 关联信号槽
- 实例化一个
QWebChannel
对象 - 将
WebTransport
单例对象注册到QWebChannel
- 将
QWebChannel
对象设置到网页中去 - 最后再加载本地网页
void WebChannelDemo::setup() { // 绑定信号槽 connect(ui.pushButton, &QPushButton::clicked, [this]() { ui.plainTextEdit->appendPlainText(QStringLiteral("发送消息到js:") + ui.lineEdit->text()); emit WEB_TRSPT->msgToJs(ui.lineEdit->text()); }); connect(WEB_TRSPT, &WebTransport::receviedJsMsg, [this](const QString& msg) { ui.plainTextEdit->appendPlainText(QStringLiteral("接收js信息:") + msg); }); // 构造一个channel对象 QWebChannel* channel = new QWebChannel(this); // 向channel对象注册自定义对象 channel->registerObject(QStringLiteral("webBridge"), WEB_TRSPT); // 使用webview的page设置channel对象 ui.webEngineView->page()->setWebChannel(channel); // 最后加载网页 ui.webEngineView->load(qApp->applicationDirPath()+"/channel/index.html"); }
2. 网页端
- 先创建一个
channel
目录,放在项目生成目录,和生成的可执行文件同级
- 使用vsCode打开这个目录,并创建如下项目结构
- 打开
index.html
文件,先编写一个这样的界面
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <!-- 样式 --> <link rel="stylesheet" href="./css/style.css"> <!-- js --> <script src="./js/qwebchannel.js"></script> <script src="./js/main.js"></script> </head> <body> <p>我是网页</p> <textarea name="textArea" id="textArea"></textarea><br> <input type="text" id="lineEdit"><br> <button id="sendBtn" onclick="senBtnClicked();">发送</button> <button id="clearBtn" onclick="clearBtnClicked();">清空</button> </body> </html>
- 打开
main.js
文件,编写js
代码,重点在初始化函数中,做了以下几件事- 直接构造一个
QWebChannel
对象,用回调函数函数接收创建好的QWebChannel对象
- 使用
QWebChannel对象
获取Qt
端注册的对象 - 给注册对象的信号绑定一个回调函数(槽函数),当
Qt
端注册的对象此信号发送时,回调函数被调用 - 调用注册对象的槽函数,给
Qt
端发送消息,直接使用Qt
端注册对象的槽函数名来调用
- 直接构造一个
// 显示信息 function outputMsg(msg) { var textArea = document.getElementById("textArea"); if (textArea) { textArea.innerHTML = textArea.innerHTML + msg + "\n"; textArea.scrollTop = textArea.scrollHeight; } } // 发送按钮点击 function senBtnClicked() { // 获取输出标签 var lineEdit = document.getElementById('lineEdit'); // 调用Qt对象函数 webTransport.msgToQt(lineEdit.value); // 显示 outputMsg("发送信息到Qt:" + lineEdit.value); } // 清空 function clearBtnClicked() { document.getElementById("textArea").innerHTML = ""; } // 初始化 window.onload = function init() { if (typeof qt !== "undefined") { new QWebChannel(qt.webChannelTransport, function(channel) { // 获取Qt注册的对象,设置到主窗口(这里的webTransport就是Qt端注册时的字符串id) window.webTransport = channel.objects.webTransport; // 绑定注册对象的信号 webTransport.msgToJs.connect(function(msg) { outputMsg("接收Qt信息:" + msg); }); webTransport.msgToQt("初始化channel成功!"); }); } else { alert("初始化qwebchannel失败") } }
三、过程中出现的问题
问题一
- 问题描述:运行时,Qt向Js端发送消息没有问题,Js端向Qt端发送消息时失败,会报如下错误
Cannot invoke unknown method of index -1 on object webTransport(0x...)
- 问题原因及解决办法:
使用Qt 5.11.2
编译生成的可执行程序,而网页端用的是Qt 5.14
的qwebchannel.js
文件,版本不兼容导致的,换成对应的qwebchannel.js
文件就好了
问题二
- 在加载本地网页时,为什么是先设置
QWebChannel
再加载网页?- 因为最开始的想法是,如果直接先使用
ui.webEngineView->page()
获取QWebEnginePage
对象,应该获取到的是个nullptr
,这个时候直接设置QWebChannel
,程序会崩掉,那我先加载网页,然后QWebEngineView
会内部构造一个QWebEnginePage
对象,我再通过page()
函数获取,这个时候肯定不是nullptr
了,再去设置QWebChannel
,这个过程简直完美,但是出人意料的是,按照这个过程设置的QWebChannel
并没有生效,也不能和js
交互- 解决办法就是先设置
QWebChannel
再加载网页,通过查看Qt
源码发现,通过page()
函数获取QWebEnginePage
对象时,内部做出了判断,如果内部维护的QWebEnginePage
对象为空时,会直接构造一个QWebEnginePage
对象,并不会返回空指针,设置完QWebChannel
后再去调用load()
函数加载网页时,内部会直接拿到设置好QWebChannel
的QWebEnginePage
对象去加载网页QWebEnginePage* QWebEngineView::page() const { Q_D(const QWebEngineView); if (!d->page) { QWebEngineView *that = const_cast<QWebEngineView*>(this); that->setPage(new QWebEnginePage(that)); } return d->page; } void QWebEngineView::load(const QUrl& url) { page()->load(url); }
四、项目完整源码
https://gitee.com/doyoung126/qt_-demo.git
下一篇:Qt和JavaScript使用QWebChannel交互二——和浏览器打开的网页交互(还没写,抽时间写)
五、总结
总结:遇到凡事不要慌,先掏出手机拍个朋网友圈
这篇关于Qt和JavaScript使用QWebChannel交互一——和Qt内嵌网页交互的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-11-01后台管理开发学习:新手入门指南
- 2024-11-01后台管理系统开发学习:新手入门教程
- 2024-11-01后台开发学习:从入门到实践的简单教程
- 2024-11-01后台综合解决方案学习:从入门到初级实战教程
- 2024-11-01接口模块封装学习入门教程
- 2024-11-01请求动作封装学习:新手入门教程
- 2024-11-01登录鉴权入门:新手必读指南
- 2024-11-01动态面包屑入门:轻松掌握导航设计技巧
- 2024-11-01动态权限入门:新手必读指南
- 2024-11-01动态主题处理入门:新手必读指南