第21章 Qt WebEngine

从Qt 5.5开始,Qt WebKit模块被废弃,取而代之的是Qt WebEngine模块。Qt WebEngine模块提供了一个Web浏览器引擎,可以很容易地将万维网(World Wide Web)中的内容嵌入到Qt应用程序中。因为Qt WebEngine模块是基于Google Chromium项目的,而Chromium现在并不支持使用MinGW进行构建,在Windows平台上需要使用VS 2017以上版本进行构建。所以,要想在Windows平台使用Qt WebEngine模块,需要安装MSVC版本的Qt。

21.1 Qt WebEngine架构

21.1.1 Qt WebEngine

Qt WebEngine中的功能被划分到了3个不同的模块:

1)Qt WebEngine Widgets模块用来创建基于C++ Widgets部件的Web程序;

2)Qt WebEngine模块用来创建基于Qt Quick的Web程序;

3)Qt WebEngine Core模块用来与Chromium交互。

21.1.2 Qt WebEngine Widgets模块

  1. 视图View(QWebEngineView)是模块中的主要窗体类组件,可以用在各种应用中加载Web内容。
  2. 页面Page(QWebEnginePage)包含在View中,它包含了Web页面的主框架,主要负责Web内容、浏览历史History(QWebEngineHistory)和菜单动作Action。View与Page十分相似,它们提供了一组相同的函数。
  3. 配置Profile(QWebEngineProfile)用于区分不同的Page,属于同一个Web引擎配置的所有网页都会共享设置Settings、脚本Script和Cookies。

21.2 基于Qt WebEngine Widgets的网页浏览器

下面是一个简单的网页浏览器的例子,包含了如下功能:

  1. 最基本的网页显示
  2. 导航菜单
  3. 显示网站图标
  4. 提供历史记录
  5. 字符串查找

21.2.1 显示一个网页

  1. 初始化
cpp 复制代码
view = new QWebEngineView(this);
view->load(QUrl("https://www.qter.org/"));
setCentralWidget(view);
resize(1024, 680);

// 关联信号和槽
connect(view, &QWebEngineView::loadProgress, this, &MainWindow::setProgress);
connect(view, &QWebEngineView::titleChanged, this, &MainWindow::adjustTitle);
connect(view, &QWebEngineView::loadFinished, this, &MainWindow::finishLoading);

locationEdit = new QLineEdit(this);
locationEdit->setText("https://www.qter.org/");
connect(locationEdit, &QLineEdit::returnPressed, this, &MainWindow::changeLocation);
  1. 在行编辑器中改变站点地址后按下回车键执行的槽:
cpp 复制代码
void MainWindow::changeLocation()
{
    QUrl url = QUrl(locationEdit->text());
    view->load(url);
    view->setFocus();
}
  1. 更新加载进度槽的实现:
cpp 复制代码
void MainWindow::setProgress(int p)
{
    progress = p;
    adjustTitle();
}
  1. 调整标题槽:
cpp 复制代码
void MainWindow::adjustTitle()
{
    if ( progress <= 0 || progress >= 100) {
        setWindowTitle(view->title());
    } else {
        setWindowTitle(QString("%1 (%2%)").arg(view->title()).arg(progress));
    }
}
  1. 完成加载后的处理槽的实现:
cpp 复制代码
void MainWindow::finishLoading(bool finished)
{
    if (finished) {
        progress = 100;
        setWindowTitle(view->title());
    } else {
        setWindowTitle("web page loading error!");
    }
}

21.2.2 网站图标

  1. 每一个网站都有一个Logo图标,即所谓的FavIcons,它一般显示在网站标题的前面。可以使用QWebEngineView的iconUrl()函数返回该图标的url,然后使用网络访问接口类来获取图标文件。
cpp 复制代码
connect(view, &QWebEngineView::iconUrlChanged, this, &MainWindow::handleIconUrlChanged);
manager = new QNetworkAccessManager(this);
  1. 每当加载的网站图标发生变化时,QWebEngineView都会发射iconUrlChanged()信号,这里关联该信号来获取新的图标的url:
cpp 复制代码
void MainWindow::handleIconUrlChanged(const QUrl &url)
{
    QNetworkRequest iconRequest(url);
    QNetworkReply *iconReply = manager->get(iconRequest);
    iconReply->setParent(this);
    connect(iconReply, &QNetworkReply::finished, this, &MainWindow::handleIconLoaded);
}
  1. 当从信号获取图标的url以后,通过QNetworkAccessManager调用get()函数来获取图标文件,当获取结束后,调用handleIconLoaded()槽来对文件进行处理:
cpp 复制代码
void MainWindow::handleIconLoaded()
{
    QIcon icon;
    QNetworkReply *iconReply = qobject_cast<QNetworkReply*>(sender());
    if (iconReply && iconReply->error() == QNetworkReply::NoError) {
        QByteArray data = iconReply->readAll();
        QPixmap pixmap;
        pixmap.loadFromData(data);
        icon.addPixmap(pixmap);
        iconReply->deleteLater();
    } else {
        icon = QIcon(QStringLiteral("../mywebengine/defaulticon.png"));
    }
    setWindowIcon(icon);
}

21.2.3 实现网页缩放

cpp 复制代码
QAction *zoomIn = new QAction(tr("放大"));
zoomIn->setShortcut(QKeySequence(Qt::CTRL | Qt::Key_Plus));
connect(zoomIn, &QAction::triggered, this, [=]() {
    view->setZoomFactor(view->zoomFactor() + 0.1);
    ui->statusbar->showMessage(tr("缩放%1%").arg(view->zoomFactor()*100));
});
QAction *zoomOut = new QAction(tr("缩小"));
... ...
QAction *resetZoom = new QAction(tr("重置"));
... ...
ui->mainToolBar->addAction(zoomIn);
ui->mainToolBar->addAction(zoomOut);
ui->mainToolBar->addAction(resetZoom);

21.2.4 显示历史记录

一般浏览器都支持显示浏览过的网页的历史记录,在Qt WebEngine Widgets模块中,QWebEngineHistory类用来表示QWebEnginePage的浏览历史。

  1. 构造函数中添加代码:
cpp 复制代码
ui->mainToolBar->addAction(tr("历史"), this, SLOT(showHistory()));
historyList = new QListWidget;
historyList->setWindowTitle(tr("历史记录"));
historyList->setMinimumWidth(300);
connect(historyList, &QListWidget::clicked, this, &MainWindow::gotoHistory); 
  1. 显示历史记录窗口的槽的定义:
cpp 复制代码
void MainWindow::showHistory()
{
    historyList->clear();
    const auto list = view->history()->items();
    for (const QWebEngineHistoryItem &item : list) {
        QListWidgetItem *history = new QListWidgetItem(item.title());
        historyList->addItem(history);
    }
    historyList->show();
}
  1. 单击历史记录项目的槽的实现:
cpp 复制代码
void MainWindow::gotoHistory(const QModelIndex &index)
{
    QWebEngineHistoryItem item = view->history()->itemAt(index.row());
    view->history()->goToItem(item);
}

21.2.5 查找功能

  1. QWebEngineView中还提供了findText()函数来实现网页中字符串的查找和高亮显示,默认是向前查找而且不区分大小写,可以通过设置第2个参数QWebEnginePage::FindFlags修改为向后查找(QWebEnginePage::FindBackward)或者区分大小写(QWebEnginePage::FindCaseSensitively)。

  2. 构造函数后面添加如下代码:

cpp 复制代码
findEdit = new QLineEdit(this);
findEdit->setMaximumWidth(150);
ui->mainToolBar->addWidget(findEdit);
ui->mainToolBar->addAction(tr("查找"), [this]() {
    view->findText(findEdit->text());
});

21.2.6 多窗口显示

  1. 有些网页中的链接需要打开一个新窗口显示,要实现这个功能需要子类化QWebEngineView,然后重新实现其中的createWindow()函数,并在其中创建一个新的窗口。
  2. 在项目中添加新的C++类,类名为WebView,基类设置为QWebEngineView。
  3. webview.h内容如下:
cpp 复制代码
#ifndef WEBVIEW_H
#define WEBVIEW_H

#include <QWebEngineView>
class MainWindow;
class WebView : public QWebEngineView
{
    Q_OBJECT
public:
    WebView(QWidget *parent = nullptr);
protected:
    QWebEngineView *createWindow(QWebEnginePage::WebWindowType type) override;
private:
    MainWindow *mainWindow;
};
#endif // WEBVIEW_H
  1. webview.cpp文件内容如下:
cpp 复制代码
#include "webview.h"
#include "mainwindow.h"

WebView::WebView(QWidget *parent)
    : QWebEngineView(parent)
{
}

QWebEngineView *WebView::createWindow(QWebEnginePage::WebWindowType type)
{
    mainWindow = new MainWindow(this);
    mainWindow->show();
    return mainWindow->createView();
}
  1. 到mainwindow.h文件中将以前的QWebEngineView类的前置声明: class QWebEngineView;

    修改为WebView的前置声明:class WebView;

  2. 然后在public中添加createView()函数的声明:WebView *createView();

  3. 将对象声明:QWebEngineView *view; 修改为:WebView *view;

  4. 到mainwindow.cpp文件中先添加头文件包含#include "webview.h",然后将构造函数中创建view对象的代码:

    view = new QWebEngineView(this); 修改为:view = new WebView(this);

  5. 下面添加createView()函数的定义:

cpp 复制代码
WebView *MainWindow::createView()
{
    return view;
}
相关推荐
码农-阿杰2 小时前
深入理解 synchronized 底层实现:从 HotSpot C++ 源码看对象锁与 Monitor 机制
开发语言·c++·
2401_832298102 小时前
AI智能体监管落地,OpenClaw率先建立行业合规标准
开发语言
Szime2 小时前
深智微IC华润微代理:MCU选型与工业控制方案推荐
c++
geovindu2 小时前
go: Lock/Mutex Pattern
开发语言·后端·设计模式·golang·互斥锁模式
知识分享小能手2 小时前
R语言入门学习教程,从入门到精通,R语言日期和时间序列(6)
开发语言·学习·r语言
叼烟扛炮3 小时前
C++ 知识点18 内部类
开发语言·c++·算法·内部类
汉克老师3 小时前
GESP5级C++考试语法知识(十五、分治算法(二))
c++·算法·排序算法·分治算法·gesp5级·gesp五级
TAN-90°-3 小时前
Java 3——getter和setter super()关键字
java·开发语言
wand codemonkey3 小时前
(二十七)Maven(依赖)【安装】+【项目结构】
java·开发语言·maven