Qt vs2022使用QCefView控件与html通信

此前,主管让我调研cef3的使用,但是cef3比较复杂,太难理解了;偶然间,在网上看到有QT第三方库QCefView,这个库封装了cef3,使得可以很简单的在桌面应用加载显示html,并与其进行通信;经过几天的调研,现在将调研结果记录下来!


目录

  • 前言
  • 一、编译QCefView
  • 二、插曲
    • 1). 安装OpenSSL
    • 2). 编译Curl
  • 三、案例
    • 1 HTML代码
      • 1). html代码
      • 2). css代码
    • 2 QT窗体显示一个html
    • 3 QT给html发送消息 (C++中调用Javascript)
    • 4 html给QT发送消息 (Javascript中调用C++)
      • 1). invokeMethod
      • 2). CefViewQuery
  • 四、总结


前言

  1. QCefView是什么?
    QCefView是为Qt框架开发的一个封装集成了Chromium Embedded Framework库的Wdiget UI组件。使用QCefView可以充分发挥CEF丰富强大的Web能力,快速开发混合架构的应用程序。

    使用Qt开发者熟悉的Forms,signal/slot来开发应用
    方便直观的Javascript/C++互操作方式

  2. 为何选择QCefView而不用Electron?
    从设计思路和最终形态来讲QCefView和Electron是完全不同的技术。

    QCefView只是一个为Qt框架开发的UI组件,Electron则是一个功能完备的应用开发框架
    QCefView是为Native系统开发者设计的,Electron对前端开发者更友好
    QCefView使用C++作为主要开发语言,Electron全部基于Javascript
    QCefView提供便捷直观的Javascript/C++互操作方式,Electron通过编写插件实现Web/Native互操作

  3. 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

  1. 下载最新源码
    Qt vs2022使用QCefView控件与html通信_第1张图片

  2. 下载解压后

    Qt vs2022使用QCefView控件与html通信_第2张图片

    CefViewCode-main中的全部文件拷贝到QCefView-main/CefViewCode 目录下: Qt vs2022使用QCefView控件与html通信_第3张图片
    QCefView-main 路径下新建文件夹build

  3. 编辑QCefView-main 路径下的QtConfig.cmake文件

    在这里写上自己的QT安装路径
    Qt vs2022使用QCefView控件与html通信_第4张图片
    建议是QT6以上的版本!

  4. 设置QT6的环境变量

Qt vs2022使用QCefView控件与html通信_第5张图片

  1. 下载安装CMake
    下载链接:https://cmake.org/download/

    Qt vs2022使用QCefView控件与html通信_第6张图片
    下载后安装即可,这里就不再缀叙安装过程!

  2. 打开CMake
    根据下图步骤进行编译!
    Qt vs2022使用QCefView控件与html通信_第7张图片
    Qt vs2022使用QCefView控件与html通信_第8张图片
    Qt vs2022使用QCefView控件与html通信_第9张图片
    插入小道消息-------------------------------------------------------------------------------------------------------------

    如果网络不好,网上说可以自行下载一个cef版本,然后将cef拷贝到路径/QCefView-main/CefViewCore/dep,然后去下图二文件中进行修改一些操作,CMake编译就不用下载了,具体我没有操作成功!
    cef官网:https://cef-builds.spotifycdn.com/index.html
    Qt vs2022使用QCefView控件与html通信_第10张图片
    Qt vs2022使用QCefView控件与html通信_第11张图片
    小道消息结束-------------------------------------------------------------------------------------------------------------

    下面接着开始下载的步骤,下图显示的是已经将cef下载完毕并解压好了的Qt vs2022使用QCefView控件与html通信_第12张图片
    Qt vs2022使用QCefView控件与html通信_第13张图片
    在路径/QCefView-main/CefViewCore/dep下,有CMake帮我们下载的CEF包Qt vs2022使用QCefView控件与html通信_第14张图片

  3. 编译VS工程

    在build目录下有一个VS工程,使用VS2022打开它
    Qt vs2022使用QCefView控件与html通信_第15张图片
    根据自己的需求设置好后右键ALL_BUILD,选择重新生成
    Qt vs2022使用QCefView控件与html通信_第16张图片

    编译成功如下图:
    Qt vs2022使用QCefView控件与html通信_第17张图片

  4. 查看编译好的库

    路径中多出了个output路径
    Qt vs2022使用QCefView控件与html通信_第18张图片

    lib目录存放的就是我们需要的QCefView.lib
    bin目录存放的是项目运行需要的动态库等文件!
    Qt vs2022使用QCefView控件与html通信_第19张图片

至此,QCefView已经编译完毕!


二、插曲

有些朋友的项目可能需要使用到Curl,并且,curl得带有openssl,否则无法使用https;请按照下面步骤进行编译!不需要可跳过此步骤!

1). 安装OpenSSL

下载和安装
下载其他人做的便捷版安装包
下载链接:http://slproweb.com/products/Win32OpenSSL.html

Qt vs2022使用QCefView控件与html通信_第20张图片

下载后安装, 一直狂点下一步就行了。
安装时如果你没有修改安装路径,默认是安装在:C:\Program Files\OpenSSL-Win64

设置一下环境变量
Qt vs2022使用QCefView控件与html通信_第21张图片
Qt vs2022使用QCefView控件与html通信_第22张图片

查看安装版本
Qt vs2022使用QCefView控件与html通信_第23张图片

OpenSSL安装完毕!

2). 编译Curl

注意:编译带有openssl的curl库,编译Debug失败,编译Release成功!

下载地址:https://curl.se/download.html

Qt vs2022使用QCefView控件与html通信_第24张图片
不知为何,这里只有Release版本的下载,所以我们待会编译带有openssl的curl库时也只能编译Release的库,编译Debug的库会失败!
当然,如果只是编译curl没有包含openssl的话,debug的库貌似是可以编得过的!

  1. 下载后解压打开
    在下图路径中,有很多个版本,具体看下图
    Qt vs2022使用QCefView控件与html通信_第25张图片
    使用VS2022打开
    Qt vs2022使用QCefView控件与html通信_第26张图片

  2. 选择 DLL Release – DLL OpenSSL 和 x64

    如果编译带有openssl的curl库,这里一定要选择 DLL Release – DLL OpenSSL ,否则会编译失败!
    Qt vs2022使用QCefView控件与html通信_第27张图片

  3. 包含openssl的库文件
    如果只是需要使用curl的http,而不需要使用https,那么,编译也就不需要带有openssl,可以直接跳到下方第4步骤进行编译;当然,在第二步骤需要选择,DLL Debug或者DLL Release项进行编译即可!

    A. 右键libcurl - 属性 - VC++目录 - 包含目录
    Qt vs2022使用QCefView控件与html通信_第28张图片
    添安装的OPenSSL库的头文件路径进来
    C:\Program Files\OpenSSL-Win64\include
    Qt vs2022使用QCefView控件与html通信_第29张图片

    B. VC++目录 - 库目录
    Qt vs2022使用QCefView控件与html通信_第30张图片
    将安装的OPenSSL库的lib添加进来
    C:\Program Files\OpenSSL-Win64\lib
    Qt vs2022使用QCefView控件与html通信_第31张图片

    C. 链接器 - 输入 - 附加依赖项
    一般来说默认会给我们添加上了这些lib,如果没有请手动打上
    Qt vs2022使用QCefView控件与html通信_第32张图片

  4. 编译
    右键curl,选择重新生成
    Qt vs2022使用QCefView控件与html通信_第33张图片
    编译成功如下图:
    Qt vs2022使用QCefView控件与html通信_第34张图片

  5. 查看编译好的库
    进入下图路径,就会有编译好的带openssl的curl库了
    Qt vs2022使用QCefView控件与html通信_第35张图片

至此,Curl编译完毕!

另外,如果编译的是带有openssl的curl库,那么此库应该是Release版本的;如果此库需要和QCefView结合一起使用,得将QCefView库也编译成Release版本的才可以一起使用,否则会编译报错!


三、案例

下面将根据本人写的一个小案例进行讲解代码知识点。此案例是QT使用QCefView显示html,并与之进行通信,互相发送消息!

具体案例代码放在下面总结处,有需要的可以去下载!

案例运行截图:
Qt vs2022使用QCefView控件与html通信_第36张图片

上方显示的是html页面
下方显示的是QT页面
当然,也可以直接整个窗体都进行显示html页面,具体根据自己的需求来就好!
因为我对HTML不熟悉,所以搞得html显示的有点奇怪,但不影响我们立即如何使用。

ui布局如下:
Qt vs2022使用QCefView控件与html通信_第37张图片
根据自己的需求来布局就可以了!

1 HTML代码

1). html代码

文件名:QCefViewTest.html

doctype html>
<html lang="en">  
    <head>
        <meta charset="UTF-8">
        <title>Logintitle>
        <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)">Message1button>					
			<button id="loginBtn" class="but" type="button" onclick="onInvokeMethodClicked('message2', '标题', '这是message2', 'B', 2.2)">Message2button>
			
        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拷贝到项目代码路径**中。
Qt vs2022使用QCefView控件与html通信_第38张图片
右键项目 - 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”

  1. 定义QCefView对象

    // 这个应该要在头文件中进行定义
    QCefView* cefViewWidget;
    
  2. 添加一个本地文件夹到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");
    
  3. 实例化QCefView对象

    // 设置QCefView的
    QCefSetting setting;
    //setting.setBackgroundColor(QColor::fromRgb(100, 80, 60));   // 设置HTML背景颜色
    
    // 创建一个QCfView窗体
    cefViewWidget = new QCefView("my://cpp_learners/QCefViewTest.html", &setting, this);
    
  4. 添加到窗体布局中

    // 定义一个网格布局,并将QCefView窗体设置在此
    QGridLayout* layout = new QGridLayout(this);
    layout->addWidget(cefViewWidget, 0, 0, 1, 1);
    
    // 将布局添加到widget中
    ui.widgetHtml->setLayout(layout);
    

    ui.widgetHtml是我们在ui界面拖动的一个widget部件

  5. 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("use-mock-keychain");
        config.addCommandLineSwitch("allow-file-access-from-files");
        config.addCommandLineSwitch("disable-spell-checking");
        config.addCommandLineSwitch("disable-site-isolation-trials");
        config.addCommandLineSwitch("enable-aggressive-domstorage-flushing");
        config.addCommandLineSwitchWithValue("renderer-process-limit", "1");
        config.addCommandLineSwitchWithValue("disable-features", "BlinkGenPropertyTrees,TranslateUI,site-per-process");
    
    	// initialize QCefContext instance with config
    	QCefContext cefContext(&a, argc, argv, &config);
    
    
    
    	QCefView_Test w;
    	w.show();
    	return a.exec();
    }
    
  6. 设置好ui部件后开始编译
    此时不出意外的话,应该是编译报错的,报错说缺少什么dll等。

    需要将我们编译好的,/QCefView-main/build/output/Debug/bin/ 路径下的所有文件都拷贝到项目的运行路径,也就是.exe所在的路径。
    Qt vs2022使用QCefView控件与html通信_第39张图片

    另外,上图html文件夹是我们另外新建的,新建好后,将上面的html代码和css代码,新建相同名字文件后放到html文件夹中。
    Qt vs2022使用QCefView控件与html通信_第40张图片

  7. 再次运行
    不出意外的话,应该是可以正常运行的了!而且也显示出了我们指定的html页面!

3 QT给html发送消息 (C++中调用Javascript)

在按钮的槽函数中进行操作

QVariantList 这是一个链表,将我们需要穿个html的数据存到此链表中

然后定义事件QCefEvent ,且绑定事件apChange,注意,这个apChange事件需要和html代码中定义的事件一致!

然后使用setArguments()方法将链表绑定到事件中

最后使用broadcastEvent(event);将事件进行广播

void QCefView_Test::on_btnSend_clicked()
{
    if (cefViewWidget) {

        // 设置传输的数据
        QVariantList list;
        list.emplace_back("qt");
        list.emplace_back("字符串");
        list.emplace_back(123);
        list.emplace_back(3.14);

        // 绑定事件
        QCefEvent event("apChange");
        // 绑定参数
        event.setArguments(list);

        //cefViewWidget->triggerEvent(event);
        cefViewWidget->broadcastEvent(event);   
    }

}

在html的javascript代码中注册事件


function ap(flag, ...arg) {
	// flag 是第一个参数,根据上面个代码传过来的值,他是qt,后续的参数都存在arg中
	// 获取QT传过来的数据,多个可以继续使用索引进行获取,例如arg[1];arg[2];等
	var mess = arg[0];	
	// ...省略了															
								
	//var t1 = arg.length;		// arg记录有多少个参数
	//var t2 = ap.length;		// ap函数有多少个参数,固定只会显示一个,就是flag
}

function onLoad() {
	if (typeof CallBridge == "undefined") {
		alert("Not in CefView context");
		return;
	}

	// 注册一个叫apChange的事件,该事件绑定名为ap的函数,当有接收到apChange事件,ap函数调用
	CallBridge.addEventListener("apChange", ap);
				
	// 还可以注册多个事件,绑定不同的函数
	CallBridge.addEventListener("sendFailChange", sendFail);
}

注册的apChange事件,把绑定名为ap的函数,当有此事件传过来时,就会调用ap()函数,就可以在ap函数中接收QT传过来的数据,进行相应的操作了,其实也就相当于QT调用Javascript的代码

还可以注册更多的事件,让QT去调用!

4 html给QT发送消息 (Javascript中调用C++)

有两种方式给QT发射信号:
invokeMethod 和 CefViewQuery

1). invokeMethod

invokeMethod(name, ...args)

当该方法在Javascript中调用后,下面的Qt signal将被触发:

void invokeMethod(int browserId,int frameId,const QString & method,const QVariantList & arguments);

继续在html中添加Javascript代码

function onInvokeMethodClicked(name, ...arg) {
   // invoke C++ code
   window.CallBridge.invokeMethod(name, ...arg);
}

然后可以在html代码中添加两个按钮,在按钮的点击事件中调用此方法即可!
根据需求进行添加参数即可!

<body onload="onLoad()" id="main" class="noselect">
    <div id="login">		
		<button id="loginBtn" class="but" type="button" onclick="onInvokeMethodClicked('message1', '标题', '这是message1', 'a', 1.1)">Message1button>	
		<button id="loginBtn" class="but" type="button" onclick="onInvokeMethodClicked('message2', '标题', '这是message2', 'B', 2.2)">Message2button>		
    div>
body>

然后再来到QT代码中
新建一个槽函数

private slots:
    // 用这个槽函数去接收html传过来的消息
    void onInvokeMethod(int browserId, int frameId, const QString& method, const QVariantList& arguments);

然后可以在构造函数中进行绑定

connect(cefViewWidget, &QCefView::invokeMethod, this, &QCefView_Test::onInvokeMethod);

之后实现槽函数onInvokeMethod
第三个参数method,就是在html中onInvokeMethodClicked的第一个参数,之后参数都放在链表arguments中;第一个和第二个参数暂时我也还没搞懂有啥用。

使用第三个参数进行判断,进行相应的操作,可以直接再次槽函数中进行操作,也可以另外定义一个函数进行操作。

当传输过来的第三个参数,在QT这边没有定义,那么可以给html广播事件回去,告诉它没有找到

void QCefView_Test::onInvokeMethod(int browserId, int frameId, const QString& method, const QVariantList& arguments)
{
    if (0 == method.compare("message1")) {
        /* 可以在这里做处理 */
        
        QString str1 = arguments.at(0).toString();
        QString str2 = arguments.at(1).toString();
        QString str3 = arguments.at(2).toString();
        float f1 = arguments.at(3).toFloat();
        int in1 = arguments.size();

    } else if (0 == method.compare("message2")) {
        /* 也可以定义函数去做处理 */
        // void _message2(const QString& method, const QVariantList& arguments)
        _message2(method, arguments);
    
    } else {
		// 当传输过来的第三个参数,在QT这边没有定义,那么可以给html广播事件回去,告诉它没有找到
        if (cefViewWidget) {

            // 设置传输的数据
            QVariantList list;
            list.emplace_back("qt");
        
            list.emplace_back(QString::fromLocal8Bit("没有找到与之对应的事件:") + method);

            // 绑定事件
            QCefEvent event("sendFailChange");
            // 绑定参数
            event.setArguments(list);

            // 官网例子使用的是broadcastEvent,在网上看到有人使用triggerEvent,测试都是可以的
            //cefViewWidget->triggerEvent(event);
            cefViewWidget->broadcastEvent(event);
        }
    }
}

2). CefViewQuery

window.CefViewQuery(query)

当从Javascript中调用该方法时,以下Qt signal会被触发:

void cefQueryRequest(int browserId,int frameId,const QCefQuery & query)

继续在html中添加Javascript代码

// 给QT发送成功后,QT给html发送成功消息			
function on_success(response) {
	// response是主程序返回的数据
	alert(response);
}	
// 给QT发送失败后,QT给html发送失败消息			
function on_failure(error_code, error_message) {
	// error_message是主程序返回的数据
	alert(error_message);
}			
function onCallBridgeQueryClicked(name, ...arg) {

	// 设置参数,传给QT
	var str1 = '这个是传给QT的数据'
	var str2 = 123
	var str3 = 3.14
	var str = name + str1 + '|' + str2 + '|' + str3;	// 因为只能传一个参数,所以可以使用拼接的方式传给QT,QT接收后,再进行分割即可
	
	var query = {
		request: str,	// 参数
		onSuccess: on_success,		// 主程序返回成功信号,执行此函数
		onFailure: on_failure,		// 主程序返回失败信号,执行此函数
	};
		
	// 给QT发射信号
	window.CefViewQuery(query);					
}

然后可以在html代码中添加个按钮,在按钮的点击事件中调用此方法即可!

<button id="loginBtn" class="but" type="button" onclick="onCallBridgeQueryClicked('html')">发送button>

然后再来到QT代码中
新建一个槽函数

private slots:
    // 用这个槽函数去接收html传过来的消息
    void onQCefQueryRequest(int browserId, int frameId, const QCefQuery& query);

然后可以在构造函数中进行绑定

connect(cefViewWidget, &QCefView::cefQueryRequest, this, &QCefView_Test::onQCefQueryRequest);

之后实现槽函数onQCefQueryRequest

根据参数三query的request方法获得字符串,然后进行分割,就拿到传过来的参数了

根据需求做完操作后,需要调用方法query.setResponseResult,将操作的结果返回给html,true为成功,false为失败,还可以传递字符串信息回去。

最后调用cefViewWidget->responseQCefQuery(query);即可

void QCefView_Test::onQCefQueryRequest(int browserId, int frameId, const QCefQuery& query) {
    
    // 获得html传过来的数据
    std::vector<std::string> vec = _split(query.request().toStdString(), "|");	// 分割获取数据
    if (1 == vec.size() || true == vec.at(1).empty()) {
        QMessageBox::information(this, QString::fromLocal8Bit("提示"), QString::fromLocal8Bit("消息为空!"));
        
        // 设置结果为false,给html返回结果
        query.setResponseResult(false, QString::fromLocal8Bit("qt接收失败,数据为空!"));
    
    } else {

        // 设置结果为true,给html返回结果
        query.setResponseResult(true, QString::fromLocal8Bit("qt接收成功!"));
    }


    // 给js返回结果(字符串)
    cefViewWidget->responseQCefQuery(query);
}

到此为止,QT与html通信流程就结束了!


四、总结

也是经过了好几天的潜心去研究,虽说没有什么特别的技术在这里,但是基本的操作还是写下来了,都是参考官网给出的例子去完成的!
后续还得再花时间去深入研究一下!

案例源码:
https://download.csdn.net/download/cpp_learner/86266086

你可能感兴趣的:(Qt,qt,html,QCefView)