支持访问网页,前进、后退、刷新,点击超链接自动跳转,获取网页鼠标事件,重新编译QWebEngineView库后还可以支持播放mp4等视频;
Qt在debug模式运行有时访问网页很卡,切换release版后访问速度基本正常。
环境说明
使用QWebEngineView类实现,qt5.6及以上版本;
qt安装时需要勾选:Qt WebEngine;
由于chrome不支持mingw编译,构建套件只能选择vs的编译器;
pro工程文件添加QT += webenginewidgets
源代码
重写QWebEngineView类,主要实现两个功能:
1、QWebEngineView不支持点击超链接自动跳转,对createWindow处理后可支持跳转;
2、QWebEngineView浏览web时鼠标事件被本身的child接收了,因此浏览网页时获取不了qt的鼠标事件,这里通过QEvent::ChildPolished安装事件过滤器的方式获取鼠标事件。
qwebengineviewchw.h
#ifndef QWEBENGINEVIEWCHW_H
#define QWEBENGINEVIEWCHW_H
#include <QWidget>
#include <QWebEngineView>
#include <qwebenginepage.h>
#include <qurl.h>
#include <QMouseEvent>
#include <QApplication>
class QWebEngineViewChw : public QWebEngineView
{
Q_OBJECT
public:
explicit QWebEngineViewChw(QWidget *parent = nullptr);
~QWebEngineViewChw()override;
protected:
QWebEngineView* createWindow(QWebEnginePage::WebWindowType type) override;
private slots:
void slot_LinkHovered(const QString& url);
private:
QUrl url_;
QVector<QObject * > mvchildObj;
protected:
bool event(QEvent* evt)override;
bool eventFilter(QObject *obj, QEvent *ev)override;
};
#endif // QWEBENGINEVIEWCHW_H
qwebengineviewchw.cpp
#include "qwebengineviewchw.h"
QWebEngineViewChw::QWebEngineViewChw(QWidget *parent) : QWebEngineView(parent)
{
setAttribute(Qt::WA_DeleteOnClose);
connect(this->page(), &QWebEnginePage::linkHovered, this, &QWebEngineViewChw::slot_LinkHovered);
}
QWebEngineViewChw::~QWebEngineViewChw()
{
}
QWebEngineView *QWebEngineViewChw::createWindow(QWebEnginePage::WebWindowType type)
{
//加载链接地址
if(!url_.isEmpty())
{
this->load(url_);
emit QEvent::ChildPolished;//重新加载页面时,手动触发一个ChildPolished事件
}
// return this;
return nullptr;
}
void QWebEngineViewChw::slot_LinkHovered(const QString &url)
{
//获取视图里面点击的链接地址
// qDebug()<<"["<<__FILE__<<"]"<<__LINE__<<__FUNCTION__<<" "<<url;
url_.setUrl(url);
}
bool QWebEngineViewChw::event(QEvent *evt)
{
//每次新加载URL时手动触发该事件,生成一个QChildEvent
if (evt->type() == QEvent::ChildPolished)
{
qDebug()<<"["<<__FILE__<<"]"<<__LINE__<<__FUNCTION__<<" ";
QChildEvent *child_ev = static_cast<QChildEvent*>(evt);
QObject *childObj = child_ev->child();
mvchildObj.append(childObj);
if (childObj)
{
childObj->installEventFilter(this);
}
}
return QWebEngineView::event(evt);
}
bool QWebEngineViewChw::eventFilter(QObject *obj, QEvent *ev)
{
foreach(QObject *childObj,mvchildObj)
{
if (obj == childObj)
{
if (/*obj == childObj&& */(ev->type() == QEvent::MouseButtonPress|| ev->type() == QEvent::MouseButtonDblClick))
{
QMouseEvent *MouseEvent = static_cast<QMouseEvent *>(ev);
int x = MouseEvent->x();
int y = MouseEvent->y();
qDebug()<<"["<<__FILE__<<"]"<<__LINE__<<__FUNCTION__<<" "<<x <<y;
return QWebEngineView::eventFilter(obj, ev);
}
}
}
return QWebEngineView::eventFilter(obj, ev);
}
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QWebEngineView>
#include "qwebengineviewchw.h"
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
private slots:
void on_pushButton_clicked();//访问
void on_pushButton_2_clicked();//刷新
void on_pushButton_back_clicked();//后退
void on_pushButton_forward_clicked();//前进
private:
Ui::MainWindow *ui;
QWebEngineViewChw *m_webView;
};
#endif // MAINWINDOW_H
mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QNetworkProxyFactory>
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
this->setWindowTitle(QStringLiteral("QWebEngineView浏览器"));
// qputenv("QTWEBENGINE_REMOTE_DEBUGGING", "7777");
QNetworkProxyFactory::setUseSystemConfiguration(false);
m_webView = new QWebEngineViewChw(this);
ui->verticalLayout->addWidget(m_webView);
}
MainWindow::~MainWindow()
{
delete ui;
}
//访问
void MainWindow::on_pushButton_clicked()
{
QString url = ui->lineEdit->text();
if (!url.isEmpty())
{
m_webView->load(url);
}
}
//刷新
void MainWindow::on_pushButton_2_clicked()
{
m_webView->reload();
}
//后退
void MainWindow::on_pushButton_back_clicked()
{
m_webView->back();
}
//前进
void MainWindow::on_pushButton_forward_clicked()
{
m_webView->forward();
}
效果图
QWebEngineView缺点和优点
1、由于QWebEngineView没有视频解码器,无法播放mp4等视频,需要重新编译QWebEngineView库,编译过程比较复杂不建议自己尝试,可以在网上下载别人编译好的,编译库和使用库的qt版本、vs版本、位数等要保持一致;
2、点击链接不跳转,重写QWebEngineView类,自动识别鼠标放在链接上面的URL地址,但有些网页链接鼠标放上不显示URL地址,这种情况无法跳转,存在一定BUG;
总结一下:简单的浏览器可以使用QWebEngineView,比较容易实现,但是稳定性和兼容性差一些,后续会研究CEF(Chromium嵌入式框架) ,并嵌入到qt程序实现浏览器功能。