官方文档:https://doc.qt.io/archives/qt-5.11/qtwebengine-overview.html
翻译文档:Qt5.9 WebEngine 概述 - 一花一世界,一叶一乾坤 - 博客园
从Qt5.5开始,Qt WebKit模块被废弃,被Qt WebEngine模块取代,Qt WebEngine模块提供了一个web浏览器的API(基于谷歌浏览器内核,libcef的库), 在不使用本地浏览器的情况下,它可以很容易地把Web内容嵌入到Qt应用程序中,Qt WebEngine为渲染HTML,XHTML和SVG文档,,使用CSS和JavaScript, 提供了C++类和QML类型。
Qt WebEngine的功能分成下列模块:
注意的是亮点,1、建议使用qt5.8之后的版本,网上说对webengine支持的好一点前面的版本可能会有bug。2、vs2015的编译器,网上说只能使用qt-msvc版本+vs2015编译器,我只试了这个版本,好使,其他的版本,没使用过不保证没问题。
http://219.83.160.146:5476/%E8%BD%AF%E4%BB%B6%E5%8C%85/cn_visual_studio_community_2015_with_update_3_x86_x64_web_installer_8922965.exe
安装选项:1、command tools for visual c++2015 2、python tools for visual studio
http://219.83.160.146:5476/%E8%BD%AF%E4%BB%B6%E5%8C%85/win10sdk/我自己存的
Windows SDK - Windows app development
安装选项:只要装debugging tools for windows
自己存的:http://219.83.160.146:5476/%E8%BD%AF%E4%BB%B6%E5%8C%85/qt-opensource-windows-x86-msvc2015_64-5.8.0.exe
官网的:Index of /archive/qt
构建套件的时候选择vs的编译器就可以了,debug选择win10sdk中的调试器
打开Qt新建一个项目,在.pro文件里面添加QT += webenginewidgets之后跟着下面这个链接走就行了
QT webengine 例子_small house-CSDN博客 很简单,就不多叙述了,网上的资料也很多。
我在使用过程中经常会遇到new一个对象但是提示链接错误的情况,其实代码是对的,可能是Qt ide的原因,可以试试把编译的目录全部删了,之后重新编译,有可能会修复哦。
这一块很重要,也是我研究的比较多的地方,先给出两篇对我研究过程最有用的文档。
Communication between C++ and Javascript in Qt WebEngine//这一篇是最有用的
QWebEngineView与js交互_Keep It Simple, Stupid-CSDN博客
最清晰Qt与JS通过qwebchannel交互例子_小猿一枚的专栏-CSDN博客
Qt调研js:
这一步很简单,只要跑runJavaScript这个函数就好了,我也没用再多研究下去,因为我的程序是以web页面为主,Qt只是一个壳子,所以基本上都是js去调用我的函数。
void JsContext::sendMsg(QWebEnginePage* page, const QString& msg)
{
page->runJavaScript(QString("recvMessage('%1');").arg(msg));
}
js调用Qt:
需要用到Qt注册一个js的对象,或者说Qt和js使用同一个对象,
qwebchannel.js是Qt提供的js方法,可以在这里下载:https://code.csdn.net/tujiaw/webengineview/tree/master/qwebchannel.js
里面提供了一些方法让qt和js共同使用一个对象。
1、需要把上面那个文件qwebchannel.js下载到html同级目录下
2、自己的js,这里面的init函数很重要,成功引用官方的qwebchannel.js之后就会找到qt对象,之后context = channel.objects.context;这个就说明js与一个叫”context“的对象绑定在一起,后面Qt中会使用到这个context
context.someattributeChanged.connect(updateattribute);下面这句话是表面给context这个对象设置一个回调函数,只要后面Qt中会使用到这个回调函数。
var context;
// 初始化
function init()
{
var updateattribute=function(text)
{
alert(text);
//$("#attrid").val(text);
}
if (typeof qt != 'undefined')
{
new QWebChannel(qt.webChannelTransport, function(channel)
{
context = channel.objects.context;
context.someattributeChanged.connect(updateattribute);
}
);
}
else
{
alert("qt对象获取失败1!");
}
}
// 接收qt发送的消息
function recvMessage(msg)
{
alert(msg);
}
// 向qt发送消息
function sendMessage(msg)
{
if(typeof context == 'undefined')
{
alert("context对象获取失败2!");
}
else
{
context.onMsg(msg);
//context.setsomeattribute(msg);
//updateattribute(context.m_someattribute);
}
}
// 控件控制函数
function onBtnSendMsg()
{
var cmd = document.getElementById("待发送消息").value;
sendMessage(cmd);
}
init();
3、html,写一个最简单的html程序,引用上面的两个js文件,实现一个按钮点击之后出发sendMessage这个函数,发送一个字符串过去。
webchannel test
webchannel test
4、Qt端new一个Jscontext对象和前面js里的context对象绑定起来,很简单的几句话,在webchannel上绑定就好了。
JsContext *jsContext = new JsContext();
QWebChannel *webChannel = new QWebChannel();
Webpage *webPage = new Webpage();
webChannel->registerObject("context", jsContext);
webPage->setWebChannel(webChannel);
5、接收回调函数,在c++中实现下面这个类Jscontext,用来和js交互的对象,注意的是里面的public slots里面有一个OnMsg函数,如果在js里面被调用context.onMsg(msg);那么在Qt里面就会有相应,这一点很简单,但是如何使用上面实现的回调函数呢?
需要声明一个信号signal:void someattributeChanged(const QString &attr);然后再emit someattributeChanged(m_someattribute);触发他即可,触发的时候将自己的参数带进去,可以是json字符串。这里有个很重要的点也是我之前遇到的坑,就是Communication between C++ and Javascript in Qt WebEngine这篇文档中没写明白的,在使用信号的时候void someattributeChanged(const QString &attr);里面必须要用const不然的话,js里面收的对象都是NULL。说明白之后我这边的功能基本都能实现了,如果说有小伙伴想要实现更加精细的功能,js和Qt的对象共享数据,那么在类里面加这个Q_PROPERTY(QString someattribute MEMBER m_someattribute NOTIFY someattributeChanged)之后,定义的私有数据应该就能共享了,具体可以看上面那篇英文文档。
#ifndef JSCONTEXT_H
#define JSCONTEXT_H
#include
#include
#include
#include "vcdlog4qt.h"
class JsContext : public QObject
{
Q_OBJECT
Q_PROPERTY(QString someattribute MEMBER m_someattribute NOTIFY someattributeChanged)
public:
explicit JsContext(QObject *parent = 0);
void sendMsg(QWebEnginePage* page, const QString& msg);
private:
QString m_someattribute;
signals:
void recvdMsg(const QString& msg);
void someattributeChanged(const QString &attr);
public slots:
void onMsg(const QString& msg);
void setsomeattribute(QString attr);
};
#endif // JSCONTEXT_H
#include "jscontext.h"
JsContext::JsContext(QObject *parent) : QObject(parent) {
VcdLog4Qt::getInstance()->info("new jscontext");
}
void JsContext::sendMsg(QWebEnginePage* page, const QString& msg)
{
page->runJavaScript(QString("recvMessage('%1');").arg(msg));
}
void JsContext::onMsg(const QString &msg)
{
emit recvdMsg(msg);
}
void JsContext::setsomeattribute(QString attr)
{
m_someattribute = attr;
emit someattributeChanged(m_someattribute);
}
有一个问题就是,webchannel在一个页面上只能开启一个通道,如果,页面多个按钮想要同时绑定这个对象进行同时传输数据是不行的,需要用总的通信通道通过协议分发给每个控件来做。
下载文件我使用了官方给的方法QWebEngineDownloadItem 这个类里面实现了下载的信号以及方法,直接用即可,也可以自己实现下载,当页面点击的时候通过上面的通信的办法告诉Qt下载的地址,然后进行下载,但是下载之后的进度上面的都需要自己去实现。
connect(webPage->profile(), SIGNAL(downloadRequested(QWebEngineDownloadItem*)),this, SLOT(downloadRequested(QWebEngineDownloadItem*)));首先绑定下面这个信号,当页面有下载动作的时候会触发这个信号,下面是触发下载之后要做的事情,下载触发之后绑定下面两个信号downloadProgress,finished,在过程中会通知你进度(前端可以实现进度条)然后结束的时候也会通知你。一定要写download->accept()有了这个之后下载才会进行。
void MainWindow::downloadRequested(QWebEngineDownloadItem* download)
{
download->accept();
connect(download.data(), SIGNAL(downloadProgress(qint64,qint64)),
this, SLOT(downloadProgress(qint64,qint64)));
connect(download.data(), SIGNAL(finished()),
this, SLOT(finished()));
}
注意:重要的点,如果说页面下载动作是当前页面保存链接,那么这个信号是会被触发的,但是如果页面是正常的下载,那么在浏览器里面效果是打开一个新的页面进行下载的,这样的话这个信号是不会被触发的,因为这个下载信号只绑定了当前页面,如果要实现触发,需要在新的页面中实现绑定才行,这也是我刚开始遇到的坑,分享给大家。
有兴趣的同学可以去看看Qt里面用webengine实现的浏览器,会学到很多哦。
最后祝大家学习愉快,有问题或者有需要源码的小伙伴可以私聊我哈。
里面也有log4qt的使用方法大家可以借鉴。