示例代码

以下为可直接套用的代码片段,覆盖窗口 / IPC / 托盘 / 热键 / 右键菜单 / 对话框 / 拖放 / YAML 等能力。片段默认处于 类 启动类 <公开 基础类 = 程序类> 内,已引用 JadeView 模块并声明:

Plaintext
变量 Jade <类型 = JadeView>
变量 主窗口ID <类型 = 整数>

接收事件方法(JadeView_应用就绪 等)可点击 Jade 变量旁的闪电图标快速生成,无需手写签名。

完整桌面应用骨架

启动方法(订阅特殊事件 → 初始化 → 注册 IPC 通道 → 消息循环):

Plaintext
方法 启动方法 <公开 类型 = 整数>
{
    // 可拦截 / 特殊事件在 初始化 前手动订阅
    Jade.订阅事件 (订阅_视图事件.请求新窗口)
    Jade.订阅事件 (订阅_视图事件.文件拖放)

    如果 (Jade.初始化 (真, "", "", "JadeView火山示例", "com.jadeview.demo", 真) == 假)
    {
        返回 (0)
    }

    Jade.置IPC频道回调 (本对象, "ipcChannelMessageCallback")
    Jade.注册IPC通道 ("ipc-echo")
    Jade.注册IPC通道 ("set-theme")
    Jade.注册IPC通道 ("minimize")

    Jade.运行消息循环 ()
    返回 (1)
}

应用就绪时加载本地前端并创建主窗口(Mica 材质 + 标题覆盖样式):

Plaintext
方法 JadeView_应用就绪 <接收事件 类型 = 整数>
参数 来源对象 <类型 = JadeView>
参数 标记值 <类型 = 整数>
参数 窗口ID <类型 = 整数>
参数 数据 <类型 = 文本型>
{
    如果 (来源对象 == Jade)
    {
        变量 窗口选项 <类型 = JadeWindowOptions>
        变量 视图选项 <类型 = JadeViewOptions>
        窗口选项.标题 = "JadeView 火山视窗 Demo"
        窗口选项.左边 = -1
        窗口选项.顶边 = -1
        窗口选项.宽度 = 1400
        窗口选项.高度 = 900
        窗口选项.可调整大小 = 真
        窗口选项.使用页面图标 = 真
        窗口选项.允许最小化 = 真
        窗口选项.允许最大化 = 真
        窗口选项.透明窗口 = 真
        窗口选项.边框风格 = 窗口边框样式.标题覆盖
        窗口选项.主题 = 窗口主题.跟随系统
        视图选项.允许全屏 = 真
        视图选项.自动播放 = 真

        变量 本地资源地址 <类型 = 文本型>
        本地资源地址 = Jade.置协议服务目录 (取运行目录 () + "web")
        主窗口ID = Jade.创建窗口 (本地资源地址, 0, 窗口选项, 视图选项)
    }
    返回 (0)
}

窗口创建完成后再设置首帧材质(此时窗口才真正存在):

Plaintext
方法 JadeView_窗口已创建 <接收事件 类型 = 整数>
参数 来源对象 <类型 = JadeView>
参数 标记值 <类型 = 整数>
参数 窗口ID <类型 = 整数>
{
    如果 (来源对象 == Jade)
    {
        如果真 (Jade.系统.是否为Win11 ())
        {
            Jade.窗口.置材质 (窗口ID, 窗口材质.云母)
        }
    }
    返回 (0)
}

IPC 应答与解析 JSON payload

Plaintext
方法 IPC频道消息 <公开 类型 = 文本型 @强制输出 = 真 @输出名 = "ipcChannelMessageCallback">
参数 通道名 <类型 = 文本型>
参数 窗口ID <类型 = 整数>
参数 数据 <类型 = 文本型>
{
    变量 数据解构 <类型 = json_object>
    数据解构.创建自文本 (数据)

    如果 (通道名 == "ipc-echo")
    {
        返回 (数据)    // 原样回声
    }
    如果 (通道名 == "set-theme")
    {
        // 前端 payload: {"mode": "Dark"}
        Jade.窗口.置主题 (窗口ID, 数据解构.取文本 ("mode", "System"))
        返回 ("主题已切换")
    }
    如果 (通道名 == "minimize")
    {
        Jade.窗口.最小化 (窗口ID)
        返回 ("已最小化")
    }
    返回 ("未知通道: " + 通道名)
}

可拦截事件:外链交给系统浏览器

Plaintext
方法 JadeView_请求新窗口 <接收事件 类型 = 整数 注释 = "返回 1 拦截,0 放行。">
参数 来源对象 <类型 = JadeView>
参数 标记值 <类型 = 整数>
参数 窗口ID <类型 = 整数>
参数 地址 <类型 = 文本型>
{
    如果 (来源对象 == Jade)
    {
        打开指定网址 (地址, )   // 交给系统默认浏览器
        返回 (1)               // 拦截 WebView 内新开窗口
    }
    返回 (0)
}

文件拖放:转发前端 + enter 同步拦截

Plaintext
变量 拒绝拖入 <类型 = 逻辑型>

方法 JadeView_文件拖放 <接收事件 类型 = 整数 注释 = "需手动订阅;enter/drop 阶段可拦截。">
参数 来源对象 <类型 = JadeView>
参数 标记值 <类型 = 整数>
参数 窗口ID <类型 = 整数>
参数 数据 <类型 = 文本型>
{
    如果 (来源对象 == Jade)
    {
        // enter/over/drop/leave 全程转发回页面(宿主接管后页面收不到原生 drop)
        Jade.发送IPC消息 (窗口ID, "drag-drop", 数据)

        如果真 (拒绝拖入)
        {
            变量 拖放数据 <类型 = json_object>
            如果真 (拖放数据.创建自文本 (数据))
            {
                如果真 (拖放数据.取文本 ("type", "") == "enter")
                {
                    返回 (1)   // enter 阶段拒绝:光标变禁止,后续不会有 drop
                }
            }
        }
    }
    返回 (0)
}

异步对话框

Plaintext
方法 对话框结果回调 <公开 类型 = 整数 @强制输出 = 真 @输出名 = "dialogBoxCallback">
参数 数据文本 <类型 = 文本型>
{
    // 结果 JSON 推回前端(也可直接在火山侧处理)
    Jade.发送IPC消息 (主窗口ID, "dialog-result", 数据文本)
    返回 (0)
}
Plaintext
// 打开文件(多选)
Jade.显示打开文件对话框_异步 (主窗口ID, "打开文件", "", "",
        "[{\"name\":\"所有文件\",\"extensions\":[\"*\"]}]",
        "openFile,multiSelections", 本对象, "dialogBoxCallback")

// 消息框(确定/取消,结果 {"response":0})
Jade.显示消息框_异步 (主窗口ID, "提示", "确定要继续吗?", "",
        "[\"确定\",\"取消\"]", 0, 1, 提示框类型.询问, 本对象, "dialogBoxCallback")

系统托盘:图标 + 菜单 + 键名分派

Plaintext
// 创建托盘(图标 + 提示 + 含子菜单/分隔线/禁用项/风险项的菜单)
如果真 (Jade.托盘.创建 ())
{
    Jade.托盘.置图标 (取运行目录 () + "web\\tray.ico")
    Jade.托盘.置提示 ("JadeView 火山视窗 Demo")
    Jade.托盘.添加菜单项 (托盘菜单项类型.普通项, "show", "显示主窗口", "", 假, 假)
    Jade.托盘.添加菜单项 (托盘菜单项类型.分隔线, "sep1", "", "", 假, 假)
    Jade.托盘.添加菜单项 (托盘菜单项类型.子菜单, "sub", "更多操作", "", 假, 假)
    Jade.托盘.添加菜单项 (托盘菜单项类型.普通项, "flash", "任务栏闪烁", "sub", 假, 假)
    Jade.托盘.添加菜单项 (托盘菜单项类型.分隔线, "sep2", "", "", 假, 假)
    Jade.托盘.添加菜单项 (托盘菜单项类型.普通项, "exit", "退出程序", "", 假, 真)   // 风险项标红
}
Plaintext
方法 JadeView_托盘交互事件 <接收事件 类型 = 整数 注释 = "左键点击唤回主窗口。">
参数 来源对象 <类型 = JadeView>
参数 标记值 <类型 = 整数>
参数 事件类型 <类型 = 文本型>
参数 托盘ID <类型 = 整数>
{
    如果 (来源对象 == Jade)
    {
        如果真 (事件类型 == 托盘事件类型.左键点击)
        {
            Jade.窗口.置可视 (主窗口ID, 真)
            Jade.窗口.置焦点 (主窗口ID)
        }
    }
    返回 (0)
}

方法 JadeView_托盘菜单命令事件 <接收事件 类型 = 整数 注释 = "菜单点击按 键名 分派。">
参数 来源对象 <类型 = JadeView>
参数 标记值 <类型 = 整数>
参数 托盘ID <类型 = 整数>
参数 键名 <类型 = 文本型>
参数 项目ID <类型 = 整数>
参数 项目类型 <类型 = 文本型>
参数 已选中 <类型 = 逻辑型>
参数 风险项目 <类型 = 逻辑型>
{
    如果 (来源对象 == Jade)
    {
        如果 (键名 == "show")
        {
            Jade.窗口.置可视 (主窗口ID, 真)
            Jade.窗口.置焦点 (主窗口ID)
        }
        如果 (键名 == "flash")
        {
            Jade.窗口.置任务栏闪烁 (主窗口ID, 10)
        }
        如果 (键名 == "exit")
        {
            Jade.托盘.销毁 ()
            Jade.退出程序 ()
        }
    }
    返回 (0)
}

全局热键:Ctrl+Alt+J 唤回窗口

Plaintext
变量 已注册热键ID <类型 = 整数>

// 注册(74 = 'J' 的虚拟键码)
已注册热键ID = Jade.注册全局热键 (位或 (热键功能键.Control, 热键功能键.Alt), 74)
Plaintext
方法 JadeView_全局热键 <接收事件 类型 = 整数 注释 = "焦点不在本程序也生效。">
参数 来源对象 <类型 = JadeView>
参数 标记值 <类型 = 整数>
参数 窗口ID <类型 = 整数>
参数 热键ID <类型 = 整数>
参数 修饰键 <类型 = 整数>
参数 虚拟键码 <类型 = 整数>
{
    如果 (来源对象 == Jade)
    {
        Jade.窗口.置可视 (主窗口ID, 真)
        Jade.窗口.置焦点 (主窗口ID)
    }
    返回 (0)
}

右键菜单接管:原生项 + 自定义项混排

Plaintext
变量 菜单_复制 <类型 = 整数>
变量 菜单_刷新 <类型 = 整数>
变量 菜单_关于 <类型 = 整数>

// 启动方法中订阅(也可在 初始化 前)
Jade.订阅事件 (订阅_视图事件.菜单事件)
Jade.订阅事件 (订阅_视图事件.自定义菜单事件)
Plaintext
方法 JadeView_菜单事件回调 <接收事件 类型 = 整数 注释 = "右键触发;创建菜单并 置显示,WebView2 弹出原生菜单。">
参数 来源对象 <类型 = JadeView>
参数 标记值 <类型 = 整数>
参数 窗口ID <类型 = 整数>
参数 X坐标 <类型 = 整数>
参数 Y坐标 <类型 = 整数>
参数 菜单场景 <类型 = 文本型>
参数 默认菜单项列表 <类型 = 文本型>
参数 数据 <类型 = 文本型>
{
    如果 (来源对象 == Jade)
    {
        // 每次右键重建(上次创建的先销毁)
        如果真 (菜单_复制 > 0)
        {
            Jade.菜单.销毁 (菜单_复制)
            Jade.菜单.销毁 (菜单_刷新)
            Jade.菜单.销毁 (菜单_关于)
        }
        菜单_复制 = Jade.菜单.创建 (原生菜单项.复制, 菜单类型.默认菜单项, 0, 0)
        菜单_刷新 = Jade.菜单.创建 (原生菜单项.刷新, 菜单类型.默认菜单项, 0, 0)
        菜单_关于 = Jade.菜单.创建 ("关于本应用", 菜单类型.命令, 0, 1001)

        变量 菜单列表 <类型 = 整数数组类>
        菜单列表.加入成员 (菜单_复制)
        菜单列表.加入成员 (菜单_刷新)
        菜单列表.加入成员 (菜单_关于)
        Jade.菜单.置显示 (窗口ID, 菜单列表)
    }
    返回 (0)
}

方法 JadeView_自定义菜单事件 <接收事件 类型 = 整数 注释 = "数据 = 创建时传入的 item_id。">
参数 来源对象 <类型 = JadeView>
参数 标记值 <类型 = 整数>
参数 窗口ID <类型 = 整数>
参数 数据 <类型 = 文本型>
{
    如果 (来源对象 == Jade)
    {
        如果真 (数据 == "1001")
        {
            Jade.打开关于对话框 (窗口ID)
        }
    }
    返回 (0)
}

执行脚本并按请求 id 取结果

Plaintext
// 提交脚本,记下请求 id
变量 请求ID <类型 = 整数>
请求ID = Jade.执行脚本 (主窗口ID, "document.title")
Plaintext
方法 JadeView_脚本执行结果 <接收事件 类型 = 整数 注释 = "数据为 JSON,含 id 与 result。">
参数 来源对象 <类型 = JadeView>
参数 标记值 <类型 = 整数>
参数 窗口ID <类型 = 整数>
参数 数据 <类型 = 文本型>
{
    如果 (来源对象 == Jade)
    {
        变量 结果 <类型 = json_object>
        如果真 (结果.创建自文本 (数据))
        {
            调试输出 ("请求", 结果.取整数 ("id", 0), "结果:", 结果.取文本 ("result", ""))
        }
    }
    返回 (0)
}

YAML 配置持久化

Plaintext
// 写:自动解析("42" 存为数字);写字符串:强制原样存文本
Jade.YAML.写 ("config", "app.name", "我的应用")
Jade.YAML.写 ("config", "window.width", "1200")
Jade.YAML.写字符串 ("config", "raw.code", "12345")

// 读
变量 名称 <类型 = 文本型>
名称 = Jade.YAML.读 ("config", "app.name")

// 键路径操作
如果真 (Jade.YAML.是否存在 ("config", "window.width"))
{
    调试输出 ("keys:", Jade.YAML.列出键 ("config", ""))     // 根节点所有键
    调试输出 ("len:", Jade.YAML.取长度 ("config", "app"))
}
Jade.YAML.删除 ("config", "raw.code")

系统能力速用

Plaintext
// 剪贴板
Jade.系统.置剪贴板文本 ("复制的内容")
调试输出 (Jade.系统.取剪贴板文本 ())

// 系统通知(带按钮,点击经 通知动作 事件回传)
变量 通知选项 <类型 = JadeNotificationOptions>
通知选项.标题 = "任务完成"
通知选项.正文 = "文件已处理完毕"
通知选项.按钮1 = "打开目录"
Jade.显示通知 (通知选项)

// NTP 网络时间(不依赖本机时钟,失败返回 -1)
调试输出 ("UTC 毫秒:", Jade.系统.取网络时间戳 ())

// 文件图标提取(返回 jade:// URL,可直接给前端 <img> 用)
变量 图标地址 <类型 = 文本型>
图标地址 = Jade.系统.取文件图标 ("C:\\Windows\\explorer.exe", 64, 主窗口ID, 0)

// 任务栏进度(配合 进度条状态类型)
Jade.窗口.置任务栏进度 (主窗口ID, 60, 进度条状态类型.正常)

// 开机自启
Jade.系统.置开机自启 (真, "--autostart")