1.主要目标
-
用最简单的代码实例相互通信
-
JS调用C++代码
-
C++调用JS代码
-
-
利用QWebView渲染出png图片
2.介绍项目的情况
在项目中只要用到了浏览器组件,不关你是libcef,QWebEngine,QWebView,都少不了和前端通信的需求。
在QWebView中做到这些都是很简单的事情,通常也是几行代码的时候。但是也有点小坑要绕着走。
1.新建一个项目
使用QtCreator新建一个Widget项目的过程,我就省略了啊。里面自动帮我们创建一个widget.ui文件
我们直接在从designer的设计器里面,放一个QWebView控件和一个按钮(测试调用JS代码)
效果图如下:
这是加载了百度
之后的样式
2.代码实例
1.准备html文件
为了演示效果,我自己手写了一个简单的html文件。
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>FLOT DEMO</title>
<script LANGUAGE="JavaScript">
function jsFun(parameter)
{
alert(parameter)
return "jsFun result"
}
function clickButton()
{
Widget.doSomething('abc')
}
</script>
</head>
<body>
<button type="button" onclick="clickButton()">Click Me!</button>
<p>test html</p>
</body>
</html>
我把这个文件放到了qrc资源里面去加载。
效果图如下:
2.调用js代码
void Widget::CallJsFunction()
{
ui->webView->page()->mainFrame()->evaluateJavaScript("jsFun(\"json format data\")");
}
一行代码就调用了js代码
这里我就简单的解释下evaluateJavaScript(const QString & scriptSource)
函数。
这个函数里面传递的参数从字面的意思上看就是你要执行的js代码。这是其一,我在测试的过程中发现其实它也可以传递js的函数名和参数。我在测试的时候就是这样用的。
点击Test call js
弹出的是JS的提示。
3.调用C++代码
在调用C++的代码需要麻烦点,但是也没有多麻烦。跟我一起试下。
1.注册我们自己的对象
我们需要自己注册一个对象进去。不要慌,也没有几行代码。
// 1.首先链接一个信号
connect(ui->webView->page()->mainFrame(), SIGNAL(javaScriptWindowObjectCleared()), this, SLOT(OnJavaScriptWindowObjectCleared()));
// 2.信号处理函数
void Widget::OnJavaScriptWindowObjectCleared()
{
ui->webView->page()->mainFrame()->addToJavaScriptWindowObject("Widget", new MyObject());
}
// 3.MyObject对象声明
class MyObject : public QObject {
Q_OBJECT
public slots:
void doSomething(const QString &data)
{
QMessageBox::information(nullptr, tr("From web call"), data, QMessageBox::Ok);
}
};
2.html里面调用
function clickButton()
{
Widget.doSomething('abc')
}
这个是Button的点击响应事件,里面用的Widget就是我们自己注册的。doSomething()
就是调用了MyObject的成员函数。
效果图如下:
我们稍微总结下:
根据信号触发注册自定义的对象。
JS段根据自定义的对象调用成员函数
嘿嘿,看起来还是很简单的。就是给我的感觉这种方式挺神奇的。有机会深挖下原理。
3.生成png图片
// 绑定页面加载完成的信号
connect(ui->webView, SIGNAL(loadFinished(bool)), this, SLOT(OnLoadFinished(bool)));
void Widget::OnLoadFinished(bool result)
{
QString strUrl = ui->webView->url().toDisplayString();
// render image
if (result) {
renderImage();
}
else{
qDebug() << "load error";
}
}
// 渲染图片的方法
bool Widget::renderImage()
{
// 获取当前页面的大小
QSize contentSize = ui->webView->page()->mainFrame()->contentsSize();
// 声明一张图片大小和页面一样大
QImage image = QImage(contentSize, QImage::Format_RGB32);
// 设置page的可视窗口大小和页面的一样
ui->webView->page()->setViewportSize(contentSize);
QPainter painter(&image);
// 绘制到painter上
ui->webView->page()->mainFrame()->render(&painter);
painter.end();
// 保存
image.save("D:\\test_web_render.png");
return true;
}
上面的代码我做了详细的注释,就不再介绍了。
我尝试了百度
效果图如下:
3.介绍QWebView的知识
刚才我相信大家基本骑了下自行车,快速的实践一遍。
这里我简单的介绍下QWebView的知识。我其实懂得不多,也是从官方的文档中学习的。
1.关系图
这张图从文档中截出来的,我觉得很简单的,一下子就介绍了几个class的关系。
2.注册对象
根据官方的文档介绍,我们在注册js对象的时候,要先连接javaScriptWindowObjectCleared()
信号,再去注册对象。
因为在这里对象已经被全部清除,确保在加载新的地址时候,你的对象会被注册进去。否则加载的时机不对,你的对象就算加载进去,在加载新的URL可能会被清空。
## 4.总结
最后,总结下我遇到的问题。
* 在使用QWebView的时候一定要注意版本,为什么?因为QWebView这个组件使用的内核版本是非常低的,有可能新的特性它并不支持。
* 在加载https的时候,页面无法加载,通过查看错误信息发现,需要把两个dll`libeay32.dll ssleay32.dll`放到你的exe运行目录下。
* 使用file协议加载页面的时候需要使用绝对路径。我是查了RFC文档说明,file协议不支持相对路径。
* 渲染图片的时候,QWebView有时候获取的页面大小不对。我采取的做法是让前端调用我的接口返回正确的页面大小。
关于更多的QWebView,大家在遇到的时候再去查文档也不迟。
https://gitee.com/liushixiong/study-qt