Qt for HarmonyOS/user development/embedded subwindow guide zh
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 与鸿蒙子窗的区别
| 类型 | 区别点 |
|---|---|
| 同进程嵌入 |
|
| 跨进程嵌入 |
|
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 与裁剪受父节点影响。
- 多实例场景下,必须在窗口未显示前完成绑定。