从 Qt WebKit 移植到 Qt WebEngine

以下章节包含移植应用程序的有关信息,使用 Qt WebKit QWebView API 要使用 Qt WebEngine QWebEngineView .

体系结构

Chromium provides its own network and painting engines, which Qt WebEngine uses. This, among other things, allows Qt WebEngine to provide better and more reliable support for the latest HTML5 specification than Qt WebKit. However, Qt WebEngine is thus also heavier than Qt WebKit and does not provide direct access to the network stack and the HTML document through C++ APIs.

类名

The Qt WebEngine equivalent of Qt WebKit C++ classes are prefixed by " QWebEngine" instead of " 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 <frame> 元素,其定义单个框架的外观和内容,或采用 <iframe> 元素,在文本块中插入框架。

在 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);
							

某些方法现在异步返回结果

Because Qt WebEngine uses a multi-process architecture, calls to some methods from applications will return immediately, while the results should be received asynchronously via a callback mechanism. A function pointer, a functor, or a lambda expression must be provided to handle the results when they become available.

Qt WebKit

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

Qt WebEngine (with a lambda function in C++11)

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 (with a functor template wrapping a member function)

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 (with a regular functor)

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 were reused for their interface but, unlike Qt WebKit, Qt WebEngine has its own HTTP implementation and cannot go through a QNetworkAccessManager .

The signals and methods of QNetworkAccessManager that are still supported were moved to the 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 还影响证书管理办法。更多信息,见 管理证书 .

关于个别方法的注意事项

evaluateJavaScript

QWebFrame::evaluateJavaScript 被移动并重命名为 QWebEnginePage::runJavaScript 。目前,只能在页面主框架运行 JavaScript,且结果会被异步返回给所提供的 Functor (函子)。

Qt WebKit

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

Qt WebEngine (采用 Lambda 表达式在 C++ 11)

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

setHtml 和 setContent

QWebEnginePage::setHtml and QWebEnginePage::setContent 异步履行方式如同正常 HTTP 加载,不像其 QWebPage 搭档。

setContentEditable

QWebPage::setContentEditable 没有等效的,因为透过最新 HTML 标准中的 contentEditable 属性可以编辑任何文档元素。 因此, QWebEnginePage::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 被设计为使用硬件加速。因为不支持 Web View 类在 QGraphicsView ,除非将其附加到 QGLWidget 视口,否则此特征超出作用域。
QWebElement Qt WebEngine 使用多进程体系结构,这意味着对页面内部结构的访问都必须异步完成,任何查询结果都必须通过回调被返回。QWebElement API 是为同步访问而设计的,因此,这需要彻底的重新设计。
QWebDatabase 在 Qt WebKit 中包裹的此 API Web SQL 数据库特征,已从 HTML5 标准中删掉。
QWebPluginDatabase, QWebPluginFactory, QWebPluginInfo, QWebPage::setPalette, QWebView::setRenderHints Qt WebEngine 使用 Skia 渲染 Web 页面,不使用 QPainter 或 Qt 为此目的。HTML5 标准现在还提供了更好的替代,当 Qt WebKit 引入的本机控制插件不可用时。
QWebHistoryInterface 拜访过的链接由 Qt WebEngine 自动持久化。
QWebPage::setContentEditable 在最新 HTML 标准中,编辑任何文档元素可以通过 contentEditable 属性。因此 runJavaScript 就是所需要的: page->runJavaScript("document.documentElement.contentEditable = true")
QWebPage::setLinkDelegationPolicy There is no way to connect a signal to run C++ code when a link is clicked. However, link clicks can be delegated to the Qt application instead of having the HTML handler engine process them by overloading the QWebEnginePage::acceptNavigationRequest () function. This is necessary when an HTML document is used as part of the user interface, and not to display external data, for example, when displaying a list of results.

注意: acceptNavigationRequest() starts the loading process and emits the loadStarted() signal before 请求被接受或拒绝。因此, loadFinished() 信号返回 false 是可预期的即使在委派请求后。