从Qt WebKit移植到Qt WebEngine

Qt WebKit 和 Qt WebEngine API 之间差异的概述。

以下部分包含有关将使用Qt WebKit QWebView API的应用程序移植到使用Qt WebEngine QWebEngineView的信息。

架构

Chromium 提供了自己的网络和绘图引擎,Qt WebEngine 使用了这些引擎。这使得 Qt WebEngine 能够比 Qt WebKit 提供更好、更可靠的最新 HTML5 规范支持。然而,Qt WebEngine 也因此比 Qt WebKit 更重,并且不提供通过 C++ API 直接访问网络堆栈和 HTML 文档的功能。

类名

Qt WebEngine 中与 Qt WebKit C++ 类等效的类前缀为“QWebEngine”,而不是“QWeb”

Qt WebKit

#include <QWebHistory>
#include <QWebHistoryItem>
#include <QWebPage>
#include <QWebView>

QWebHistory
QWebHistoryItem
QWebPage
QWebView

Qt WebEngine

#include <QWebEngineHistory>
#include <QWebEngineHistoryItem>
#include <QWebEnginePage>
#include <QWebEngineView>

QWebEngineHistory
QWebEngineHistoryItem
QWebEnginePage
QWebEngineView

Qt 模块名称

在qmake项目文件中

Qt WebKit

QT += webkitwidgets

Qt WebEngine

QT += webenginewidgets

在源文件中包含模块

Qt WebKit

#include <QtWebKit/QtWebKit>
#include <QtWebKitWidgets/QtWebKitWidgets> // With Qt >= 4.8

Qt WebEngine

#include <QtWebEngineWidgets/QtWebEngineWidgets>

QWebFrame 已合并到 QWebEnginePage

HTML框架可以用来将网页分成几个区域,每个区域的内容可以单独显示。

在Qt WebKit中,QWebFrame表示网页内的一个框架。每个QWebPage对象至少包含一个框架,即主框架,可以通过QWebPage::mainFrame()获取。额外的框架将为由HTML 元素创建的框架,该元素定义了单个框架的外观和内容,或者由元素创建的框架,该元素在文本块中插入一个框架。

在Qt WebEngine中,框架处理已被合并到QWebEnginePage类中。所有子框架现在被视为内容的一部分,并且只能通过JavaScript访问。QWebFrame类的方法,例如load(),现在可以直接通过QWebEnginePage本身使用。

Qt WebKit

QWebPage page;
connect(page.mainFrame(), SIGNAL(urlChanged(const QUrl&)), SLOT(mySlotName()));
page.mainFrame()->load(url);

Qt WebEngine

QWebEnginePage page;
connect(&page, SIGNAL(urlChanged(const QUrl&)), SLOT(mySlotName()));
page.load(url);

一些方法现在异步返回它们的结果

由于Qt WebEngine采用了多进程架构,应用程序对某些方法的调用会立即返回,而结果应通过回调机制异步接收。必须提供一个函数指针、仿函数或lambda表达式来处理结果,当结果可用时。

Qt WebKit

QWebPage *page = new QWebPage;
QTextEdit *textEdit = new QTextEdit;
// *textEdit is modified immediately.
textEdit->setPlainText(page->toHtml());
textEdit->setPlainText(page->toPlainText());

Qt WebEngine(使用C++11中的lambda函数)

QWebEnginePage *page = new QWebEnginePage;
QTextEdit *textEdit = new QTextEdit;
// *textEdit must remain valid until the lambda function is called.
page->toHtml([textEdit](const QString &result){ textEdit->setPlainText(result); });
page->toPlainText([textEdit](const QString &result){ textEdit->setPlainText(result); });

Qt WebEngine(使用一个包装成员函数的仿函数模板)

template<typename Arg, typename R, typename C>
struct InvokeWrapper {
    R *receiver;
    void (C::*memberFun)(Arg);
    void operator()(Arg result) {
        (receiver->*memberFun)(result);
    }
};

template<typename Arg, typename R, typename C>
InvokeWrapper<Arg, R, C> invoke(R *receiver, void (C::*memberFun)(Arg))
{
    InvokeWrapper<Arg, R, C> wrapper = {receiver, memberFun};
    return wrapper;
}

QWebEnginePage *page = new QWebEnginePage;
QTextEdit *textEdit = new QTextEdit;
// *textEdit must remain valid until the functor is called.
page->toHtml(invoke(textEdit, &QTextEdit::setPlainText));
page->toPlainText(invoke(textEdit, &QTextEdit::setPlainText));

Qt WebEngine(带有常规函数对象)

struct SetPlainTextFunctor {
    QTextEdit *textEdit;
    SetPlainTextFunctor(QTextEdit *textEdit) : textEdit(textEdit) { }
    void operator()(const QString &result) {
        textEdit->setPlainText(result);
    }
};

QWebEnginePage *page = new QWebEnginePage;
QTextEdit *textEdit = new QTextEdit;
// *textEdit must remain valid until the functor is called.
page->toHtml(SetPlainTextFunctor(textEdit));
page->toPlainText(SetPlainTextFunctor(textEdit));

Qt WebEngine 不与 QNetworkAccessManager 交互

Qt Network 中的一些类,如 QAuthenticator,因其接口被重用,但与 Qt WebKit 不同,Qt WebEngine 有自己的 HTTP 实现,无法通过 QNetworkAccessManager 进行。

QNetworkAccessManager 仍然支持的信号和方法已移至 QWebEnginePage 类。

Qt WebKit

QNetworkAccessManager qnam;
QWebPage page;
page.setNetworkAccessManager(&qnam);
connect(&qnam, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)), this, SLOT(authenticate(QNetworkReply*,QAuthenticator*)));

Qt WebEngine

QWebEnginePage page;
connect(&page, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)), this, SLOT(authenticate(QNetworkReply*,QAuthenticator*)));

注意

在Qt WebEngine中,必须将QAuthenticator显式设置为null以取消身份验证:

*authenticator = QAuthenticator();

省略QNetworkAccessManager也会影响证书的管理方式。更多信息,请参见Managing Certificates

关于各个方法的注意事项

评估JavaScript

QWebFrame::evaluateJavaScript 已被移动并重命名为 runJavaScript。目前只能在页面的主框架上运行 JavaScript,并且结果会异步返回到提供的函数对象。

Qt WebKit

QWebPage *page = new QWebPage;
qDebug() << page->mainFrame()->evaluateJavaScript("'Java' + 'Script'");

Qt WebEngine(使用C++11中的lambda表达式)

QWebEnginePage *page = new QWebEnginePage;
page->runJavaScript("'Java' + 'Script'", [](const QVariant &result){ qDebug() << result; });

setHtml 和 setContent

setHtmlsetContent 以异步方式执行,与普通的HTTP加载方式相同,这与它们的QWebPage对应物不同。

设置内容可编辑

QWebPage::setContentEditable 没有等效的方法,因为在最新的HTML标准中,任何文档元素都可以通过contentEditable属性设置为可编辑。因此,runJavaScript 就是所需要的全部。

Qt WebKit

QWebPage page;
page.setContentEditable(true);

Qt WebEngine

QWebEnginePage page;
page.runJavaScript("document.documentElement.contentEditable = true");

不可用的Qt WebKit API

此列表中的Qt WebKit类和方法在Qt WebEngine中将不可用。

QGraphicsWebView

Qt WebEngine 设计用于硬件加速。由于我们无法在 QGraphicsView 中支持一个网页视图类,除非它被附加到一个 QGLWidget 视口,因此此功能不在范围内。

QWebElement

Qt WebEngine 使用多进程架构,这意味着对页面内部结构的任何访问都必须异步进行,任何查询结果都必须通过回调返回。QWebElement API 是为同步访问设计的,这将需要完全重新设计。

QWebDatabase

此API在Qt WebKit中封装的Web SQL数据库功能已从HTML5标准中移除。

QWebPluginDatabase, QWebPluginFactory, QWebPluginInfo, QWebPage::setPalette, QWebView::setRenderHints

Qt WebEngine 使用 Skia 渲染网页,并且不为此目的使用 QPainter 或 Qt。HTML5 标准现在也提供了更好的替代方案,这些方案在 Qt WebKit 中引入原生控件插件时是不可用的。

QWebHistoryInterface

访问过的链接由Qt WebEngine自动持久化。

QWebPage::setContentEditable

在最新的HTML标准中,任何文档元素都可以通过contentEditable属性设置为可编辑。因此,只需要runJavaScript即可:page->runJavaScript("document.documentElement.contentEditable = true")

QWebPage::setLinkDelegationPolicy

当链接被点击时,无法连接信号来运行C++代码。然而,通过重载acceptNavigationRequest()函数,可以将链接点击委托给Qt应用程序,而不是由HTML处理引擎处理它们。这在HTML文档用作用户界面的一部分而不是显示外部数据时是必要的,例如,当显示结果列表时。

注意

acceptNavigationRequest()在请求被接受或拒绝之前启动加载过程并发出loadStarted()信号。因此,即使在委托请求后,也可能会收到返回falseloadFinished()信号。