qt调用cef的Demo,实现js与C++之间的交互细节

发布于:2025-09-13 ⋅ 阅读:(19) ⋅ 点赞:(0)

想在 Qt 中集成 CEF (Chromium Embedded Framework),并且实现 JS 与 C++ 交互,本文是一个最小可运行的 Demo 示例

⚠️ 提示:

  • 这个 Demo 假设你已经下载并编译好了 CEF SDK,并且把头文件、库文件配置到 Qt 工程中。

  • 代码展示了 Qt 调用 CEF,创建一个简单的浏览器窗口,并实现 JS 调用 C++ 和 C++ 调用 JS 的交互。


1. main.cpp


#include <QApplication>
#include "cef_app_qt.h"
#include "cef_browser_widget.h"

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);

    // 初始化 CEF
    CefEnableHighDPISupport();
    CefMainArgs main_args(argc, argv);
    CefRefPtr<CefAppQt> cefApp(new CefAppQt);

    int exit_code = CefExecuteProcess(main_args, cefApp, nullptr);
    if (exit_code >= 0) {
        return exit_code;  // 子进程
    }

    CefSettings settings;
    settings.no_sandbox = true;
    CefInitialize(main_args, settings, cefApp, nullptr);

    // 创建 Qt + CEF 的窗口
    CefBrowserWidget browser;
    browser.resize(800, 600);
    browser.show();

    int result = app.exec();

    // 关闭 CEF
    CefShutdown();
    return result;
}

2. cef_app_qt.h


#pragma once
#include "include/cef_app.h"

// 简单的 CefApp 派生类
class CefAppQt : public CefApp, public CefRenderProcessHandler {
public:
    CefAppQt() = default;

    CefRefPtr<CefRenderProcessHandler> GetRenderProcessHandler() override {
        return this;
    }

    // 处理渲染进程中 JS 与 C++ 的交互
    void OnContextCreated(CefRefPtr<CefBrowser> browser,
                          CefRefPtr<CefFrame> frame,
                          CefRefPtr<CefV8Context> context) override {
        CEF_REQUIRE_RENDERER_THREAD();

        // 注册 JS -> C++ 的函数
        CefRefPtr<CefV8Value> global = context->GetGlobal();
        CefRefPtr<CefV8Handler> handler = new JsHandler();
        global->SetValue("callCpp", CefV8Value::CreateFunction("callCpp", handler), V8_PROPERTY_ATTRIBUTE_NONE);
    }

private:
    class JsHandler : public CefV8Handler {
    public:
        JsHandler() = default;

        bool Execute(const CefString& name,
                     CefRefPtr<CefV8Value> object,
                     const CefV8ValueList& arguments,
                     CefRefPtr<CefV8Value>& retval,
                     CefString& exception) override {
            if (name == "callCpp") {
                if (arguments.size() > 0 && arguments[0]->IsString()) {
                    std::string msg = arguments[0]->GetStringValue();
                    qDebug("JS 调用了 C++,传递参数: %s", msg.c_str());

                    // 返回一个值给 JS
                    retval = CefV8Value::CreateString("C++ 已收到: " + msg);
                    return true;
                }
            }
            return false;
        }

        IMPLEMENT_REFCOUNTING(JsHandler);
    };

    IMPLEMENT_REFCOUNTING(CefAppQt);
};

3. cef_browser_widget.h


#pragma once
#include <QWidget>
#include "include/cef_browser.h"
#include "include/cef_client.h"

class CefBrowserWidget : public QWidget, public CefClient, public CefLifeSpanHandler {
    Q_OBJECT
public:
    CefBrowserWidget(QWidget* parent = nullptr) : QWidget(parent) {
        CefWindowInfo window_info;
#if defined(Q_OS_WIN)
        window_info.SetAsChild((HWND)winId(), {0, 0, width(), height()});
#endif
        CefBrowserSettings browser_settings;

        CefBrowserHost::CreateBrowser(window_info, this,
            "file:///index.html", browser_settings, nullptr, nullptr);
    }

    CefRefPtr<CefLifeSpanHandler> GetLifeSpanHandler() override {
        return this;
    }

    void OnAfterCreated(CefRefPtr<CefBrowser> browser) override {
        CEF_REQUIRE_UI_THREAD();
        this->browser = browser;
    }

    // C++ 调用 JS
    void callJs(const std::string& msg) {
        if (browser) {
            CefRefPtr<CefFrame> frame = browser->GetMainFrame();
            std::string jsCode = "onCppMessage('" + msg + "')";
            frame->ExecuteJavaScript(jsCode, frame->GetURL(), 0);
        }
    }

private:
    CefRefPtr<CefBrowser> browser;
    IMPLEMENT_REFCOUNTING(CefBrowserWidget);
};

4. index.html (放在可访问路径下)


<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <title>Qt + CEF Demo</title>
  <script>
    // JS -> C++
    function sendToCpp() {
        let msg = document.getElementById("msg").value;
        let result = callCpp(msg);  // 调用绑定的 C++ 函数
        alert("C++ 返回: " + result);
    }

    // C++ -> JS
    function onCppMessage(text) {
        alert("来自 C++ 的消息: " + text);
    }
  </script>
</head>
<body>
  <h2>Qt + CEF + JS 交互 Demo</h2>
  <input type="text" id="msg" value="你好 C++">
  <button onclick="sendToCpp()">发送给 C++</button>
</body>
</html>

效果:

  1. 在 Qt 窗口中打开 index.html

  2. 输入内容并点击按钮,JS 调用 callCpp(),C++ 收到参数并返回字符串。

  3. C++ 可以调用 callJs("Hello from C++"),触发 JS 函数 onCppMessage()


网站公告

今日签到

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