admin管理员组文章数量:1598599
首先你需要Qt5.6或者以上的版本才有QWebEngine这个模块, 据说5.9之前的有些bug, 所以我建议使用5.9之后的版本,
注意debug模式下QWebEngineView会很卡很占内存,反应很慢,但是release模式下响应速度很快不卡
这里给大家上一个QCefView的链接: https://cefview.github.io/QCefView/.
(1)首先你需要安装Qt
安装qt我就不多说了,大家伙随便找个博客就行, 但是QT6之后是需要版权的,也就是说商用是收费的(QT老奸巨猾,居然不开源了), 这里有个需要注意的地方,安装的时候需要安装这个几个模块才能使用QWebEngine, 直接上一张别的地方偷来的图哈, 若侵权请联系我删除, 注意了大家伙,这里有个问题哈,有可能2015版本是不带有QWebEngine模块的,所以大家伙最好安装2017(下面三个箭头的那个), 其他的按照下图勾选就可以了, 加入内存充足, 可以直接全部勾选,玩意哪天想用别的模块呢, 我之前就用了Qml模块,哈哈
(2)新建工程
新建一个工程,我这里直接新建一个大家伙照做就是
项目名称随意哈
注意我圈出来的地方,这里选中之后你才可以使用Qt设计师界面
之后一直接点下一步就可以了,
我给我创建好的目录大家伙看一下,这里的WebView文件夹是我创建用来存放html文件的地方,大家可以自由发挥,这里我在html文件的同级文件夹下放了一个qwebchannel.js文件,这个文件是QT提供的文件,用于在前端中创建webChannel()对象使用;稍后在我贴出来的HTML文件中你会看到new QWebChannel…的一段js代码
(3)下面我讲贴出所有的打代码,注意哈, 那些创建项目时候生成,并且我未做任何改动的文件我不会贴出来
(3.1)首先在创建完成项目后需要更改.Pro文件,将QWebEngineView需要的模块引入,之后创建一个pushButton,我是直接使用Qt设计师
点击.pro文件进行修改,这里主要是加载模块加载代码如下(network可加可不加,看你需不需要使用网络地址)
QT += core gui webenginewidgets webchannel network
点击UI文件到达设计师界面
进入之后拖一个pushButon到任意位置(前提是他不会被别的控件遮住,直接鼠标按住然后拖到画布上就可以了)
右键单机pushButton,然后点击转到槽
选中第一个点击的槽,然后点击ok
这个时候点击编辑,然后点击主界面文件,主语一定要点击主界面CPP文件,不然你会停在UI文件的代码便捷界面
这个时候你会发现你的主界面CPP文件中多出来一个代码块,这就是所谓的点击响应的槽函数,当然,你的函数体是空的,我这里是已经写了代码,大家不用担心
(3.2)现在你要创建一个自定义的类,类名有你自己决定我的自定义类文件如下
右键点击项目选择Add New
选择c++类
之后一直点知道出现ok为止;
我创建的类叫做WebClientBridge,一下是他的头文件和源文件内容,注释详细,大家可以读读注释免得踩坑
web_client_bridge.h
/*
* 提供给void QWebChannel::registerObject(const QString &id, QObject *object)注册的辅助类;
* 注册完成后在前端可以通过创建js端的QWebChannel对象调用到这个辅助类中的槽函数或者变量
*/
#ifndef WEB_CLIENT_BRIDGE_H
#define WEB_CLIENT_BRIDGE_H
#include <QObject>
#include <QtWebChannel>
#include <QDebug>
#include "developtool.h"
class WebClientBridge : public QObject
{
Q_OBJECT
/*
* 更在类型之后的就是你要注册的公开变量(属性)的名称
* 注册的属性名称并不一定要和要改变的成员变量名称一致,但写成一致更容易使用
*
* 注册公开变量(属性)是给js调用使用的,c++端还是使用的还是原始变量名或者直接调用相关成员函数
* 注意c++端直接使用的原始变量名更改数据前端是无法检测到更改的,若需要前端也获取到这个数据的变更,需要使用 NOTIFY 绑定信号,并在 WRITE
* 绑定的函数中主动发射这个 NOTIFY 绑定的信号,发射之后前端会自动处理这个信号并调用 READ 绑定的函数重新获取一次值,以此来完成数据同步
* 使用Q_PROPERTY宏板是不区分修饰符的(私有,公有,继承三种都是可以的),只要在当前类中有的成员变量和成员函数都可以板顶
*/
Q_PROPERTY(QString someattribute_test READ getSomeattribute_1 WRITE setSomeattribute_1 NOTIFY someattribute_1_change )
Q_PROPERTY(QString someattribute_2 READ getSomeattribute_2 WRITE setSomeattribute_2 NOTIFY someattribute_2_change)
public:
explicit WebClientBridge(QObject *parent = nullptr);
QString someattribute_1;
QString getSomeattribute_2(){
qDebug()<<"getSomeattribute_2"<<someattribute_2;
return someattribute_2;
}
void setSomeattribute_2(const QString &new_someattribute_2){
someattribute_2 = new_someattribute_2;
qDebug()<<"setSomeattribute_2"<<someattribute_2;
emit someattribute_2_change();
}
private:
//本地调试调试端口
QString str_port;
//前开发者窗口对象
DevelopTool* myDevelopTool;
QString getSomeattribute_1(){
qDebug()<<"getSomeattribute_1"<<someattribute_1;
return someattribute_1;
}
void setSomeattribute_1(const QString &new_someattribute_1){
someattribute_1 = new_someattribute_1;
qDebug()<<"setSomeattribute_1"<<someattribute_1;
emit someattribute_1_change();
}
QString someattribute_2;
public slots:
/*
* (1)前端js调用QT代码的函数,一定要写在public slots:中,注意,形参前的" const "不能被省略,
* 否则会得到以下错误:无法将参数QJsonValue(string, " sd ")转换为目标类型。
*
* (2)若是一个函数只是提供给前端修改变量的值,我们则可以不写这个函数,
* 而是直接通过宏Q_PROPERTY将变量注册为辅助类的公开变量(相当于直接注册为属性),
* 这里的公开是指js代码和c++代码都可以直接操作这个变量,并不是指3变量的修饰符public
* 例如你可以将一个private修饰的变量注册为辅助类的公开变量
*/
void openDevelopTool();//供给前端调用的打开谷歌开发者界面的接口,这个所有项目中都不用改动,只要在前端特定的情况下(例如按下某个按钮)调用就可以
void jscall(const QString &datafromjs);//测试例子
signals:
void someattribute_1_change();
void someattribute_2_change();
};
#endif // WEBCLASS_H
web_client_bridge.cpp
#include "web_client_bridge.h"
#include <qmessagebox.h>
WebClientBridge::WebClientBridge(QObject *parent) :
QObject(parent),
myDevelopTool(nullptr),
str_port("0518"),
someattribute_1("someattribute_test"),
someattribute_2(QString::fromLocal8Bit("someattribute_2_的值呀"))
{
/*
* 首先需要设置一个环境变量QTWEBENGINE_REMOTE_DEBUGGING来指定调试页面(谷歌浏览器F12打开的界面)所使用的端口号。例如,将7777端口设为调试端口,可在主窗口初始化方法的最开头添加下面的代码:
* 这个时候控制台会打印这一句话 Remote debugging server started successfully. Try pointing a Chromium-based browser to http://127.0.0.1:7777
* 这个时候你直接在浏览器上输入 http://127.0.0.1:7777 或者 http://localhost:7777 就可以进入开发者工具页面
* 当然你要是觉得这样子不舒服,那你可以再创建一个窗口显示一个web页面,但是QWebEngineView::load()中要填上 http://127.0.0.1:7777 或者 http://localhost:7777这个地址
* 这里我也进行展示下自己创建一个指定调试页面,若是要在前端通过按键打开,则需要在辅助类(WebClientBridge)提供一个给前端调用的函数,函数中就是创建一个调试界面的窗口,前端在检测到按键之后就调用即可
*/
qputenv("QTWEBENGINE_REMOTE_DEBUGGING",str_port.toStdString().c_str() );
}
//供给前端调用的打开谷歌开发者界面的接口,这个所有项目中都不用改动,只要在前端特定的情况下(例如按下某个按钮)调用就可以
void WebClientBridge::openDevelopTool()
{
qDebug()<<"openDevelopTool";
//防止创建多个DebelopTool界面
if(!myDevelopTool) myDevelopTool = new DevelopTool("http://127.0.0.1:"+str_port);
myDevelopTool->show();
}
void WebClientBridge::jscall(const QString &datafromjs)
{
QMessageBox::information(NULL, QString::fromLocal8Bit("client直接变量调用"), QString::fromLocal8Bit("c端的直接变量调用:%1").arg(someattribute_1));
qDebug()<<"someattribute_2:"+someattribute_2;
/*
* 这里使用进行了属性绑定的函数改变变量的值,在前端也能同步这个值
* 若直接写 this->someattribute_1 = "111111111111111",则前端中的对应值并未改变
* 测试流程,先点击前端中的 调用c++的按钮,此时你会发现someattribute_1的值被前端更改并打印,
* 随后查看控制台你会发现qDebug打印出来的 111111111111111,之后点击client界面上的pushButton,
* 若代码是setSomeattribute_1( "111111111111111"); 则前端弹出会有someattribute_1:111111111111111
* 若代码是this->someattribute_1 = "111111111111111";则前端弹出会有someattribute_1:xxxxxxxxx(xxxxxxxxx代表不是111111111111111的意思)
* */
setSomeattribute_1( "111111111111111");
qDebug()<<someattribute_1;
QMessageBox::information(NULL, QString::fromLocal8Bit("jscallme公开变量掉用"), QString::fromLocal8Bit("前端的公开变量调用:%1").arg(datafromjs));
}
developtool.h
/*
* 用于显示开发者工具的自定义类
* 主要是创建一个界面,界面上通过QWebEngineView将本地调试界面加载显示出来
*/
#ifndef DEVELOPTOOL_H
#define DEVELOPTOOL_H
#include <QWidget>
#include <QGridLayout>
#include "qwebengineviewplus.h"
class DevelopTool : public QWidget
{
Q_OBJECT
public:
/*参数
* DevelopTool_Url: QWebEngineView::load()需要的url参数
* parent: 父窗口指针,默认为空
*/
explicit DevelopTool(QString DevelopTool_Url,QWidget *parent = nullptr);
signals:
private:
const QString DevelopTool_Url;
QWebEngineViewPlus * m_webView ;//创建加载前端界面的对象(继承自Qt的webenginewidgets模块提供)
};
#endif // DEVELOPTOOL_H
developtool.cpp
#include "developtool.h"
DevelopTool::DevelopTool(QString DevelopTool_Url,QWidget *parent) :
QWidget(parent) ,
DevelopTool_Url(DevelopTool_Url)
{
setWindowTitle(QString::fromLocal8Bit("自定义开发者工具窗口"));
this->setMinimumSize({1000,600});//设置窗口最小大小
m_webView = new QWebEngineViewPlus(this);//创建加载前端页面的对象
m_webView->load(QUrl(this->DevelopTool_Url));//将页面加载到对象上
QGridLayout* layout = new QGridLayout(this);//创建布局方式(只有在布局上才能添加其他组件)
layout->addWidget(m_webView);//将显示web页面的窗口加载到网格布局上
this->setLayout(layout);//将布局设置到当前Qwidget上
}
qwebengineviewplus.h
/*
* 自定义类,主要是通过继承QWebEngineView重写createWindow函数从而支持链接跳转
*/
#ifndef QWEBENGINEVIEWPLUS_H
#define QWEBENGINEVIEWPLUS_H
#include <QWebEngineView>
#include <QMainWindow>
#include <qurl.h>
class QWebEngineViewPlus : public QWebEngineView
{
Q_OBJECT
public:
explicit QWebEngineViewPlus(QWidget *parent = nullptr);
private slots:
void slot_LinkHovered(const QString& url);
protected:
//这个函数应该是由底层的QWebEnginePage发起调用的,如果不想新建QWebEngineView,在这儿重写。
//由于源码中对这一块有些小bug,所以不支持点击链接跳转,这里重写就是为了支持跳转
QWebEngineView * createWindow(QWebEnginePage::WebWindowType type) override;
private:
QUrl url_;
};
#endif // QWEBENGINEVIEWPLUS_H
qwebengineviewplus.cpp
#include "qwebengineviewplus.h"
QWebEngineViewPlus::QWebEngineViewPlus(QWidget *parent):
QWebEngineView(parent)
{
setAttribute(Qt::WA_DeleteOnClose);
//当前端鼠标移动到连接上会触发这个信号,连接自定义槽函数将链接地址获取下来
connect(this->page(), &QWebEnginePage::linkHovered, this, &QWebEngineViewPlus::slot_LinkHovered);
//当加载新页面的icon时候会触发这个信号,这里刷新一遍显示icon
connect(this,&QWebEngineViewPlus::iconChanged,[=](){
this->window()->setWindowIcon(this->icon());
});
//当加载新页面的标题时候会触发这个信号,这里刷新一下标题
connect(this,&QWebEngineViewPlus::titleChanged,[=](){
this->window()->setWindowTitle(this->title());
});
}
void QWebEngineViewPlus::slot_LinkHovered(const QString &url)
{
//获取视图里面点击的链接地址
url_ = url;
}
QWebEngineView *QWebEngineViewPlus::createWindow(QWebEnginePage::WebWindowType type)
{
//加载链接地址(创建一个新的界面显示一个新的网页)
// QWebEngineViewPlus* new_QWebEngineViewPlus = new QWebEngineViewPlus();
// new_QWebEngineViewPlus->load(this->url_);
// new_QWebEngineViewPlus->show();
// return new_QWebEngineViewPlus;
//加载链接地址(不创建新的界面,显示新的网页)
Q_UNUSED(type)
//this->load(this->url_);
this->setUrl(this->url_);
return 0;
}
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QWebEngineView>
#include <QtWebChannel>
#include <QtDebug>
#include "web_client_bridge.h"
#include "qwebengineviewplus.h"
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
QWebEngineViewPlus *webView = nullptr;//创建加载前端界面的对象(继承自Qt的webenginewidgets模块提供)
QWebChannel *webChannel = nullptr;//创建qt与前端界面通信的对象(Qt的webenginewidgets模块提供)
WebClientBridge *WebClientBridge_obj;//自定义辅助类
private slots:
void on_pushButton_clicked();
private:
Ui::MainWindow *ui;
protected:
//重载窗口变化响应函数
void resizeEvent(QResizeEvent *);
};
#endif // MAINWINDOW_H
mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
/*
* 自定义辅助类,这个类的作用就是提供给QWebChannel进行注册,注册之后这个类就可以直接在前端使用,
* 注意这个一定要在QWebEngineViewPlus对象之前定义,因为这里面有设置调试界面的环境配置,若是在QWebEngineViewPlus之后定义,则会出现调试环境设置失败的问题
*/
WebClientBridge_obj = new WebClientBridge();
//初始化前端对象
webView = new QWebEngineViewPlus(this);//QT提供的类,可以将html文件显示到这个控件上
//通过文件的相对地址获取文件的绝对地址
QDir tempDir("./WebView/test.html");
QString absoluteDir = tempDir.absolutePath();
webView->load(QUrl(absoluteDir));//设置要显示的html文件(这里QUrl的地址要写绝对地址,否则渲染不出来,据说使用qrc相对地址也可以)
//webView->load(QUrl("https://baidu/"));//设置要显示的网页文件
//webView->load(QUrl("http://localhost:8080/"));//设置要显示的本地网页文件
webView->setMinimumSize(this->size());//设置QWebEngineViewPlus窗口最小大小为主窗口初始化大小
//webView->move((this->width()-webView->width())/2,(this->height()-webView->height())/2);//使QWebEngineViewPlus窗口相对于整个程序居中
webChannel = new QWebChannel;//QT提供的类,用于client与web通信的通道
webChannel->registerObject("WebClientBridge_obj", WebClientBridge_obj);//将自定义类注册到通信通道中
webView->page()->setWebChannel(webChannel);//最后一步将通信的通道设置到QWebEngineViewPlus控件上
ui->pushButton->move(100,900);
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::on_pushButton_clicked()
{
//打开开发者工具
WebClientBridge_obj->openDevelopTool();
static int count = 0;
//直接调用前端函数
webView->page()->runJavaScript(QString("showAlert(%1)").arg(++count));
}
void MainWindow::resizeEvent(QResizeEvent *)
{
//让web页面的大小始终填满整个窗口,测试on_pushButton_clicked功能时屏蔽,否则会遮住pushButton按钮
//webView->resize(this->size());
}
main.cpp
#include "mainwindow.h"
#include <QApplication>
#include <qsharedmemory.h>
int main(int argc, char *argv[])
{
QApplication::setAttribute(Qt::AA_UseOpenGLES);//解决有些电脑上html页面居然是黑屏
QApplication a(argc, argv);
QSharedMemory sigleton(a.applicationName());
if(!sigleton.create(1)) return 0; //多次启动直接退出
MainWindow w;
w.show();
return a.exec();
}
前端HTML文件,这里我只写了一个HTML文件
<!DOCTYPE html>
<html>
<head>
<script src="./qwebchannel.js">
//这里是加载Qt提供的QWebChannel的js文件,是相对地址,根据当前HTML文件与你复制的qwebchannel.js文件的相对地址得出src
</script>
<script type="text/javascript">
//捕获全局键盘事件,若将window.onkeydown改成document.onkeydown则只在当前页面捕获
window.onkeydown = function (event) {
var keyCode = event.keyCode || event.which || event.charCode;
var ctrlKey = event.ctrlKey || event.metaKey;
//捕获ctrl+F12
if (ctrlKey && keyCode == 123) {
event.preventDefault();//阻止默认事件
WebClientBridge_obj.openDevelopTool();//调用辅助类打开开发者工具
}
// event.preventDefault(); // 注意:阻止默认事件不能放在外面,会阻止浏览器或者input/textarea的默认事件,应该放在相应的按键组合中去阻止
return false;
}
function showAlert(data) {
//直接读取c++辅助类中的某个已经注册为公开变量的变量
//jsInvokeC()中修改了someattribute_test的值,这个值的修改会同步到c++客户端,所以这里读取到的值是已经修改了的值
alert("someattribute_1:" + WebClientBridge_obj.someattribute_test);
console.log(
"===============================>>>>>>>>>>>>>>",
WebClientBridge_obj.someattribute_test
);
alert("someattribute_2:" + data + WebClientBridge_obj.someattribute_2);
}
var data = 0;
function jsInvokeC() {
//直接修改c++辅助类中的某个已经注册为公开变量的变量
WebClientBridge_obj.someattribute_test = "someattribute_1的值_" + data + "_test"
//读取修改后的值并调用辅助类的public slots:修饰的槽函数,将数据传给c++客户端
WebClientBridge_obj.jscall(data++ + WebClientBridge_obj.someattribute_test);
}
// QT交互,创建一个QWebChannel对象,并将c++中注册带辅助类加载到前端
//需要将qwebchannel.js这个js文件引入到创建QWebChannel对象的文件中,qwebchannel.js定义了QWebChannel对象
//qwebchannel.js是Qt的WebEngine模块提供的,在qt安装目录下搜索就能找到这个文件(前提是安装qt的时候安装了WebEngine模块)
new QWebChannel(qt.webChannelTransport,
function (channel) {
//这里的window.WebClientBridge_obj是自己定义的一个名称,可以随便取
//这行代码相当于在前端js和客户端c++进行关联,关联完毕后就可以调用到注册的辅助类的数据和方法
window.WebClientBridge_obj = channel.objects.WebClientBridge_obj;
});
</script>
</head>
<body>
<div>
<input type="button" value="调用c++" onclick="jsInvokeC()" style="background-color: aqua;">
</div>
</body>
</html>
其他相关文章(转载其他人的连接):链接: https://blog.csdn/hitzsf/article/details/109279003.
链接: https://blog.csdn/hitzsf/article/details/109278967.
链接: https://www.jianshu/p/e4ec0ab2f999.
本文标签: QTQWebEngineViewhtml
版权声明:本文标题:Qt使用QWebEngineView渲染HTML 内容由热心网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:https://m.elefans.com/dianzi/1728286982a1152293.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论