跳到主要内容

高级用法

窗口关闭拦截

通过监听 window-closing 事件,您可以拦截窗口关闭行为,例如弹出确认对话框:

from jadeview import events, ipc, dialog

def on_window_closing(window_id, data):
result = dialog.show_message_box(
window_id,
title="确认",
message="确定要关闭窗口吗?",
buttons="确定|取消",
type_="question",
)
if result and result["response"] == 1:
return True # 返回 True 拦截关闭
return None # 返回 None 允许关闭

ipc.on(events.WINDOW_CLOSING, on_window_closing)

IPC 双向通信

Python → 前端

使用 send_ipc_message 向前端推送消息:

# Python 端
ipc.send_ipc_message(window_id, "update-data", {"count": 42})
// 前端 JS
jade.on("update-data", (data) => {
console.log(data.count); // 42
});

前端 → Python

前端使用 jade.invoke(),Python 端使用 register_ipc_handler 接收:

# Python 端
def handle_get_user(window_id, payload):
return {"name": "张三", "age": 30} # dict 自动序列化为 JSON

ipc.register_ipc_handler("get-user", handle_get_user)
// 前端 JS
const user = await jade.invoke("get-user", "some-payload");
console.log(user.name); // "张三"

本地文件服务(协议服务)

JadeView 提供内置的协议服务,将本地目录映射为可访问的 URL:

from jadeview import tools, window

def on_ready(window_id, data):
base_url = tools.set_protocol_service_path("C:/myapp/web")
# base_url 类似 "http://jade.myapp/base/"

window.create_webview_window(
f"{base_url}index.html",
title="本地应用",
)

这种方式比 file:// 协议更安全,避免了跨域限制问题。

系统托盘与菜单

from jadeview import tray, ipc, events

tray_id = 0

def on_ready(window_id, data):
global tray_id
tray_id = tray.tray_create()
tray.tray_set_tooltip(tray_id, "我的应用 - 运行中")
tray.tray_set_icon_from_file(tray_id, "C:/myapp/icon.ico")
tray.tray_set_menu_items(tray_id, [
{"item_type": 0, "key": "show", "label": "显示窗口"},
{"item_type": 1, "key": "theme", "label": "主题"},
{"item_type": 0, "key": "light", "label": "亮色", "parent_key": "theme"},
{"item_type": 0, "key": "dark", "label": "暗色", "parent_key": "theme"},
{"item_type": 2, "key": "sep", "label": ""},
{"item_type": 0, "key": "quit", "label": "退出", "dangerous": 1},
])

def on_tray_menu(window_id, data):
# data 为 JSON 字符串,包含被点击的菜单项 key
print(f"托盘菜单被点击: {data}")

ipc.on(events.TRAY_MENU_COMMAND, on_tray_menu)

全局热键

from jadeview import tools, ipc, events, window

hotkey_id = 0
main_win_id = 0

def on_ready(window_id, data):
global hotkey_id
# 注册 Ctrl+Alt+K
hotkey_id = tools.register_global_hotkey("CTRL+ALT", "K")

def on_hotkey(window_id, data):
print("热键被触发!")
# 例如:将窗口置前
if main_win_id:
window.set_window_focus(main_win_id)

ipc.on(events.GLOBAL_HOTKEY, on_hotkey)

修饰键支持多种写法:

  • 字符串:"CTRL+ALT""CTRL+SHIFT"
  • 列表:["CTRL", "ALT"]
  • 整数:MOD_CONTROL | MOD_ALT

主键支持:

  • 字母:"A" - "Z"
  • 功能键:"F1" - "F24"
  • 特殊键:"Enter""Space""ESC"

YAML 配置持久化

SDK 内置了 YAML 配置存储功能,适合保存用户偏好:

from jadeview import tools

# 写入配置
tools.yaml_set("settings.yaml", "ui.theme", "dark")
tools.yaml_set("settings.yaml", "ui.language", "zh-CN")

# 读取配置
theme = tools.yaml_get("settings.yaml", "ui.theme") # "dark"
lang = tools.yaml_get("settings.yaml", "ui.language") # "zh-CN"

配置文件自动保存在应用数据目录中。

窗口背景效果(Windows 11)

在 Windows 11 上,您可以使用 Mica/Acrylic 等背景效果:

from jadeview import window, tools

def on_ready(window_id, data):
win_id = window.create_webview_window(
"https://example.com",
title="Mica 效果演示",
transparent=1, # 必须启用透明
)

if tools.is_windows_11():
window.set_window_backdrop(win_id, "mica") # Mica 效果
# window.set_window_backdrop(win_id, "micaAlt") # Mica Alt
# window.set_window_backdrop(win_id, "acrylic") # Acrylic 毛玻璃

URL Scheme 与文件关联

from jadeview import tools

# 注册自定义协议 myapp://
tools.register_url_scheme("myapp")

# 注册文件关联 .mydata
tools.register_file_association("mydata", "My Data File")

# 取消注册
tools.unregister_url_scheme("myapp")
tools.unregister_file_association("mydata")

运行时切换边框样式(2.1 新增)

2.1 版本支持在运行时动态切换窗口边框样式,无需销毁重建窗口:

from jadeview import window

# 切换为无标题栏
window.set_window_frame_style(win_id, "no-titlebar")

# 切换为 title-overlay(Windows 专属,标题栏按钮覆盖在内容上)
window.set_window_frame_style(win_id, "title-overlay")

# 自定义 overlay 按钮样式
window.set_titlebar_overlay_style(
win_id,
height=40,
icon_color_hex="#FFFFFF",
hover_bg_hex="#3B3B3B80",
)

# 切回标准边框
window.set_window_frame_style(win_id, "normal")

可选的 frame_style 值:

  • "normal" — 有边框 + 标题栏(默认)
  • "no-titlebar" — 有边框 + 无标题栏
  • "borderless" — 无边框 + 无标题栏
  • "title-overlay" — 有边框 + 标题栏按钮覆盖在内容上(每个按钮宽度 45 像素,高度默认 32 像素)

打印 WebView 内容(2.1 新增)

from jadeview import window

# 打开系统打印对话框
window.jade_print(win_id)

JAPK 资源包加载(2.1 新增)

JAPK 是 JadeView 的资源打包格式,将前端文件(HTML/CSS/JS/图片等)打包为单个 .japk 文件,支持 Ed25519 签名验证。

基本用法

from jadeview import japk, tools, window

def on_ready(window_id, data):
# 1. 设置公钥(用于验证签名)
japk.set_public_key("你的Base64公钥")

# 2. 读取 .japk 文件并加载到内存
with open("app.japk", "rb") as f:
japk.load_from_bytes(f.read())

# 3. 检查是否加载成功
if japk.is_loaded():
print(f"已加载: {japk.get_app_signature()}")
print(f"签名信息: {japk.get_signature_info()}")

# 4. 设置协议服务路径(加载后自动从包内提供资源)
base_url = tools.set_protocol_service_path("japk://")

# 5. 创建窗口
window.create_webview_window(f"{base_url}index.html", title="JAPK App")

运行时切换资源源

from jadeview import japk, tools, webview

def switch_to_japk(window_id, japk_path):
"""切换到 JAPK 包资源"""
with open(japk_path, "rb") as f:
japk.load_from_bytes(f.read())
base_url = tools.set_protocol_service_path(japk_path)
webview.navigate_to_url(window_id, f"{base_url}index.html")
webview.reload(window_id)

def switch_to_directory(window_id, dir_path):
"""切回目录模式"""
japk.unload()
base_url = tools.set_protocol_service_path(dir_path)
webview.navigate_to_url(window_id, f"{base_url}index.html")
webview.reload(window_id)

相关事件

事件说明
japk-load-successJAPK 加载成功时触发
japk-load-failedJAPK 加载失败时触发

应用打包

SDK 支持主流 Python 打包工具,打包时需要手动将 JadeView DLL 包含到输出中。

DLL 搜索机制

SDK 按以下优先级自动搜索 DLL 文件:

  1. 环境变量 JADEVIEW_DLL_PATH — 用户手动指定的目录(最高优先)
  2. PyInstaller 解压目录sys._MEIPASS(PyInstaller 专用)
  3. exe 所在目录sys.executable 的父目录(Nuitka / cx_Freeze 等)
  4. 当前工作目录os.getcwd()
  5. SDK 包内部jadeview/dll/(开发模式)

每个目录下会检查三种文件布局:

  • {dir}/x64/JadeView_x64.dll
  • {dir}/dll/x64/JadeView_x64.dll
  • {dir}/JadeView_x64.dll

PyInstaller

pyinstaller --add-binary "jadeview/dll/x64/JadeView_x64.dll;." --noconsole main.py

或在 .spec 文件中:

a = Analysis(...)
a.binaries += [('JadeView_x64.dll', 'jadeview/dll/x64/JadeView_x64.dll', 'BINARY')]

Nuitka

nuitka --include-data-files=jadeview/dll/x64/JadeView_x64.dll=JadeView_x64.dll --windows-console-mode=disable main.py

如果需要保留子目录结构:

nuitka --include-data-dir=jadeview/dll=dll main.py

cx_Freeze

setup.py 中:

from cx_Freeze import setup, Executable

setup(
executables=[Executable("main.py")],
options={
"build_exe": {
"include_files": [
("jadeview/dll/x64/JadeView_x64.dll", "JadeView_x64.dll"),
],
}
},
)

自定义 DLL 路径

如果以上自动搜索都不满足需求,可通过环境变量指定:

import os
os.environ["JADEVIEW_DLL_PATH"] = "C:/myapp/libs"

import jadeview # 会从 C:/myapp/libs 加载 DLL
提示

32 位 Python 会自动加载 JadeView_x86.dll,64 位 Python 加载 JadeView_x64.dll,无需手动选择。