Sciter之c++与前端事件状态交互(六)

上一篇介绍了c与前端html相互调用能力,本章将介绍c与html(前端)事件状态相互。

前言

Sciter 是一个高质量但小众的嵌入式 UI 引擎,适合追求性能、体积和原生集成的桌面应用开发者。

我觉得 Sciter 比较有意思,它很小众,是闭源的,商用需要许可。它是Andrew Fedoniouk开发维护,Andrew获得了物理学和应用数学硕士学位以及艺术文凭。他的职业生涯始于俄罗斯航空航天工业的研究员。这种跨领域背景使他既具备深厚的技术功底,又懂得用户界面设计的艺术。

Sciter官网:https://sciter.com/ 2025-11-15 sciter-js-sdk最新版v6.0.2.28

本次入门开发环境:window 10 + Clion 2024.3 + Sciter-js v6.0.2.28(2025-11-15最新版) + Bundled MinGW 11.0

c++监听js事件

  • 基于窗口级别的 handle_event

c++ 代码

#include <cstdint>  // C++ 标准头文件(首选)
#include <windows.h>
#include <thread>
#include <fcntl.h>
#include "sciter-x-window.hpp"
#include "aux-cvt.h"
#include "sciter-x.h"
#include "sciter-x-dom.h"
#include "sciter-x-threads.h"
#include "sciter-x-behavior.h"


class myWindow : public sciter::window {
public:
    myWindow() : window(SW_MAIN | SW_ENABLE_DEBUG) {}

    // 重写 window 的事件处理
    bool handle_event(HELEMENT he, BEHAVIOR_EVENT_PARAMS &params) override {
        if (params.cmd == DOCUMENT_PARSED && params.heTarget == root())
            initial_window_state_defined = sciter::dom::element(root()).get_attribute("window-state").length() != 0;

        // 能够处理所有事件,例如按钮点击、窗口激活、获得失去焦点等...
        // 捕获自定义事件
        if (params.cmd == CUSTOM && params.name != nullptr) {
            // 还有大量事件需要过滤
            if (wcscmp(params.name, L"my-custom-event") == 0) {
                // 筛选出我们的事件
                std::wcout << L"捕获到自定义事件: " << params.name << "cmd = 0x" << std::hex << params.cmd << std::endl;
                std::wcout << L"接收到的数据:" << params.data.to_string() << std::endl;
            }
        }
        return false;
    }
};

int uimain(std::function<int()> run) {
    // 创建ui窗口实例
    sciter::om::hasset<myWindow> window = new myWindow();

    // 加载前端UI的html文件
    window->load(
            WSTR("file://C:\\Users\\Administrator\\Desktop\\project\\sciter\\app\\demo_20251121\\ui\\hello-ui_event.html"));

    window->expand();

    return run();
}

/**
 * 图形用户界面(GUI)应用程序的标准入口函数,相当于控制台程序中的 main 函数。
 * 2025-11-15 by lingkang
 */
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
    // 启用试调
    SciterSetOption(NULL, SCITER_SET_SCRIPT_RUNTIME_FEATURES,
                    ALLOW_FILE_IO |
                    ALLOW_SOCKET_IO |
                    ALLOW_EVAL |
                    ALLOW_SYSINFO);
    // 设置控制台输出为宽字符模式(可选但推荐)
    _setmode(_fileno(stdout), _O_U8TEXT);

    // 初始化sciter
    sciter::application::start();
    // 加载我们的窗口
    uimain([]() -> int { return sciter::application::run(); });
    // 结束时 关闭
    sciter::application::shutdown();
    return 0;
}

static std::vector<sciter::string> _argv;
// 设置 sciter 的初始化应用
namespace sciter {

    namespace application {
        HINSTANCE hinstance() {
            return nullptr; // not used
        }

        const std::vector<sciter::string> &argv() {
            // 获取命令行参数
            return _argv;
        }
    }

}

前端代码

<!DOCTYPE html>
<html
        window-width=600px
        window-height=450px
        window-resizable=true
>
<head>
    <meta charset="UTF-8">
    <title>lingkang的sciter前端与c++之间事件状态交互</title>
    <style>
        .flex-row {
            display: flex;
            flex-direction: row;
            gap: 10px;
        }
    </style>
</head>
<body style="display: flex;flex-direction: column;gap: 20px">
<h2>发送事件给c++</h2>
<button id="btn-01">发送简单事件</button>

<h2>监听c++发过来的事件</h2>
<p>这是一个伪命题,转换思路为:c++调用js代码即可。例如上一篇提到的 “c++调用前端js定义的 my_js_fun 方法”</p>

<script>
    // 给按钮绑定点击事件
    document.getElementById('btn-01').onclick = function () {
        const event = new Event('my-custom-event', {
            data: 'lingkang你好~'
        })
        // 发送
        Window.this.postEvent(event)
    }
</script>
</body>
</html>

前端监听c++事件

这是一个伪命题,转换思路为:c++调用 js 代码即可。例如上一篇提到的 “c++调用前端js定义的 my_js_fun 方法” 来触发前端方法事件

c++调用js定义的方法伪代码:

    // 调用html中定义的js方法
    void callJavaScriptFun() {
        // 入参,只有一个
        VALUE argvs[1];
        LPCWSTR chars = L"入参字符串:lingkang";
        ValueStringDataSet(&argvs[0], chars, wcslen(chars), 0);
        VALUE result;
        // 调用前端js定义的 my_js_fun 方法
        SCDOM_RESULT ok = SciterCallScriptingFunction(root(), "my_js_fun", argvs, 1, &result);
        if (ok == SCDOM_OK) {
           LPCWSTR str_data;
          UINT str_length;
          ValueStringData(&result, &str_data, &str_length);
            // 获取字符串数据
            std::wcout << "调用js的结果: " << str_data << std::endl;
        } else {
            // 处理错误
            std::cout << "调用js出错啦 " << std::endl;
        }

        // 清理
        ValueClear(&result);
        ValueClear(&argvs[0]);
    }

效果

image-1763794051242