Qt vs2022使用QCefView控件与html通信
Posted cpp_learners
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Qt vs2022使用QCefView控件与html通信相关的知识,希望对你有一定的参考价值。
此前,主管让我调研cef3的使用,但是cef3比较复杂,太难理解了;偶然间,在网上看到有QT第三方库QCefView,这个库封装了cef3,使得可以很简单的在桌面应用加载显示html,并与其进行通信;经过几天的调研,现在将调研结果记录下来!
目录
前言
-
QCefView是什么?
QCefView是为Qt框架开发的一个封装集成了Chromium Embedded Framework库的Wdiget UI组件。使用QCefView可以充分发挥CEF丰富强大的Web能力,快速开发混合架构的应用程序。使用Qt开发者熟悉的Forms,signal/slot来开发应用
方便直观的javascript/C++互操作方式 -
为何选择QCefView而不用Electron?
从设计思路和最终形态来讲QCefView和Electron是完全不同的技术。QCefView只是一个为Qt框架开发的UI组件,Electron则是一个功能完备的应用开发框架
QCefView是为Native系统开发者设计的,Electron对前端开发者更友好
QCefView使用C++作为主要开发语言,Electron全部基于Javascript
QCefView提供便捷直观的Javascript/C++互操作方式,Electron通过编写插件实现Web/Native互操作 -
QCefView适合开发何种类型的应用?
如果你打算使用Web前端技术来开发你的应用UI,同时保持使用Native方式编写核心业务/功能逻辑,QCefView是最佳选择。例如:
音乐/视频播放器
游戏平台
工具类应用
等等……
以上场景中的应用几乎都是基于内容的平台,他们都需要展示很多列表,表格或者有各种复杂特效的页面。基于此种目的,Web前端技术是目前的最好的选择,把UI当作Web前端App来开发,而核心的功能和逻辑仍然使用Native的方式来编写,然后通过QCefView整合,能极大的提升生产效率,并且一份UI代码适配所有主流桌面平台。
如果你打算开发一款浏览器,QCefView并不是较好的选择,因为QCefView设计的目的是UI组件,并不提供作为浏览器的全部特性,该类需求应该使用原生CEF来实现较好。
上面内容出自QCefView官网
官网链接:https://cefview.github.io/QCefView/
一、编译QCefView
注意:Window环境编译QCefView依赖VS2019或VS2022 和 QT6以上版本,还有CMake!
官网:https://cefview.github.io/QCefView/zh/docs/intros
-
下载最新源码
-
下载解压后
将CefViewCode-main中的全部文件拷贝到QCefView-main/CefViewCode 目录下:
在 QCefView-main 路径下新建文件夹build -
编辑QCefView-main 路径下的QtConfig.cmake文件
在这里写上自己的QT安装路径
建议是QT6以上的版本! -
设置QT6的环境变量
-
下载安装CMake
下载链接:https://cmake.org/download/
下载后安装即可,这里就不再缀叙安装过程! -
打开CMake
根据下图步骤进行编译!
插入小道消息-------------------------------------------------------------------------------------------------------------如果网络不好,网上说可以自行下载一个cef版本,然后将cef拷贝到路径/QCefView-main/CefViewCore/dep,然后去下图二文件中进行修改一些操作,CMake编译就不用下载了,具体我没有操作成功!
cef官网:https://cef-builds.spotifycdn.com/index.html
小道消息结束-------------------------------------------------------------------------------------------------------------下面接着开始下载的步骤,下图显示的是已经将cef下载完毕并解压好了的
在路径/QCefView-main/CefViewCore/dep下,有CMake帮我们下载的CEF包 -
编译VS工程
在build目录下有一个VS工程,使用VS2022打开它
根据自己的需求设置好后右键ALL_BUILD,选择重新生成
编译成功如下图:
-
查看编译好的库
路径中多出了个output路径
lib目录存放的就是我们需要的QCefView.lib;
bin目录存放的是项目运行需要的动态库等文件!
至此,QCefView已经编译完毕!
二、插曲
有些朋友的项目可能需要使用到Curl,并且,curl得带有openssl,否则无法使用https;请按照下面步骤进行编译!不需要可跳过此步骤!
1). 安装OpenSSL
下载和安装
下载其他人做的便捷版安装包
下载链接:http://slproweb.com/products/Win32OpenSSL.html
下载后安装, 一直狂点下一步就行了。
安装时如果你没有修改安装路径,默认是安装在:C:\\Program Files\\OpenSSL-Win64
设置一下环境变量
查看安装版本
OpenSSL安装完毕!
2). 编译Curl
注意:编译带有openssl的curl库,编译Debug失败,编译Release成功!
下载地址:https://curl.se/download.html
不知为何,这里只有Release版本的下载,所以我们待会编译带有openssl的curl库时也只能编译Release的库,编译Debug的库会失败!
当然,如果只是编译curl没有包含openssl的话,debug的库貌似是可以编得过的!
-
下载后解压打开
在下图路径中,有很多个版本,具体看下图
使用VS2022打开
-
选择 DLL Release – DLL OpenSSL 和 x64
如果编译带有openssl的curl库,这里一定要选择 DLL Release – DLL OpenSSL ,否则会编译失败!
-
包含openssl的库文件
如果只是需要使用curl的http,而不需要使用https,那么,编译也就不需要带有openssl,可以直接跳到下方第4步骤进行编译;当然,在第二步骤需要选择,DLL Debug或者DLL Release项进行编译即可!A. 右键libcurl - 属性 - VC++目录 - 包含目录
添安装的OPenSSL库的头文件路径进来
C:\\Program Files\\OpenSSL-Win64\\include
B. VC++目录 - 库目录
将安装的OPenSSL库的lib添加进来
C:\\Program Files\\OpenSSL-Win64\\lib
C. 链接器 - 输入 - 附加依赖项
一般来说默认会给我们添加上了这些lib,如果没有请手动打上
-
编译
右键curl,选择重新生成
编译成功如下图:
-
查看编译好的库
进入下图路径,就会有编译好的带openssl的curl库了
至此,Curl编译完毕!
另外,如果编译的是带有openssl的curl库,那么此库应该是Release版本的;如果此库需要和QCefView结合一起使用,得将QCefView库也编译成Release版本的才可以一起使用,否则会编译报错!
三、案例
下面将根据本人写的一个小案例进行讲解代码知识点。此案例是QT使用QCefView显示html,并与之进行通信,互相发送消息!
具体案例代码放在下面总结处,有需要的可以去下载!
案例运行截图:
上方显示的是html页面
下方显示的是QT页面
当然,也可以直接整个窗体都进行显示html页面,具体根据自己的需求来就好!
因为我对HTML不熟悉,所以搞得html显示的有点奇怪,但不影响我们立即如何使用。
ui布局如下:
根据自己的需求来布局就可以了!
1 HTML代码
1). html代码
文件名:QCefViewTest.html
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Login</title>
<link rel="stylesheet" type="text/css" href="Login.css"/>
</head>
<body onload="onLoad()" id="main" class="noselect">
<div id="login">
<form method="post">
<input id="account" type="text" required="required" placeholder="请输入" name="u"></input>
<button id="loginBtn" class="but" type="button" onclick="onCallBridgeQueryClicked('html')">发送</button>
<textarea id="output" type="text" required="required" placeholder="内容" name="t"></textarea>
</form>
<button id="loginBtn" class="but" type="button" onclick="onInvokeMethodClicked('message1', '标题', '这是message1', 'a', 1.1)">Message1</button>
<button id="loginBtn" class="but" type="button" onclick="onInvokeMethodClicked('message2', '标题', '这是message2', 'B', 2.2)">Message2</button>
</div>
<script>
function ap(flag, ...arg)
// flag 是第一个参数,后续的参数都存在arg中
// 获取QT传过来的数据,多个可以继续使用索引进行获取,例如arg[1];arg[2];等
var mess = arg[0];
if (mess != '')
var txt = document.getElementById('output').value; //获取textarea的值
var text = flag + ": " + mess;
if (txt == '')
document.getElementById('output').value = text; //设置textarea的值
else
document.getElementById('output').value = txt + "\\n" + text; //设置textarea的值
//var t1 = arg.length; // arg记录有多少个参数
//var t2 = ap.length; // ap函数有多少个参数,固定只会显示一个,就是flag
// 使用事件方式给QT发送失败后,QT给html发送失败消息
function sendFail(flag, ...arg)
var mess = arg[0];
var txt = document.getElementById('output').value; //获取textarea的值
var text = flag + ": " + mess;
if (txt == '')
document.getElementById('output').value = text; //设置textarea的值
else
document.getElementById('output').value = txt + "\\n" + text; //设置textarea的值
function onLoad()
if (typeof CallBridge == "undefined")
alert("Not in CefView context");
return;
// 注册一个叫apChange的事件,该事件绑定名为ap的函数,当有接收到apChange事件,ap函数调用
CallBridge.addEventListener("apChange", ap);
// 还可以注册多个事件,绑定不同的函数
CallBridge.addEventListener("sendFailChange", sendFail);
function onInvokeMethodClicked(name, ...arg)
// invoke C++ code // 给QT发射信号
window.CallBridge.invokeMethod(name, ...arg);
// 给QT发送成功后,QT给html发送成功消息
function on_success(response)
// response是主程序返回的数据
var txt = document.getElementById('output').value; //获取textarea的值
var text = response;
//document.getElementById('output').value = txt + "\\n" + text; //设置textarea的值
// 给QT发送失败后,QT给html发送失败消息
function on_failure(error_code, error_message)
// error_message是主程序返回的数据
var txt = document.getElementById('output').value; //获取textarea的值
var text = response;
document.getElementById('output').value = txt + "\\n" + text; //设置textarea的值
function onCallBridgeQueryClicked(name, ...arg)
var message = document.getElementById("account").value;
//var name = 'html';
var str = name + "|" + message; // 由于只能传递一个字符串参数,如果想要传递多个,可以使用一个字符进行隔开组合到一起,qt就收后再进行分割获取即可
document.getElementById("account").value = ''; // 把输入框清空
if (message != '')
var query =
request: str, // 参数
onSuccess: on_success, // 主程序返回成功信号,执行此函数
onFailure: on_failure, // 主程序返回失败信号,执行此函数
;
// 给QT发射信号
window.CefViewQuery(query);
var txt = document.getElementById('output').value; //获取textarea的值
var text = name + ": " + message;
if (txt == '')
document.getElementById('output').value = text; //设置textarea的值
else
document.getElementById('output').value = txt + "\\n" + text; //设置textarea的值
</script>
</body>
</html>
2). css代码
文件名:Login.css
html
width: 100%;
height: 100%;
overflow: hidden;
font-style: sans-serif;
body
width: 100%;
height: 100%;
font-family: 'Open Sans',sans-serif;
margin: 0;
background-color: #4A374A;
#login
position: absolute;
top: 50%;
left:50%;
margin: -150px 0 0 -150px;
width: 300px;
height: 300px;
#login h1
color: #fff;
text-shadow:0 0 10px;
letter-spacing: 1px;
text-align: center;
h1
font-size: 2em;
margin: 0.67em 0;
input
width: 278px;
height: 18px;
margin-bottom: 10px;
outline: none;
padding: 10px;
font-size: 13px;
color: #fff;
//text-shadow:1px 1px 1px;
border-top: 1px solid #312E3D;
border-left: 1px solid #312E3D;
border-right: 1px solid #312E3D;
border-bottom: 1px solid #56536A;
border-radius: 4px;
background-color: #2D2D3F;
.but
width: 300px;
min-height: 20px;
display: block;
background-color: #4a77d4;
border: 1px solid #3762bc;
color: #fff;
padding: 9px 14px;
font-size: 15px;
line-height: normal;
border-radius: 5px;
margin: 0;
textarea
width: 300px;
height: 200px;
margin-bottom: 10px;
outline: none;
resize: none;
pointer-events: none;
font-size: 13px;
border-top: 1px solid #312E3D;
border-left: 1px solid #312E3D;
border-right: 1px solid #312E3D;
border-bottom: 1px solid #56536A;
border-radius: 4px;
2 QT窗体显示一个html
新建一个项目名为QCefView_Test,将路径**/QCefView-main/include/的头文件拷贝到项目代码路径中;还有将编译好的QCefView.lib拷贝到项目代码路径**中。
右键项目 - C/C++ - 常规 - 附加包含目录
添加我们的项目代码路径和include路径进来
例如我的是:
E:\\Code\\vs2022Code\\QCefView_Test\\QCefView_Test
E:\\Code\\vs2022Code\\QCefView_Test\\QCefView_Test\\include
右键项目 - 链接器 - 输入 - 附加依赖项
添加lib进来:QCefView.lib
在构造函数中进行如下操作:
添加头文件:
#include “QCefView.h”
#include “QCefContext.h”
-
定义QCefView对象
// 这个应该要在头文件中进行定义 QCefView* cefViewWidget;
-
添加一个本地文件夹到URL映射
QDir dir = QCoreApplication::applicationDirPath(); QString path = QDir::toNativeSeparators(dir.filePath("html")); // 获取运行路径,并拼接上html // 添加一个本地文件夹到URL映射:参数一是文件夹路径,参数二应该是自定义协议和域名 QCefContext::instance()->addLocalFolderResource(path, "my://cpp_learners"); // 自定义协议:my 自定义域名:cpp_learners //QCefContext::instance()->addLocalFolderResource(path, "https://cpp_learners");
-
实例化QCefView对象
// 设置QCefView的 QCefSetting setting; //setting.setBackgroundColor(QColor::fromRgb(100, 80, 60)); // 设置HTML背景颜色 // 创建一个QCfView窗体 cefViewWidget = new QCefView("my://cpp_learners/QCefViewTest.html", &setting, this);
-
添加到窗体布局中
// 定义一个网格布局,并将QCefView窗体设置在此 QGridLayout* layout = new QGridLayout(this); layout->addWidget(cefViewWidget, 0, 0, 1, 1); // 将布局添加到widget中 ui.widgetHtml->setLayout(layout);
ui.widgetHtml是我们在ui界面拖动的一个widget部件
-
main.cpp文件添加如下代码
一定要添加,否则运行报错!#include "QCefContext.h" #include "QCefConfig.h" int main(int argc, char *argv[]) QApplication a(argc, argv); // build QCefConfig QCefConfig config; config.setUserAgent("QCefViewTest"); config.setLogLevel(QCefConfig::LOGSEVERITY_DEFAULT); config.setBridgeObjectName("CallBridge"); config.setRemoteDebuggingPort(9000); config.setBackgroundColor(Qt::lightGray); // add command line args // config.addCommandLineSwitch("allow-universal-access-from-files"); config.addCommandLineSwitch("enable-media-stream"); config.addCommandLineSwitch
以上是关于Qt vs2022使用QCefView控件与html通信的主要内容,如果未能解决你的问题,请参考以下文章