当前位置:   article > 正文

Qt webengine 显示web页面、前后端通信以及下载详解_qtwebengine

qtwebengine

概述

官方文档: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的功能分成下列模块:

  • Qt WebEngine Widgets 模块: 用于创建基于Widget的web应用.
  • Qt WebEngine 模块: 用于创建基于Qt Quick的web应用.
  • Qt WebEngine Core 模块: 与Chromium交互

环境安装

注意的是亮点,1、建议使用qt5.8之后的版本,网上说对webengine支持的好一点前面的版本可能会有bug。2、vs2015的编译器,网上说只能使用qt-msvc版本+vs2015编译器,我只试了这个版本,好使,其他的版本,没使用过不保证没问题。

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

win10sdk

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

Qt5.8

自己存的: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的原因,可以试试把编译的目录全部删了,之后重新编译,有可能会修复哦。

与前端js交互

这一块很重要,也是我研究的比较多的地方,先给出两篇对我研究过程最有用的文档。

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去调用我的函数。

  1. void JsContext::sendMsg(QWebEnginePage* page, const QString& msg)
  2. {
  3. page->runJavaScript(QString("recvMessage('%1');").arg(msg));
  4. }

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中会使用到这个回调函数。

  1. var context;
  2. // 初始化
  3. function init()
  4. {
  5. var updateattribute=function(text)
  6. {
  7. alert(text);
  8. //$("#attrid").val(text);
  9. }
  10. if (typeof qt != 'undefined')
  11. {
  12. new QWebChannel(qt.webChannelTransport, function(channel)
  13. {
  14. context = channel.objects.context;
  15. context.someattributeChanged.connect(updateattribute);
  16. }
  17. );
  18. }
  19. else
  20. {
  21. alert("qt对象获取失败1!");
  22. }
  23. }
  24. // 接收qt发送的消息
  25. function recvMessage(msg)
  26. {
  27. alert(msg);
  28. }
  29. // 向qt发送消息
  30. function sendMessage(msg)
  31. {
  32. if(typeof context == 'undefined')
  33. {
  34. alert("context对象获取失败2!");
  35. }
  36. else
  37. {
  38. context.onMsg(msg);
  39. //context.setsomeattribute(msg);
  40. //updateattribute(context.m_someattribute);
  41. }
  42. }
  43. // 控件控制函数
  44. function onBtnSendMsg()
  45. {
  46. var cmd = document.getElementById("待发送消息").value;
  47. sendMessage(cmd);
  48. }
  49. init();

3、html,写一个最简单的html程序,引用上面的两个js文件,实现一个按钮点击之后出发sendMessage这个函数,发送一个字符串过去。

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta http-equiv=Content-Type context="text/html;charset=utf-8">
  5. <title>webchannel test</title>
  6. </head>
  7. <body>
  8. <p>webchannel test</p>
  9. <script type="text/javascript" src="./qwebchannel.js"></script>
  10. <script type="text/javascript" src="./msgutils.js"></script>
  11. <input id="待发送消息" type="text" name="msgText" />
  12. <input type="button" value="send msg" onclick="onBtnSendMsg()" />
  13. </body>
  14. </html>

4、Qt端new一个Jscontext对象和前面js里的context对象绑定起来,很简单的几句话,在webchannel上绑定就好了。

  1. JsContext *jsContext = new JsContext();
  2. QWebChannel *webChannel = new QWebChannel();
  3. Webpage *webPage = new Webpage();
  4. webChannel->registerObject("context", jsContext);
  5. 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)之后,定义的私有数据应该就能共享了,具体可以看上面那篇英文文档。

  1. #ifndef JSCONTEXT_H
  2. #define JSCONTEXT_H
  3. #include <QObject>
  4. #include <QWebEnginePage>
  5. #include <QString>
  6. #include "vcdlog4qt.h"
  7. class JsContext : public QObject
  8. {
  9. Q_OBJECT
  10. Q_PROPERTY(QString someattribute MEMBER m_someattribute NOTIFY someattributeChanged)
  11. public:
  12. explicit JsContext(QObject *parent = 0);
  13. void sendMsg(QWebEnginePage* page, const QString& msg);
  14. private:
  15. QString m_someattribute;
  16. signals:
  17. void recvdMsg(const QString& msg);
  18. void someattributeChanged(const QString &attr);
  19. public slots:
  20. void onMsg(const QString& msg);
  21. void setsomeattribute(QString attr);
  22. };
  23. #endif // JSCONTEXT_H
  1. #include "jscontext.h"
  2. JsContext::JsContext(QObject *parent) : QObject(parent) {
  3. VcdLog4Qt::getInstance()->info("new jscontext");
  4. }
  5. void JsContext::sendMsg(QWebEnginePage* page, const QString& msg)
  6. {
  7. page->runJavaScript(QString("recvMessage('%1');").arg(msg));
  8. }
  9. void JsContext::onMsg(const QString &msg)
  10. {
  11. emit recvdMsg(msg);
  12. }
  13. void JsContext::setsomeattribute(QString attr)
  14. {
  15. m_someattribute = attr;
  16. emit someattributeChanged(m_someattribute);
  17. }

有一个问题就是,webchannel在一个页面上只能开启一个通道,如果,页面多个按钮想要同时绑定这个对象进行同时传输数据是不行的,需要用总的通信通道通过协议分发给每个控件来做。

页面下载文件

下载文件我使用了官方给的方法QWebEngineDownloadItem 这个类里面实现了下载的信号以及方法,直接用即可,也可以自己实现下载,当页面点击的时候通过上面的通信的办法告诉Qt下载的地址,然后进行下载,但是下载之后的进度上面的都需要自己去实现。
connect(webPage->profile(), SIGNAL(downloadRequested(QWebEngineDownloadItem*)),this, SLOT(downloadRequested(QWebEngineDownloadItem*)));首先绑定下面这个信号,当页面有下载动作的时候会触发这个信号,下面是触发下载之后要做的事情,下载触发之后绑定下面两个信号downloadProgress,finished,在过程中会通知你进度(前端可以实现进度条)然后结束的时候也会通知你。一定要写download->accept()有了这个之后下载才会进行。

  1. void MainWindow::downloadRequested(QWebEngineDownloadItem* download)
  2. {
  3. download->accept();
  4. connect(download.data(), SIGNAL(downloadProgress(qint64,qint64)),
  5. this, SLOT(downloadProgress(qint64,qint64)));
  6. connect(download.data(), SIGNAL(finished()),
  7. this, SLOT(finished()));
  8. }

注意:重要的点,如果说页面下载动作是当前页面保存链接,那么这个信号是会被触发的,但是如果页面是正常的下载,那么在浏览器里面效果是打开一个新的页面进行下载的,这样的话这个信号是不会被触发的,因为这个下载信号只绑定了当前页面,如果要实现触发,需要在新的页面中实现绑定才行,这也是我刚开始遇到的坑,分享给大家。

有兴趣的同学可以去看看Qt里面用webengine实现的浏览器,会学到很多哦。

最后祝大家学习愉快,有问题或者有需要源码的小伙伴可以私聊我哈。

里面也有log4qt的使用方法大家可以借鉴。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/不正经/article/detail/605186
推荐阅读
相关标签
  

闽ICP备14008679号