Qt QWebEngine 加载网页及交互,实现C++与JS 相互调用

打印 上一主题 下一主题

主题 901|帖子 901|积分 2703

前言

本篇主要介绍QT开辟过程中如何使用QWebengine加载网页,通过C++与JS 相互调用,实现QT程序与HTML网页的交互。QtWebEngine 是Qt的一个子模块,它提供了一个 Web 浏览器引擎,可以轻松地将互联网上的内容嵌入到 Qt 应用程序中。
1、QtWebEngine介绍

Qt WebEngine 分为以下三大部分:


  • Qt WebEngine Widgets Module 用于创建基于小部件的 Web 应用程序
  • Qt WebEngine Module 用于创建基于 Qt Quick 的 Web 应用程序
  • Qt WebEngine Core Module 用于与 Chromium 交互
下图是QWebEngine的架构,本文主要关注其中的Qt WebEngine Widgets 模块。

Qt WebEngine Process 是一个单独的可实行文件,用于渲染网页和实行 JavaScript。这可以缓解安全问题并隔离由特定内容引起的崩溃。留意,在发布使用QWebEngine加载网页的应用程序时,Qt WebEngine 可实行程序必须随应用程序一起提供。
下图是Qt WebEngine Widgets 模块的构造布局。其中的view 就是 QWebEngineView,page 代表QWebEnginePage。每一个QWebEngineView实例包含一个QWebEnginePage成员。QWebEnginePage可以有一个QWebEngineHistory和几个QAction对象。QWebEngineHistory提供对页面导航历史记载的访问,而QAction用于对网页应用操作。此外,QWebEnginePage可以或许在页面的主框架上下文中运行JavaScript代码,并允许处置惩罚特定的自定义事件,如显示自定义的身份验证对话框。
每个QWebEnginePage附属于一个QWebEngineProfile,QWebEngineProfile可以有一个QWebEngineSettings来指定页面设置,还可以有一个QWebEngineScriptCollection用于在页面上运行脚本,以及一个QWebEngineCookieStore用于访问Chromium的HTTP cookie。QWebEnginePage还可以直接指向一个脚本集合。

2、安装

QtWebengine模块作为Qt的子模块同样支持跨平台,可以安装在Windows、Linux、MacOS系统上。下面以Windows系统安装为例来阐明如何安装,其他系统下安装过程类似。对于本身编译Qt开辟环境同时支持QtWebengine的,可以参考这篇文章Qt5开辟环境-银河麒麟V10ARM平台
起首在Qt安装目次下找到MaintenanceTool.exe,双击打开,如下图所示

点击上图左下角的设置按钮,配置qt在线更新必要的版本库。在打开的配置页面中,按照下图1-4的顺序配置并测试当前系统安装的qt版本对应的在线库地点,最后在关闭页眼前一定不要忘记点第5步OK按钮来生存配置信息,如下图所示:

上图中的版本库链接可以在这个网址找到,根据实际必要找到对应的地点。下图是我必要的qt在线更新库链接,必要留意的是所选链接对应的文件目次中必须有Updates.xml文件。

配置幸亏线更新版本库后,点击next按钮进行下一步操作,在弹出页面中选择Add or remove components ,如下图所示

点击next按钮进入下个页面,如下图所示,勾选Qt WebEngine,然后点next按钮,开始安装。

3、焦点类介绍

3.1 QWebEngineView

QWebEngineView是Qt WebEngine网页浏览模块的主要窗口部件组件。它可以在各种应用程序中使用,及时显示来自互联网的网页内容。QWebEngineView 主要api及其含义见下表。
api功能描述load(url)加载指定的url并显示setUrl(url)设置url属性,将会清空webview,并重新load该urlpage()返回该web view对应的QWebEnginePage 实例setHtml(html)将web view内容设置为htmlsetPage(newpage)将当前web view的page 设置为newpage,newpage的父节点持有newpage实例,如果当前page是web view的子节点,调用该函数后当前page将被删除setZoomFactor(factor)设置web view 的缩放系数triggerPageAction(actiontype)触发指定的动作,actiontypeback()槽函数,用于加载在通过链接导航构建的文档列表中的前一个文档。如果没有上一个文档,则不实行任何操作。等价于 view->page()->triggerAction(QWebEnginePage::Back)forward()槽函数,用于加载在通过链接导航构建的文档列表中的后一个文档。如果没有下一个文档,则不实行任何操作。等价于 view->page()->triggerAction(QWebEnginePage::Forwardreload()槽函数,重新加载当前网页iconChanged(icon)信号,当与webview关联的图标(“favicon”)发生更改时,会发出此信号。新的图标由icon参数指定。iconUrlChanged(url)信号,当与webview关联的图标(“favicon”)的URL发生更改时,会发出此信号。新的图标URL由url参数指定。loadFinished(bOK)信号,当网页加载完成时发出此信号,bOK为true体现加载乐成,否则加载失败loadProgress(int progress)信号,加载进度变化时发出此信号,参数progress为当前加载进度renderProcessTerminated( terminationStatus, int exitCode)信号,当渲染进程以非零退出状态制止时,会发出此信号。terminationStatus是进程的制止状态,而exitCode是进程制止时的状态码。 3.2 QWebEnginePage

QWebEnginePage管理HTML文档的内容、导航链接的历史记载和操作。QWebEnginePage的API与QWebEngineView非常相似,以是我们仍旧可以使用常见的函数,例如action()(在QWebEngineView中称为pageAction())、triggerAction()和findText()。
api功能描述createStandardContextMenu()创建标准的上下文菜单,当用户在web页面点击鼠标右键时显示该菜单devToolsPage()如果没有设置 developer tools 网页,则返回null,如果设置了则返回对应的developer tools 网页setDevToolsPage(page)设置page为developer tools 网页download(url,filename,)下载文件findText(substring, options, resultCallback)在网页中搜索字符串,搜索到的字符串高亮显示,如果搜索到字符串回调函数的bool类型参数为true,否则为false。调用该函数并传一个空的substring参数,可去掉高亮显示的查询效果print(printer,resultCallback)将当前显示的网页打印成PDF文档,resultCallback有一个bool类型的参数,若打印乐成参数为true,否则为falsereplaceMisspelledWord(replacement)将拼写错误的词替换为函数参数replacement,当前拼写错误的词在 QWebEngineContextMenuData::misspelledWord()中可以找到, 发起的替换词在QWebEngineContextMenuData::spellCheckerSuggestions()中runJavaScript(scriptSource, worldId, resultCallback)运行一段JS代码,返回值可在resultCallback中获取到,返回值只能是一些简单类型的数据。为了避免与网页上其他的js脚本产生辩论,可以为当前运行的js脚本指定一个id,即这里的参数worldid,worldid取值范围0-256。超出这个值,js将在MainWorld下实行save(filepath, format)将当前加载的网页生存到磁盘,文件将按照指定的format,生存到filepathsetAudioMuted(muted)设置网页音频是否静音setWebChannel( channel, worldId)设置该页面的Web通道实例为channel,并使用Chromium IPC消息将其连接到Web引擎的传输层。该传输层在JavaScript worldId 对应的空间中以qt.webChannelTransport的情势暴露,在使用Qt WebChannel JavaScript API时应使用该传输层。留意:网页不会持有通道对象,且每个页面只能安装一个Web通道,即使在另一个JavaScript世界中设置,也会卸载任何已安装的Web通道toHtml( resultCallback)将网页同步地转为HTML格式的文档,以body标签作为开始和结束标签。转换乐成后网页调用resultCallback将效果以字符串的情势传回toPlainText(resultCallback)将网页同步地转为纯文本内容。转换乐成后网页调用resultCallback将效果以字符串的情势传回audioMutedChanged(muted)信号, 当页面的静音状态发生变化时,会发出此信号authenticationRequired(requestUrl, authenticator)信号,当访问requestUrl必要身份验证时,会发出此信号。应使用authenticator来转达连接的用户名和密码。findTextFinished( result)信号,当页面搜索字符串搜索完成时,会发出此信号。result参数是字符串搜索的效果。pdfPrintingFinished( filePath, success)信号,当将网页打印为PDF文件完成时,会发出此信号。filePath参数包含哀求创建文件的路径,success参数为true体现文件乐成创建,为false则体现创建失败。recentlyAudibleChanged(recentlyAudible)当页面的可听状态recentlyAudible发生变化时,即音频播放或制止时,会发出此信号。windowCloseRequested()信号, 无论何时页面哀求关闭Web浏览器窗口(例如通过JavaScript的window.close()调用),都会发出此信号。 3.3 QWebEngineProfile

QWebEngineProfile是网页的配置文件类,一个QWebEngineProfile包含设置、脚本、持久性Cookie策略以及所有属于该配置文件的网页共享的已访问链接列表。 主要api及其含义
api功能描述defaultProfile()类方法,返回默认配置文件。默认配置文件使用存储名称 “Default”cachePath()返回缓存路径。默认情况下,该路径位于QtWebEngine/StorageName特定子目次中的StandardPaths::CacheLocation下。留意:使用QStandardPaths::writableLocation(QStandardPaths::CacheLocation)来获取QStandardPaths::CacheLocation路径clearAllVisitedLinks()清除已访问链接数据库中的所有链。clearHttpCache()删除配置文件的缓存条目httpAcceptLanguage()返回Accept-Language HTTP哀求头字段的值httpCacheMaximumSize()返回HTTP缓存的最大大小(以字节为单位),如果大小由QtWebEngine自动控制,则返回0httpCacheType()返回使用的HTTP缓存类型。如果配置文件是无记载模式(off-the-record),则返回MemoryHttpCachehttpUserAgent()返回发送到HTTP的用户署理字符串,用于标识浏览器installUrlSchemeHandler(scheme, handler)在当前QWebEngineProfile中为自定义URL方案注册一个处置惩罚程序handler。在应用程序启动时,必要先使用QWebEngineUrlScheme::registerScheme注册该方案isOffTheRecord()如果这是一个无痕浏览模式的配置文件,则不在计算机上留下任何记载,该函数返回true。这将强制将Cookie和HTTP缓存存储在内存中,但也会强制将所有其他通常持久化的数据存储在内存中。persistentCookiesPolicy()返回持久性Cookie的当前策略。如果配置文件是无记载模式(off-the-record),则返回NoPersistentCookies。persistentStoragePath()返回用于存储浏览器和网页内容的持久化数据的路径。持久化数据包括持久性Cookie、HTML5本地存储和已访问链接。默认情况下,该路径位于QStandardPaths:ataLocation下的QtWebEngine/StorageName特定子目次中。使用函数 QStandardPaths::writableLocation(QStandardPaths:ataLocation)来获取QStandardPaths:ataLocation 的路径scripts()返回在与该配置文件共享的所有页面中注入的脚本集合。visitedLinksContainsUrl(url)如果url被此配置文件视为已访问链接,则返回true。downloadRequested( downloadItem )信号,每当触发下载时,就会发出此信号。downloadItem参数生存下载的状态。下载必须使用QWebEngineDownloadItem::accept()显式接受,否则默认情况下将被取消。downloadItem的父对象是配置文件。如果downloadItem未被接受,它将在信号发出后立即被删除。此信号不能与排队的连接一起使用 3.4 QWebEngineHistory

每个QWebEnginePage对象都包含一个访问过的页面历史记载,可以通过QWebEnginePage::history()来访问。历史记载使用current item的概念,将访问过的页面分为可以通过使用back()和forward()函数进行后退和进步导航的页面。可以通过调用currentItem()获取当前项。可以通过将恣意项转达给goToItem()把历史记载中的恣意项设置为当前项。调用backItems()函数获取可以通过back()函数访问的页面列表;类似地,通过调用forwardItems()函数获取当前页面之后的页面列表。调用items()函数可以获取完备的历史记载列表。与容器类似,可以使用itemAt()获取历史记载中的恣意项,count()返回项的总数,clear()函数用于清除历史记载。QWebEngineHistory 主要api及其含义
api功能描述back()将当前项设置为历史记载中的前一项,并导航到相应的页面backItem()返回当前页之前的一个历史记载中的网页项canGoBack()如果历史记载中当前项之前存在一个项,则返回true;否则返回falsecanGoForward()如果历史记载中当前项之后有一个要进步到的项,则返回true;否则返回falseclear()清空浏览的网页历史记载count()返回历史记载中网页的数量currentItem()返回当前历史记载项forward()将当前项设置为历史记载中的前后一项,并导航到相应的页面forwardItem()返回当前页之后的一个历史记载中的网页项goToItem(item)导航到item相应的页面itemAt(index)返回索引为index的历史记载页面项items()返回所有的历史记载项 3.5 QWebEngineSettings

QWebEngineSettings用户配置浏览器属性,例如字体大小和字体族、自定义样式表的位置以及通用属性,例如JavaScript支持。我们可以使用setAttribute()函数来设置各个属性。每个QWebEnginePage对象都有本身的QWebEngineSettings对象,用于配置该页面的设置。
QWebEngineSettings 主要api及其含义
api功能描述defaultSettings()类方法, 返回属于默认配置文件的网页的设置(QWebEngineSettings 对象),未使用其他配置文件创建的网页都属于默认配置文件setAttribute(attribute, on)根据on的值,启用或禁用指定的属性功能setDefaultTextEncoding(encoding)指定默认的文本编码系统。encoding的值必须是描述编码的字符串,例如 “utf-8” 或 “iso-8859-1”。如果留空,将使用默认值setFontFamily( which, family)为指定的通用字体族 which 设置实际的字体族familysetFontSize( type, size)将指定类型type的字体大小设置为以像素为单位的sizesetUnknownUrlSchemePolicy( policy)将处置惩罚导航哀求到未知URL方案的策略设置为policy。默以为QWebEngineSettings::AllowUnknownUrlSchemesFromUserInteractiontestAttribute( attribute)如果属性attribute已启用,则返回true;否则返回false。 4、加载网页

在Qt测试工程中新建 WebengineWidgets 带界面类,然后在ui文件中按照下图添三个按钮,一个Widget组件,并将Widget组件提升为QWebEngineView。

然后在webenginewidgets.cpp 文件中的构造函数中添加下面这行代码,如下面的代码所示
  1.         ui->webview->load(QUrl("https://www.baidu.com"));
复制代码
编译运行,效果如下图所示:

5、C++调用JS

将加载线上网页改为加载本地html文件,新建一个webtest.html文件,添加下图所示的代码
  1. <!DOCTYPE html>
  2. <html>
  3.         <head>
  4.                 <meta charset="utf-8">
  5.                 <meta name="viewport" content="width=device-width, viewport-fit=cover">
  6.                 <title>QWebEngineTest</title>
  7.                
  8.                 <script type="text/javascript">
  9.                        
  10.                         //C++ 调用showalert函数
  11.                         function showalert(text)
  12.                         {
  13.                                 alert(text)
  14.                         }       
  15.                 </script>
  16.         </head>
  17.         <body>
  18.                 <p>
  19.                         QWebEngineTest
  20.                 </p>
  21.         </body>
  22. </html>
复制代码
5.1 无返回值

在webtest.html中有个函数 showalert(text) ,函数体中只有一行代码,这行代码的意思是在网页上弹出一个提示框,并将传过来的参数text显示到提示框上。
起首加载本地html文件,若要调用JS函数,必须期待网页加载完成,否则会调用失败。这里在槽函数slot_webviewLoadFinished中调用JS代码:
  1. WebengineWidgets::WebengineWidgets(QWidget *parent) :
  2.     QWidget(parent),
  3.     ui(new Ui::WebengineWidgets)
  4. {
  5.     ui->setupUi(this);
  6.     QString appDirPath = QApplication::applicationDirPath();
  7.     qDebug() <<QString("appDirPath:") << appDirPath;
  8.     QString webtestfile = appDirPath.append("/../../../webtest.html");
  9.     ui->webview->load(QUrl(QString("file://%1").arg(webtestfile)));
  10.     connect(ui->webview, &QWebEngineView::loadFinished, this, &WebengineWidgets::slot_webviewLoadFinished);
  11. }
  12. void WebengineWidgets::slot_webviewLoadFinished(bool bOK)
  13. {
  14.     QString jsCode = QString("showalert('%1')").arg("Hello QtWebEngine!");
  15.     ui->webview->page()->runJavaScript(jsCode, [](const QVariant &v) { qDebug() << v.toString(); });
  16. }
复制代码
编译运行程序,效果如下图所示

5.2 有返回值

在html中,新增有返回值的JS函数,
  1. //C++ 调用getJsData函数
  2. function getJsData()
  3. {
  4.         return "C++ Call JS demo"
  5. }       
复制代码
在slot_webviewLoadFinished槽函数中,调用getJsData()函数,返回值将在lamda回调中打印。
  1. void WebengineWidgets::slot_webviewLoadFinished(bool bOK)
  2. {
  3.     QString jsCode = QString("showalert('%1')").arg("Hello QtWebEngine!");
  4.     //ui->webview->page()->runJavaScript(jsCode, [](const QVariant &v) { qDebug() << v.toString(); });
  5.     jsCode = "getJsData()";
  6.     ui->webview->page()->runJavaScript(jsCode, [](const QVariant &v) { qDebug() << v.toString(); });
  7. }
复制代码
再次编译运行,效果如下

6、JS调用C++

QWebChannel是C++应用程序和HTML/JavaScript应用程序之间的桥梁。通过将一个派生自QObject的对象发布到QWebChannel,并在HTML端使用qwebchannel.js,可以透明地访问QObject的属性、公共槽和方法。不必要手动进行消息转达和数据序列化,C++端的属性更新和信号发射会自动传输到潜在的远程运行的HTML客户端。在客户端,将为任何发布的C++ QObject 创建一个JavaScript对象。它反映了C++对象的API,因此可以直观地使用。
C++的QWebChannel API使得可以与任何HTML客户端通信,这些客户端可以在本地或甚至远程呆板上运行。唯一的限定是HTML客户端要支持qwebchannel.js使用的JavaScript功能。因此,可以实现C++与险些任何现代HTML浏览器或独立的JavaScript运行时(如node.js)进行交互。
起首从Qt安装目次的/Examples/Qt-5.15.2/webchannel/shared目次下拷贝qwebchannel.js到项目的bin目次下,在pro文件中增加DESTDIR = $$PWD/bin。

6.1 新建WebObject 类继续自QObject。

  1. #include <QObject>
  2. class WebObject : public QObject
  3. {
  4.     Q_OBJECT
  5. public:
  6.     Q_PROPERTY(QString nativeText READ nativeText MEMBER m_nativeText NOTIFY nativeTextChanged FINAL)
  7.     explicit WebObject(QObject *parent = nullptr);
  8.        
  9.     QString nativeText() const { return m_nativeText; }
  10.    
  11. signals:
  12.         //在C++中定义的信号,可以在JS端监听此信号接收消息
  13.     void nativeTextChanged(const QString &text);
  14. public slots:
  15.         //C++ 端的公共槽函数,可以在JS端调用。
  16.     void setNativeText(const QString &text);
  17. private:
  18.     QString m_nativeText;
  19. };
复制代码
cpp 代码如下
  1. #include <QDebug>
  2. #include "webobject.h"
  3. WebObject::WebObject(QObject *parent)
  4.     : QObject{parent}
  5. {
  6. }
  7. void WebObject::setNativeText(const QString &text)
  8. {
  9.     m_nativeText = text;
  10.     qDebug() << QString("setNativeText:") << text;
  11.     emit nativeTextChanged(text);
  12. }
复制代码
6.2 将WebObject对象注册到QWebChannel中

在WebengineWidgets类中添加成员 WebObject *m_pWebObj,然后创建QWebChannel对象,并注册m_pWebObj。代码如下:
  1.         m_pWebObj =  new WebObject();
  2.     QWebChannel *pWebChannel = new QWebChannel();
  3.     //注册C++对象到QWebChannel,这样远端的QWebChannel也会生成一个对应的JS对象
  4.     pWebChannel->registerObject("nativeObj", m_pWebObj);
  5.     ui->webview->page()->setWebChannel(pWebChannel);
复制代码
6.3 然后修改webtest.html代码, 如下

  1. <!DOCTYPE html>
  2. <html>
  3.         <head>
  4.                 <meta charset="utf-8">
  5.                 <meta name="viewport" content="width=device-width, viewport-fit=cover">
  6.                 <title>QWebEngineTest</title>
  7.                
  8.                 <script type="text/javascript" src="./qwebchannel.js"></script>
  9.                 <script type="text/javascript">
  10.                        
  11.                         var nativeObj //全局变量
  12.                         //第一个参数是QtWebEngine 挂载到前端全局环境中的 window.qt.webChannelTransport
  13.                         new QWebChannel(qt.webChannelTransport, function(channel) {
  14.                                 nativeObj = channel.objects.nativeObj //C++ 注册的对象名称为nativeObj,所以channel.objects后面的名字是nativeObj
  15.                                 //连接WebObject类的nativeTextChanged信号
  16.                                 nativeObj.nativeTextChanged.connect(function(text)
  17.                                 {
  18.                                         alert("nativeTextChanged: " + text)
  19.                                 })
  20.                         })
  21.                        
  22.                         // 在网页端调用C++函数
  23.                         function jsCallCpp ()
  24.                         {
  25.                                 //调用WebObject类的setNativeText函数
  26.                                 nativeObj.setNativeText("JS Call C++ test ")
  27.                         }
  28.                
  29.                         function getNativeText()
  30.                         {
  31.                                 //调用WebObject类的nativeText函数,获取属性值
  32.                                 alert("new nativeText is: "  + nativeObj.nativeText)
  33.                         }
  34.                 </script>
  35.         </head>
  36.         <body>
  37.                 <p>
  38.                         QWebEngineTest
  39.                 </p>
  40.                 <button onclick="jsCallCpp()" >调用C++对象的函数setNativeText</button>
  41.                 <button onclick="getNativeText()" >获取C++对象属性nativeText </button>
  42.         </body>
  43. </html>
复制代码
编译运行程序,当点击 【调用C++对象的函数setNativeText】按钮时,调用jsCallCpp函数,在这个函数中,调用nativeObj.setNativeText 将字符串“JS Call C++ test ”设置到CPP端生存,同时触发信号nativeTextChanged,网页端收到信号后弹出alert并显示转达过来的参数text。 点击【获取C++对象属性nativeText】按钮时,调用getNativeText() 函数,在该函数中通过nativeObj对象获取属性nativeText,并弹出alert显示。 效果图如下:

总结

本文具体介绍了QWebEngine的安装及焦点类,并通过两个具体的示例演示了C++与JS相互调用的具体流程。希望通过阅读本文,能帮助你快速掌握QWebEngine。对文中内容有任何疑问,接待留言讨论!

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

络腮胡菲菲

金牌会员
这个人很懒什么都没写!
快速回复 返回顶部 返回列表