如何捕获和处理QtWebEnginePage内容更改?

时间:2017-01-31 20:23:24

标签: javascript c++ html5 qt qtwebengine

在Qt的(现已弃用) QWebPage课程中,每当html内容发出一个信号 contentsChanged() 用户编辑页面或以编程方式更改的页面更改了网页。在较新的QtWebEnginePage类中,似乎不是等效信号。鉴于从Qt应用程序使网页可编辑的方法已从QWebPage::setContentEditable方法更改为本机html5 javascript contenteditable,这并不令我感到惊讶。

我的问题: 有没有办法去"听" QtWebEnginePage内容更改?这是我现在以某种方式从javascript处理的东西吗?

请注意,我查看了Qt提供的移植信息,但没有发现任何令我印象深刻的内容......

1 个答案:

答案 0 :(得分:0)

不幸的是,与QtWebEngine相比,QtWebKit与其他Qt设施的整合程度更差,更差。 QtWebKit能够开箱即用的很多东西只能通过QtWebEngine的JavaScript技巧来实现。我能够在自己的项目中解决这个特殊问题,但这并不容易。

首先,我必须通过QWebChannel设置C ++代码和JavaScript代码之间的交互。在这个答案中涵盖的主题太大了,但从好的方面来看,关于此的文档或多或少都是好的:请参阅Qt WebChannel JavaScript API及其examples。最后,从C ++代码开始,您应该可以执行

之类的操作
webChannel->registerObject(QStringLiteral("myObject"), myObject);

其中webChannel是指向QWebChannel的指针,而myObject是指向具有公共插槽的QObject子类的指针。此操作将允许JavaScript代码调用myObject的公共槽,从而实现JavaScript和C ++之间的连接。

JavaScript用于跟踪DOM更改的“本机”解决方案是MutationObserver。它是一个实例化的JavaScript对象,用于侦听DOM更改。在每个DOM突变上,观察者调用构造时提供给它的回调函数。为了通知C ++代码中DOM的变化,回调应该调用暴露给JavaScript的某个对象的槽。在此插槽中的C ++代码中,您可以根据需要对内容更改做出反应 - 如果C ++代码的多个部分可能要订阅contentsChanged信号,请为它们提供此类信号,从插槽中发出myObject

以下是JavaScript端MutationObserver设置的简单示例:

var observer = MutationObserver(function(mutations, observer) {
    myObject.onContentChanged();
});

observer.start = function() {
    this.observe(document, {
        subtree: true,
        attributes: true,
        childList: true,
        characterData: true,
        characterDataOldValue: true
    });
}

observer.stop = function() {
    this.disconnect();
}

虽然设置此方法比使用QtWebKit的{​​{1}}信号要复杂得多,但在一天结束时我发现它更灵活,因为contentsChanged你可以看到完全在DOM中发生了哪些变化并进行了一些高级处理:

  1. 忽略您不感兴趣的更改。
  2. 记住以前的DOM状态,以便进一步实现撤消/重做。
  3. 在需要通过手动执行的JavaScript代码更改DOM时暂停侦听DOM更改 - 有时候通知C ++代码这样的更改是很方便的,因为C ++代码难以区分文本编辑引起的更改与某些脚本执行引起的更改之间的差异。
  4. 记录确切发生的更改 - 添加或删除或更改某个节点等。