Qt for HarmonyOS/user development/embedded subwindow guide zh

From Qt Wiki
< Qt for HarmonyOS
Revision as of 05:59, 6 January 2026 by Shawn Luo (talk | contribs) (Created page with "== 1. 概念与边界 == === 1.1 嵌入式“子窗”是什么 === '''同进程嵌入''' * 不是系统级“窗口”,而是'''当前窗口 root node 下的子 node'''。 * 子 node 内部可挂载 XComponent 进行自渲染。 * 布局、输入、生命周期受 Qt 顶层窗口控制。 '''跨进程嵌入(EmbeddedComponent / EmbeddedUIExtensionAbility)''' * 宿主与内容分属不同进程,Qt 可作为 Provider。 * '''Qt 作为 Provider''':Qt 侧提供...")
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to navigation Jump to search

1. 概念与边界

1.1 嵌入式“子窗”是什么

同进程嵌入

  • 不是系统级“窗口”,而是当前窗口 root node 下的子 node
  • 子 node 内部可挂载 XComponent 进行自渲染。
  • 布局、输入、生命周期受 Qt 顶层窗口控制。

跨进程嵌入(EmbeddedComponent / EmbeddedUIExtensionAbility)

  • 宿主与内容分属不同进程,Qt 可作为 Provider。
  • Qt 作为 Provider:Qt 侧提供窗口内容,由 Host 侧负责嵌入与显示。
  • 可通过绑定键将 Host 实例与 Provider 的 Qt 窗口一一对应(多实例场景)。

1.2 与鸿蒙子窗的区别

类型 区别点
同进程嵌入
  • 不是系统子窗:不会被窗口管理器单独管理,也没有系统级 Z-Order。
  • 无独立生命周期:随 Qt 顶层窗口创建/销毁。
  • 坐标与裁剪受父节点约束:不具备系统层面的跨屏/多窗定位能力。
跨进程嵌入
  • 不是系统子窗:仍不归系统窗口管理器单独管理。
  • 生命周期由 Host 驱动:随 EmbeddedComponent / EmbeddedUIExtensionAbility 会话创建与销毁。
  • 坐标与裁剪由 Host 控制:嵌入区域受 Host 布局与裁剪约束。

2. 类型划分与选型

类型 方式 适用场景 关键 Qt 接口
同进程嵌入 winId()/ Qt::WA_NativeWindow 嵌入 CEF、SDL 等需要原生窗口句柄的第三方渲染 QWidget::winId()、Qt::WA_NativeWindow
跨进程嵌入(Qt 作为 Provider) EmbeddedComponent / EmbeddedUIExtensionAbility 其他宿主嵌入 Qt 内容 QEmbeddedUiExtensionAbility / QtOhosExtras::setBundledAbilityAndQWindowBindingKeyForQWindow()

3. 同进程嵌入

3.1 通过 winId() 触发 native node

适合需要原生窗口句柄的第三方框架(如 CEF、SDL)。核心点:强制创建 native window handle

class NativeNodeHost : public QWidget {
    Q_OBJECT
public:
    explicit NativeNodeHost(QWidget *parent = nullptr)
        : QWidget(parent, Qt::Widget) {
        this->setAttribute(Qt::WA_NativeWindow); // 可选:如果会调用 winId() 可不设置
    }

    void bindThirdPartyRenderer() {
        WId wid = winId();
        QWindow *qw = windowHandle();
        Q_UNUSED(qw);
        // third_party_bind_native_handle(wid);
    }
};

说明:

  • setAttribute(Qt::WA_NativeWindow)与 winId() 是两种方式;通常二选一即可。
  • winId() 会强制 Qt 创建 native window handle,并隐式设置 Qt::WA_NativeWindow。
  • setAttribute(Qt::WA_NativeWindow) 只是标记为 native,实际创建通常发生在 show()/create() 阶段。
  • 触发嵌入式 native node 时,通常要求控件有一个非空 parent(作为嵌入容器)。
  • 若 parent 是顶层窗口,native node 会直接挂在该窗口的根节点层级下。
  • winId() 是单控件强制创建方式,而设置环境变量 QT_USE_NATIVE_WINDOWS=1 是全局方式。


4. 跨进程嵌入(EmbeddedComponent / EmbeddedUIExtensionAbility)

Qt 支持跨进程嵌入。Qt 作为 Provider 时可细分为单实例与多实例。

在 Qt 的 HarmonyOS 工程模板中已预置两种 ExtensionAbility:

  • QEmbeddedUiExtensionAbility:extensionProcessMode: "instance",单实例模式。
  • QBundledEmbeddedUiExtensionAbility:extensionProcessMode: "bundle",多实例模式。

4.1 Qt 作为 Provider(其他框架为 Host)

4.1.1 单进程单实例(QEmbeddedUiExtensionAbility)

  • 适用:同一 Provider 进程只需一个实例。
  • 方式:Host 侧创建 EmbeddedComponent,Provider 侧创建顶层 Qt 窗口并显示即可。

Provider 侧(Qt)最小示例:

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

    auto *window = new QWidget;
    window->setWindowTitle("Single Instance UiExtension");
    window->resize(800, 600);
    window->show();

    return app.exec();
}

4.1.2 单进程多实例(QBundledEmbeddedUiExtensionAbility)

  • 适用:同一 Provider 进程内并发多个实例。
  • 方式:使用绑定键将 Host 实例与 Provider 的 Qt 窗口一一对应。
  • 标准参数名
    io.qt.public.bundledAbilityAndQWindowBindingKey
    

Host 侧(ArkUI)示例要点: 为每个 EmbeddedComponent的 want.parameters 设置唯一绑定键。

private want1: Want = {
  bundleName: 'com.ohos.ohosqttemplate',
  abilityName: 'QBundledEmbeddedUiExtensionAbility',
  moduleName: 'entry',
  parameters: {
    'io.qt.public.bundledAbilityAndQWindowBindingKey': 'A',
  }
}

Provider 侧(Qt)示例要点: 使用接口 QtOhosExtras::setBundledAbilityAndQWindowBindingKeyForQWindow()。

项目 内容
声明 qtohosextras/src/ohosextras/qohoswindowutils.h
参数 window:待绑定的 QWindow;key:唯一绑定键
作用 建立映射,用于多实例对应
QApplication app(argc, argv);

auto getOrCreateUnderlyingQWindow = [](QWidget *widget) {
    widget->winId();
    return widget->windowHandle();
};

auto windowA = makeBundledUiExtensionWindow("A");
QtOhosExtras::setBundledAbilityAndQWindowBindingKeyForQWindow(
    getOrCreateUnderlyingQWindow(windowA.get()), "A");

return app.exec();


5. 常见问题

  • Q: winId() 与 windowHandle() 的差别?
    • A: winId() 会强制生成 native window handle;windowHandle() 在未创建 native handle 前可能为空。
  • Q: 多实例 EmbeddedUIExtensionAbility 为何要绑定键?
    • A: 用于将 Host 的 EmbeddedComponent 与 Provider 的 Qt 窗口一一对应,避免错绑。

6. 注意事项

  • 嵌入式子窗仍处在同一个 Qt 顶层窗口内,Z-Order 与裁剪受父节点影响。
  • 多实例场景下,必须在窗口未显示前完成绑定。

7. 参考资料