一、Qt WebEngine基本概念
Qt WebEngine中主要分为三个模块:Qt WebEngine Widgets模块,主要用于创建基于C++ Widgets部件的Web程序;Qt WebEngine模块用来创建基于Qt Quick的Web程序;Qt WebEngine Core模块用来与Chromeium交互。网页玄幻和JavaScript的执行从GUI进程分离到Qt WebEngine进程,主要架构如下。

二、Qt WebEngine Widgets
本文主要关注Qt WebEngine Widgets模块,其架构如下。QWebEngineView是主要窗体类组件,用来加载Web。QWebEnginePage包含在QWebEngineView中,主要包含了Web页面的主框架,负责内容分、浏览历史QWebEngineHistory等。配置QWebEngineProfile用于区分不同的Page,属于同一个Web引擎配置的所有网页共享设置Settings、脚本Script和Cookies。

三、一个简易的浏览器
重写QWebenginePage的acceptNavigationRequest进行导航设置,没有特殊需求可只用用基类。
cpp
class CustomWebEnginePage : public QWebEnginePage {
Q_OBJECT
public:
CustomWebEnginePage(QObject *parent = nullptr) : QWebEnginePage(parent) {}
bool acceptNavigationRequest(const QUrl &url, NavigationType type, bool isMainFrame) override {
if (type == QWebEnginePage::NavigationTypeLinkClicked && isMainFrame) {
load(url); // 允许在当前页面打开新链接
return false; // 阻止默认打开新窗口的行为
}
return QWebEnginePage::acceptNavigationRequest(url, type, isMainFrame);
}
};
浏览器页面实现细节:
cpp
void Test2015::TestWebEngineWidget()
{
if (ui.frameWeb)
{
auto& pParent = ui.webEngineView;
auto& pWebView = ui.webEngineView;
//pWebView->setPage(new CustomWebEnginePage(pWebView));
pWebView->load(QUrl("https://blog.csdn.net/WSTONECH?type=blog"));
QWebEngineSettings::globalSettings()->setAttribute(QWebEngineSettings::JavascriptEnabled, true);
pWebView->settings()->setAttribute(QWebEngineSettings::JavascriptEnabled, true);
pWebView->settings()->setAttribute(QWebEngineSettings::LinksIncludedInFocusChain, true);
//工具栏
urlEdit = new QLineEdit(pParent);
backButton = new QPushButton("Back", pParent);
forwardButton = new QPushButton("Forward", pParent);
refreshButton = new QPushButton("Refresh", pParent);
goButton = new QPushButton("Go", pParent);
favBtn = new QPushButton("收藏", pParent);
QHBoxLayout *toolbarLayout = new QHBoxLayout(ui.frameToolBar);
toolbarLayout->addWidget(backButton);
toolbarLayout->addWidget(forwardButton);
toolbarLayout->addWidget(refreshButton);
toolbarLayout->addWidget(urlEdit);
toolbarLayout->addWidget(goButton);
toolbarLayout->addWidget(favBtn);
//历史记录ListView
historyModel = new QStringListModel(pParent);
ui.listView_History->setModel(historyModel);
//进度条
ui.progressBar->setMaximum(100);
ui.progressBar->setVisible(false);
//
connect(urlEdit, &QLineEdit::returnPressed, [=]() {
QString urlStr = urlEdit->text().trimmed();
QUrl url = urlStr.startsWith("http") ? QUrl(urlStr) : QUrl("https://" + urlStr);
if (url.isValid()) {
pWebView->setUrl(url);
}
});
connect(pWebView->page(), &QWebEnginePage::urlChanged, urlEdit, [=](QUrl url) {
urlEdit->setText(url.toString());
});
//进度条更新
connect(pWebView, &QWebEngineView::loadProgress, this, [=](int progressValue) {
if (progressValue == 100) {
ui.progressBar->setVisible(false);
}
else {
ui.progressBar->setVisible(true);
ui.progressBar->setValue(progressValue);
}});
//更新历史地址 页面加载完成在记录历史地址防止未完全加载title等无法解析
connect(pWebView, &QWebEngineView::loadFinished, this, [=](bool ok) {
if (ok)
{
historyUrls.clear();
QList<QWebEngineHistoryItem> items = pWebView->history()->items();
for (const QWebEngineHistoryItem& item : items) {
if (item.isValid() && (item.url().toString() != "about:blank"))
{
string title = item.title().toStdString();
string urlstr = item.url().toString().toStdString();
historyUrls.append(item.title() + " - " + item.url().toString());
}
}
historyModel->setStringList(historyUrls);
}
});
//
connect(ui.listView_History->selectionModel(), &QItemSelectionModel::currentChanged,
this, [=](const QModelIndex& index) {
if (!index.isValid()) return;
QList<QWebEngineHistoryItem> items = pWebView->history()->items();
if (index.row() >= 0 && index.row() < items.size()) {
pWebView->load(items[index.row()].url());
}
});
connect(favBtn, &QPushButton::clicked, this, [=]() {
QString url = pWebView->url().toString();
});
connect(backButton, &QPushButton::clicked, this, [=]() {
if (pWebView->page()->history()->canGoBack()) {
pWebView->back();
}
});
connect(forwardButton, &QPushButton::clicked, this, [=]() {
if (pWebView->page()->history()->canGoForward()) {
pWebView->forward();
}
});
connect(refreshButton, &QPushButton::clicked, pWebView, &QWebEngineView::reload);
connect(goButton, &QPushButton::clicked, this, [=]() {
QString input = urlEdit->text();
QUrl url;
if (input.startsWith("http://") || input.startsWith("https://")) {
url = QUrl(input);
}
else {
url = QUrl("https://" + input);
}
if (url.isValid()) {
pWebView->setUrl(url);
}
});
}
}
实现效果