Skip to content

UI 扩展(QML) ​

用 QML 替换宿主的界面组件(底板、音柱、字幕视图、装饰…)。 槽位清单与背景绘制准则见 UI 插槽——本页只讲怎么写。


声明 ​

type 用 theme(局部插槽扩展建议 style_layer: "effects"):

json
{
  "id": "community.theme.neon_wave",
  "name": "极光霓虹律动波形条",
  "version": "1.0.0",
  "target_app_version": "0.2",
  "type": "theme",
  "style_layer": "effects",
  "ui_extensions": {
    "audio_level": "CustomWaveform.qml"
  },
  "enabled": false
}

只使用宿主已消费的槽位;overlay_root / style_bar 当前无 Loader,勿用。


注入属性 ​

属性适用说明
hostContext悬浮窗类style / subtitle / audio / window / invoke
bridge全部公开槽(与 Host SPI 对齐),如 bridge.getPluginConfig(pluginId)
pluginId全部你的插件 id
appState背景组件全局应用状态(bgColor / bgOpacity / neonBorderColor…)
window / targetWindow背景组件目标窗体实例指针
customRadius背景组件宿主注入的目标窗口圆角(设置中心 16、历史窗 16、通用弹窗 12…)
hovered悬浮窗是否处于鼠标悬停态

组件声明了对应 property 才会被赋值——不需要的就别声明。

完整属性与 HostContext 见 QML 界面插槽与 HostContext。


配置读取:必须有 Connections ​

⚠️ bridge.getPluginConfig(pluginId) 是瞬态函数调用,不是 QML 响应式属性。 只读一次的话,用户在设置面板改开关时你的组件不会更新。

qml
import QtQuick 2.15

Item {
    id: root
    anchors.fill: parent

    readonly property string myPluginId: "community.theme.my_theme"

    // 1. 初始读取
    property var cfg: (typeof bridge !== "undefined" && bridge && bridge.getPluginConfig)
        ? bridge.getPluginConfig(root.myPluginId) : ({})

    // 2. 解包 + 默认值
    readonly property bool enableGlow: (cfg && typeof cfg.neon_glow !== "undefined") ? cfg.neon_glow : true

    // 3. 必须监听信号,热刷新 cfg
    Connections {
        target: (typeof bridge !== "undefined") ? bridge : null
        function onPluginConfigChanged(pid) {
            if (pid === root.myPluginId) {
                root.cfg = bridge.getPluginConfig(root.myPluginId) || ({})
            }
        }
    }

    // 4. 绑定到视觉图层
    Rectangle {
        anchors.fill: parent
        visible: root.enableGlow
        border.color: "#00f0ff"
        border.width: 1.5
    }
}

视觉规范(硬要求) ​

  • 所有插件 QML 必须通过 ThemeTokens 与 PluggableWindowBackground 自动适配主题切换。
  • 禁止用 Emoji 或文本字符充当图标,必须使用矢量 SVG(ThemeTokens.icon 或插件自带 SVG)。
  • 组件里不要写死字体族/图标色——写死会在用户换主题时穿帮;用 ThemeTokens.*。
  • 背景类插槽必须自绘边框与圆角自适应,详见 UI 插槽 § 背景插槽准则。

调用插件的 Python 动作 ​

QML 侧通过槽位调插件的 action_*:

qml
// 同步(会阻塞 UI 线程,只适合瞬时动作)
bridge.invokePluginAction(pluginId, "run", {"source": "ui"})

// 耗时动作请用异步版,或让 Python 侧走 self.run_in_background()
bridge.invokePluginActionAsync(pluginId, "ask", {"prompt": "…"})

插件发上来的事件在 QML 里由 pluginEvent(plugin_id, event_name, payload) 接收, 见 事件总线。


热调试 ​

改 QML 后:停用再启用插件即可重载;或重启应用(开发期可用 TRANSBOX_QML_RELOAD=1 的宿主热重载能力,见 热调试)。


相关 ​

TransBox - 赋能全人类无界限跨语言交流