Qt和JavaScript使用QWebChannel交互一——和Qt内嵌网页交互
Qt和JavaScript使用QWebChannel交互一——和Qt内嵌网页交互
前言
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内嵌网页交互的更多相关文章
- JavaScript进阶 - 第6章 事件响应,让网页交互
6-1什么是事件 JavaScript 创建动态页面.事件是可以被 JavaScript 侦测到的行为. 网页中的每个元素都可以产生某些可以触发 JavaScript 函数或程序的事件. 比如说,当用 ...
- Qt WebEngine 网页交互
环境:Qt5.7.0,VS2013 一.简单介绍 从 Qt5.4 开始已经去掉 Qt WebKit 模块了,使用的是 chrome 内核封装的 QtWebEngine,浏览器相关的类有以下几个: QW ...
- ECharts-基于Canvas,纯Javascript图表库,提供直观,生动,可交互,可个性化定制的数据可视化图表
ECharts http://ecomfe.github.com/echarts 基于Canvas,纯Javascript图表库,提供直观,生动,可交互,可个性化定制的数据可视化图表.创新的拖拽重计算 ...
- Qt 与 JavaScript 通信
使用QWebView加载网页后,解决Qt与JavaScript通信的问题: The QtWebKit Bridge :http://qt-project.org/doc/qt-4.8/qtwebkit ...
- QT与JavaScript互调 - 虹的日志 - 网易博客
QT与JavaScript互调 - 虹的日志 - 网易博客 QT与JavaScript互调 2012-05-29 21:43:14| 分类: 技术 | 标签:qt javascript w ...
- JavaScript高级用法一之事件响应与网页交互
综述 本篇的主要内容来自慕课网,事件响应与网页交互,主要内容如下 1 什么是事件 2 鼠标单击事件( onclick ) 3 鼠标经过事件(onmouseover) 4 鼠标移开事件(onmouseo ...
- C#在WinForm中使用WebKit传递js对象实现与网页交互的方法
这篇文章主要介绍了C#在WinForm中使用WebKit传递js对象实现与网页交互的方法,涉及针对WebBroswer控件及WebKit控件的相关使用技巧,需要的朋友可以参考下 本文实例讲述了C#在W ...
- Qt 4.5发布(最大的变动是换用LGPL许可证,移植进了苹果的Cocoa框架。之前的Qt只支持Carbon框架,现在的Qt 4.5两者都支持。单一源代码创建出支持32位或64位字节的Intel或PowerPC Mac二进制文件)
Nokia的开源Qt开发工具正式发布了4.5版.如前所述,Qt 4.5最大的变动是换用LGPL许可证,目前采用的三个许可证分别为LGPL/GPL和商业许可证. 新版 ...
- Qt 子窗口内嵌到父窗口中(无边框附体show即可)good
有时需要把一个子窗口内嵌进入父窗口当中. 我们可以这样做 1.新建一个QWidget 或者QDialog的子类 ClassA(父类为ClassB) 2.在新建类的构造函数中添加设置窗口属性 setWi ...
随机推荐
- C++面试题(四)——智能指针的原理和实现
C++面试题(一).(二)和(三)都搞定的话,恭喜你来到这里,这基本就是c++面试题的最后一波了. 1,你知道智能指针吗?智能指针的原理. 2,常用的智能指针. 3,智能指针的 ...
- 【转】关于DNS不得不说的一些事
转自:https://www.cnblogs.com/rjzheng/p/11395695.html 引言 今天我们来聊聊DNS.所谓域名系统(Domain Name System缩写DNS,Doma ...
- ProjectEuler 007题
题目:By listing the first six prime numbers: 2, 3, 5, 7, 11, and 13, we can see that the 6th prime is ...
- Python的GPU编程实例——近邻表计算
技术背景 GPU加速是现代工业各种场景中非常常用的一种技术,这得益于GPU计算的高度并行化.在Python中存在有多种GPU并行优化的解决方案,包括之前的博客中提到的cupy.pycuda和numba ...
- 将视图批量新增到PowerDesigner中并以model图表的形式展示
1:需求 数据库中的所有视图大概64个左右,都需要新增到PowerDesigner中,以图表(model)的形式给展示出来,如下: 2:问题点: 由于2020年春节期间病毒的原因,我们需要远程办公,新 ...
- Java并发之AQS原理解读(二)
上一篇: Java并发之AQS原理解读(一) 前言 本文从源码角度分析AQS独占锁工作原理,并介绍ReentranLock如何应用. 独占锁工作原理 独占锁即每次只有一个线程可以获得同一个锁资源. 获 ...
- Go-内置函数之append、recover用法
package main import "fmt" import "time" func test() { defer func() { if err := r ...
- for循环练习之打印三角形
public class TestDemo01 { /** * 打印三角形 * 1.打印空格 * 2.打印三角形 */ public static void main(String[] args) { ...
- 如何实现LRU缓存
大家好,我是程序员学长,今天我们来聊一聊LRU缓存问题. Tips: LRU在计算机软件中无处不在,希望大家一定要了解透彻. 问题描述 设计LRU(最近最少使用)缓存结构,该结构在构造时确定大小,假设 ...
- tomcat漏洞总结
描述 Tomcat是Apache 软件基金会(Apache Software Foundation)的Jakarta 项目中的一个核心项目,由Apache.Sun 和其他一些公司及个人共同开发而成.由 ...