WebEngine 内容操纵范例

内容操纵 展示如何使用 JQuery 采用 Qt WebEngine Widgets 去创建具有特殊效果和内容操纵的 Web 浏览器。

在应用程序中,调用 QWebEnginePage::runJavaScript () 去执行 jQuery JavaScript 代码。实现 QMainWindow 采用 QWebEngineView 作为构建浏览器本身的中心 Widget。

运行范例

要运行范例从 Qt Creator ,打开 欢迎 模式,然后选择范例从 范例 。更多信息,拜访 构建和运行范例 .

MainWindow 类定义

MainWindow 类继承 QMainWindow 。它实现许多履行应用程序和 Web 内容动作的槽:

class MainWindow : public QMainWindow
{
    Q_OBJECT
public:
    MainWindow(const QUrl& url);
protected slots:
    void adjustLocation();
    void changeLocation();
    void adjustTitle();
    void setProgress(int p);
    void finishLoading(bool);
    void viewSource();
    void highlightAllLinks();
    void rotateImages(bool invert);
    void removeGifImages();
    void removeInlineFrames();
    void removeObjectElements();
    void removeEmbeddedElements();
private:
    QString jQuery;
    QWebEngineView *view;
    QLineEdit *locationEdit;
    QAction *rotateAction;
    int progress;
};
					

还声明 QString 包含 jQuery, QWebEngineView 显示 Web 内容,和 QLineEdit 充当地址栏。

MainWindow 类实现

我们从实现构造函数开始。构造函数的第一部分是设置值为 progress 到 0。此值在稍后的代码中用于可视化网页加载:

MainWindow::MainWindow(const QUrl& url)
{
    setAttribute(Qt::WA_DeleteOnClose, true);
    progress = 0;
					

下一步,加载 jQuery 库通过使用 QFile 并读取文件内容。jQuery 库是提供不同 HTML 操纵函数的 JavaScript 库:

    QFile file;
    file.setFileName(":/jquery.min.js");
    file.open(QIODevice::ReadOnly);
    jQuery = file.readAll();
    jQuery.append("\nvar qt = { 'jQuery': jQuery.noConflict(true) };");
    file.close();
					

构造函数的第二部分是创建 QWebEngineView 并将槽连接到视图的信号:

    view = new QWebEngineView(this);
    view->load(url);
    connect(view, &QWebEngineView::loadFinished, this, &MainWindow::adjustLocation);
    connect(view, &QWebEngineView::titleChanged, this, &MainWindow::adjustTitle);
    connect(view, &QWebEngineView::loadProgress, this, &MainWindow::setProgress);
    connect(view, &QWebEngineView::loadFinished, this, &MainWindow::finishLoading);
					

此外,我们创建 QLineEdit 作为浏览器的地址栏。然后设置垂直 QSizePolicy 以随时填充浏览器可用区域。添加 QLineEdit QToolBar 及一组导航动作来自 QWebEngineView::pageAction ():

    locationEdit = new QLineEdit(this);
    locationEdit->setSizePolicy(QSizePolicy::Expanding, locationEdit->sizePolicy().verticalPolicy());
    connect(locationEdit, &QLineEdit::returnPressed, this, &MainWindow::changeLocation);
    QToolBar *toolBar = addToolBar(tr("Navigation"));
    toolBar->addAction(view->pageAction(QWebEnginePage::Back));
    toolBar->addAction(view->pageAction(QWebEnginePage::Forward));
    toolBar->addAction(view->pageAction(QWebEnginePage::Reload));
    toolBar->addAction(view->pageAction(QWebEnginePage::Stop));
    toolBar->addWidget(locationEdit);
					

构造函数的第三部分是实现两个 QMenu Widget 并赋值它们一组动作:

    QMenu *viewMenu = menuBar()->addMenu(tr("&View"));
    QAction *viewSourceAction = new QAction(tr("Page Source"), this);
    connect(viewSourceAction, &QAction::triggered, this, &MainWindow::viewSource);
    viewMenu->addAction(viewSourceAction);
    QMenu *effectMenu = menuBar()->addMenu(tr("&Effect"));
    effectMenu->addAction(tr("Highlight all links"), this, &MainWindow::highlightAllLinks);
    rotateAction = new QAction(this);
    rotateAction->setIcon(style()->standardIcon(QStyle::SP_FileDialogDetailedView));
    rotateAction->setCheckable(true);
    rotateAction->setText(tr("Turn images upside down"));
    connect(rotateAction, &QAction::toggled, this, &MainWindow::rotateImages);
    effectMenu->addAction(rotateAction);
    QMenu *toolsMenu = menuBar()->addMenu(tr("&Tools"));
    toolsMenu->addAction(tr("Remove GIF images"), this, &MainWindow::removeGifImages);
    toolsMenu->addAction(tr("Remove all inline frames"), this, &MainWindow::removeInlineFrames);
    toolsMenu->addAction(tr("Remove all object elements"), this, &MainWindow::removeObjectElements);
    toolsMenu->addAction(tr("Remove all embedded elements"), this, &MainWindow::removeEmbeddedElements);
					

最后一行设置 QWebEngineView 作为中心 Widget 在 QMainWindow :

    setCentralWidget(view);
}
					

当加载页面时, adjustLocation() 被触发通过 loadFinished() 信号在 QWebEngineView 以更新地址栏:

void MainWindow::adjustLocation()
{
    locationEdit->setText(view->url().toString());
}
					

changeLocation() ,创建 QUrl 对象,然后使用它把页面加载到 QWebEngineView 。当新网页加载完成时, adjustLocation() 将再次运行以更新地址栏:

void MainWindow::changeLocation()
{
    QUrl url = QUrl::fromUserInput(locationEdit->text());
    view->load(url);
    view->setFocus();
}
					

adjustTitle() 方法设置窗口标题并显示加载进度:

void MainWindow::adjustTitle()
{
    if (progress <= 0 || progress >= 100)
        setWindowTitle(view->title());
    else
        setWindowTitle(QStringLiteral("%1 (%2%)").arg(view->title()).arg(progress));
}
void MainWindow::setProgress(int p)
{
    progress = p;
    adjustTitle();
}
					

此槽被触发通过 titleChanged() 信号在 QWebEngineView .

当网页已加载时, finishLoading() 方法被触发通过 loadFinished() 信号在 QWebEngineView 。然后,方法更新标题栏中的进度并调用 runJavaScript() 以根据当前网页评估 jQuery 库:

void MainWindow::finishLoading(bool)
{
    progress = 100;
    adjustTitle();
    view->page()->runJavaScript(jQuery);
    rotateImages(rotateAction->isChecked());
}
					

这意味着可以把 JavaScript 视为内容的一部分加载到 QWebEngineView ,因此每次加载新页面时都需要加载。一旦 jQuery 库被加载,就可以开始在浏览器中执行不同的 jQuery 函数。

rotateImages() function is then called explicitly to make sure that the images of the newly loaded page respect the state of the toggle action.

首个基于 jQuery 的函数 highlightAllLinks() ,旨在用来突出显示当前网页中的所有链接。JavaScript 代码查找 Web 元素名为 a (超链接标签)。对于每个这种元素,通过使用 CSS 把背景颜色设为黄色:

void MainWindow::highlightAllLinks()
{
    QString code = QStringLiteral("qt.jQuery('a').each( function () { qt.jQuery(this).css('background-color', 'yellow') } )");
    view->page()->runJavaScript(code);
}
					

rotateImages() 函数旋转当前网页中的图像。此 JavaScript 代码依赖 CSS 变换。它查找所有 img 元素并旋转图像 180 度,然后再次变换回来:

void MainWindow::rotateImages(bool invert)
{
    QString code;
    if (invert)
        code = QStringLiteral("qt.jQuery('img').each( function () { qt.jQuery(this).css('transition', 'transform 2s'); qt.jQuery(this).css('transform', 'rotate(180deg)') } )");
    else
        code = QStringLiteral("qt.jQuery('img').each( function () { qt.jQuery(this).css('transition', 'transform 2s'); qt.jQuery(this).css('transform', 'rotate(0deg)') } )");
    view->page()->runJavaScript(code);
}
					

剩余方法从当前网页中移除不同元素。 removeGifImages() 移除页面中的所有 GIF 图像通过查找 src 属性 (为网页中的所有元素)。任何元素采用 gif 文件作为源会被移除:

void MainWindow::removeGifImages()
{
    QString code = QStringLiteral("qt.jQuery('[src*=gif]').remove()");
    view->page()->runJavaScript(code);
}
					

removeInlineFrames() 方法移除所有 iframe 或内联元素:

void MainWindow::removeInlineFrames()
{
    QString code = QStringLiteral("qt.jQuery('iframe').remove()");
    view->page()->runJavaScript(code);
}
					

removeObjectElements() 方法移除所有 object 元素:

void MainWindow::removeObjectElements()
{
    QString code = QStringLiteral("qt.jQuery('object').remove()");
    view->page()->runJavaScript(code);
}
					

removeEmbeddedElements() 方法移除任何元素使用 embed 标签 (如嵌入在页面中的插件):

void MainWindow::removeEmbeddedElements()
{
    QString code = QStringLiteral("qt.jQuery('embed').remove()");
    view->page()->runJavaScript(code);
}
					

文件: