qt与html通信

发布于:2025-04-19 ⋅ 阅读:(20) ⋅ 点赞:(0)

**Cef视图(CefView)**是指在使用Chromium Embedded Framework(CEF)时,嵌入到应用程序中的浏览器视图。CEF是一个开源项目,它基于Google的Chromium浏览器,允许开发者将Web浏览器功能嵌入到自己的应用程序中。
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 placeholder="请输入" name="u">
            <button id="sendBtn" class="but" type="button" onclick="onCallBridgeQueryClicked('html')">发送</button>
            <textarea id="output" required placeholder="内容" name="t"></textarea>
        </form>
        
        <!-- 测试按钮区 -->
        <button class="but" type="button" onclick="onInvokeMethodClicked('message1', '标题', '这是message1', 'a', 1.1)">
            Message1
        </button>
        <button class="but" type="button" onclick="onInvokeMethodClicked('message2', '标题', '这是message2', 'B', 2.2)">
            Message2
        </button>
    </div>

    <script>
    // ==================== 事件处理函数 ==================== //
    /**
     * 处理Qt发送的apChange事件
     * @param {string} flag 事件标识
     * @param {...any} arg 可变参数列表
     */
	//该函数响应"apChange"信号,负责将接收到的消息显示在页面的文本区域(output)中
    function ap(flag, ...arg) {
        const mess = arg[0]; // 获取第一个参数
        if (mess) {
            const output = document.getElementById('output');  //获取页面上的输出文本框
			
			//格式化消息:"[flag]: [mess]"
            const newText = `${flag}: ${mess}`;

			//将接收到的消息显示在页面的文本区域(output)中
            output.value = output.value  
			? `${output.value}\n${newText}`   // 非空时换行追加
			: newText;                    // 空时直接显示
        }
    }

    /**
     * 处理Qt发送的sendFailChange事件(错误消息)
     */
    function sendFail(flag, ...arg) {
        const output = document.getElementById('output');
        const newText = `${flag}: ${arg[0]}`;
        output.value = output.value ? `${output.value}\n${newText}` : newText;
    }

    // ==================== 初始化函数 ==================== //
    /**
     * 页面加载完成后初始化CEF通信
     */
    function onLoad() {
        if (typeof CallBridge === "undefined") {
            alert("Not in CefView context");
            return;
        }

        // 注册Qt事件监听
        CallBridge.addEventListener("apChange", ap); //apchange信号绑定ap函数
        CallBridge.addEventListener("sendFailChange", sendFail);
    }

    // ==================== JS → Qt通信 ==================== //
    /**
     * 调用Qt方法(无返回值)
     * @param {string} name 方法名
     * @param {...any} arg 可变参数
     */
    function onInvokeMethodClicked(name, ...arg) {
        window.CallBridge.invokeMethod(name, ...arg);
    }

    /**
     * 发送查询请求到Qt(需要返回值)
     */
    function onCallBridgeQueryClicked(name) {
        const message = document.getElementById("account").value.trim();
        if (!message) return;

        // 清空输入框
        document.getElementById("account").value = '';

        // 更新本地消息显示
        const output = document.getElementById('output');
        const newText = `${name}: ${message}`;
        output.value = output.value ? `${output.value}\n${newText}` : newText;

        // 构建并发送请求
        window.CefViewQuery({
            request: `${name}|${message}`,
            onSuccess: (response) => console.log("成功:", response),
            onFailure: (code, msg) => {
                output.value += `\n错误(${code}): ${msg}`;
            }
        });
    }
    </script>
</body>
</html>

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: #0f8fdf;   
}   
#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: #9cc7e3;   
    border: 1px solid #9cc7e3;   
    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;     
}  

Qt应用程序中嵌入Cef浏览器

获取html文件路径:

   //获取html文件路径
   QDir dir = QCoreApplication::applicationDirPath();
   QString path = QDir::toNativeSeparators(dir.filePath("html"));  

将本地html文件夹映射为一个URL,在cef浏览器里加载我们的html文件

  QCefContext::instance()->addLocalFolderResource(path, "my://cpp_learners");  

new一个cef浏览器对象,加载指定html文件

 cefViewWidget = new QCefView("my://cpp_learners/QCefViewTest.html", &setting, this);

把cef浏览器嵌入QT界面

    QGridLayout* layout = new QGridLayout(this);
    layout->addWidget(cefViewWidget, 0, 0, 1, 1);
    ui.widgetHtml->setLayout(layout);

Qt → HTML 通信详解

Qt主动向html发送数据:

            QVariantList data;
            QString str=ui.lineEditInput->text();          
            data << "qt" << "str";
            QCefEvent event("apChange"); //创建事件,名称为"apChange"
            event.setArguments(list);   //绑定发给前端的数据
            cefViewWidget->broadcastEvent(event); //发送事件到前端
            ui.lineEditInput->clear();  //清空输入框

HTML接收

// 注册事件监听
  function onLoad() //页面加载完成后初始化CEF通信
  {
      CallBridge.addEventListener("apChange", ap); //apchange信号绑定ap函数
  }
 //该函数响应"apChange"信号,负责将接收到的消息显示在页面的文本区域(output)中
    function ap(flag, ...arg) {
        const mess = arg[0]; // 获取第一个参数
        if (mess) {
            const output = document.getElementById('output');  //获取页面上的输出文本框
			
			//格式化消息:"[flag]: [mess]"
            const newText = `${flag}: ${mess}`;

			//将接收到的消息显示在页面的文本区域(output)中
            output.value = output.value  
			? `${output.value}\n${newText}`   // 非空时换行追加
			: newText;                    // 空时直接显示
        }
    }

HTML → Qt 通信详解

HTML端发送

单击发送按钮会触发onCallBridgeQueryClicked槽函数:

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

onCallBridgeQueryClicked函数内部操作

(1) 获取用户输入
var message = document.getElementById("account").value;
(2) 构建请求字符串
var str = "html" + "|" + message;  // 例如:"html|你好Qt"
(3) 发送到Qt(通过CEF的 CefViewQuery API发送数据)
window.CefViewQuery({
    request: str,          // 要发送的数据
    onSuccess: on_success, // 成功回调(当前未实现具体逻辑)
    onFailure: on_failure  // 失败回调(会显示错误信息)
});

QT端接收

  • HTML/JavaScript 调用 window.CefViewQuery() 时,CEF 会触发 cefQueryRequest 信号。
  • Qt 通过连接这个信号到 onQCefQueryRequest 槽函数,接收并处理来自网页的请求。
    // 绑定信号CefViewQuery
    connect(cefViewWidget, &QCefView::cefQueryRequest, this, &QCefView_Test::onQCefQueryRequest);

onQCefQueryRequest函数(接收html发来的数据)

void QCefView_Test::onQCefQueryRequest(int browserId, int frameId, const QCefQuery& query) {
    // 分割字符串
    auto parts = query.request().split("|");
    QString messageType = parts[0];  // "html"
    QString content = parts[1];      // 用户输入的内容

    // 处理消息...
    query.setResponseResult(true, "处理成功"); // 可选:返回响应
    cefViewWidget->responseQCefQuery(query);  // //给js返回结果
}

更新ui

// 在output文本区域显示发送的内容
document.getElementById('output').value += "\nhtml: " + message;

js->Qt发送弹窗

单击Message按钮调用onInvokeMethodClicked槽函数

<button class="but" type="button" onclick="onInvokeMethodClicked('message1', '标题', '这是message1', 'a', 1.1)">

onInvokeMethodClicked()函数进行js调用

   function onInvokeMethodClicked(name, ...arg) {
        window.CallBridge.invokeMethod(name, ...arg);
    }

具体调用内容:

window.CallBridge.invokeMethod(
    "message1", 
    "标题",      // → str1
    "这是消息1", // → str2
    "这是消息2", // → str3
    1.1         // → f1
);
  • HTML/JavaScript 调用 window.CallBridge.invokeMethod() 时,CEF 会触发 invokeMethod 信号。
  • Qt 通过连接这个信号到 onInvokeMethod 槽函数,执行对应的逻辑。

connect

    // 绑定信号invokeMethod
    connect(cefViewWidget, &QCefView::invokeMethod, this, &QCefView_Test::onInvokeMethod);

onInvokeMethod()函数

void QCefView_Test::onInvokeMethod(int browserId, int frameId, const QString& method, const QVariantList& arguments)
{
if (0 == method.compare("message1")) {
    // 从参数列表提取数据
    QString str1 = arguments[0].toString();  // 第1个参数 → 标题
    QString str2 = arguments[1].toString();  // 第2个参数 → 消息1
    QString str3 = arguments[2].toString();  // 第3个参数 → 消息2
    float f1 = arguments[3].toFloat();       // 第4个参数 → 浮点数
    int in1 = arguments.size();              // 参数总数

    // 在Qt界面显示日志
    ui.textEditText->append("您有消息弹窗提醒1"); 

    // 格式化消息并弹窗
    QString str = QString("%1,%2,%3,%4").arg(str2).arg(str3).arg(f1).arg(in1);
    QMessageBox::information(this, str1, str); // 弹窗显示
}
}

代码仓库:
https://gitee.com/sun-Penghu/qt/tree/master/QCefView1


网站公告

今日签到

点亮在社区的每一天
去签到