Jump to content

Qt for HarmonyOS/user development guide/embedded subwindow guide: Difference between revisions

From Qt Wiki
No edit summary
edit display of bold words
Line 6: Line 6:


'''In-Process Embedding'''
'''In-Process Embedding'''
* It is not a system-level "window", but a **child node under the root node of the current window**.
* It is not a system-level "window", but a '''child node under the root node of the current window'''.
* An XComponent can be mounted inside the child node for custom rendering.
* An XComponent can be mounted inside the child node for custom rendering.
* Layout, input events, and lifecycle are controlled by the Qt top-level window.
* Layout, input events, and lifecycle are controlled by the Qt top-level window.
Line 12: Line 12:
'''Cross-Process Embedding (EmbeddedComponent / EmbeddedUIExtensionAbility)'''
'''Cross-Process Embedding (EmbeddedComponent / EmbeddedUIExtensionAbility)'''
* The host and the content run in separate processes; Qt can act as the Provider.
* The host and the content run in separate processes; Qt can act as the Provider.
* **Qt as the Provider**: The Qt side provides window content, while the Host side handles embedding and display.
* '''Qt as the Provider''': The Qt side provides window content, while the Host side handles embedding and display.
* A binding key can be used to map Host instances to Qt windows on the Provider side one-to-one (for multi-instance scenarios).
* A binding key can be used to map Host instances to Qt windows on the Provider side one-to-one (for multi-instance scenarios).


Line 21: Line 21:
|-
|-
| '''In-Process Embedding'''
| '''In-Process Embedding'''
|  
|
* **Not a system subwindow**: Not managed individually by the window manager, and has no system-level Z-Order.
* '''Not a system subwindow''': Not managed individually by the window manager, and has no system-level Z-Order.
* **No independent lifecycle**: Created and destroyed along with the Qt top-level window.
* '''No independent lifecycle''': Created and destroyed along with the Qt top-level window.
* **Position and clipping constrained by the parent node**: No system-level cross-screen or multi-window positioning capability.
* '''Position and clipping constrained by the parent node''': No system-level cross-screen or multi-window positioning capability.
|-
|-
| '''Cross-Process Embedding'''
| '''Cross-Process Embedding'''
|  
|
* **Not a system subwindow**: Still not managed individually by the system window manager.
* '''Not a system subwindow''': Still not managed individually by the system window manager.
* **Lifecycle driven by the Host**: Created and destroyed along with the EmbeddedComponent / EmbeddedUIExtensionAbility session.
* '''Lifecycle driven by the Host''': Created and destroyed along with the EmbeddedComponent / EmbeddedUIExtensionAbility session.
* **Position and clipping controlled by the Host**: The embedded area is constrained by the Host's layout and clipping.
* '''Position and clipping controlled by the Host''': The embedded area is constrained by the Host's layout and clipping.
|}
|}


Line 47: Line 47:
=== 3.1 Triggering a Native Node via winId() ===
=== 3.1 Triggering a Native Node via winId() ===


Suitable for third-party frameworks that require a native window handle (e.g., CEF, SDL). Core point: **Force the creation of a native window handle**.
Suitable for third-party frameworks that require a native window handle (e.g., CEF, SDL). Core point: '''Force the creation of a native window handle.'''


<syntaxhighlight lang="cpp">
<syntaxhighlight lang="cpp">class NativeNodeHost : public QWidget {
class NativeNodeHost : public QWidget {
     Q_OBJECT
     Q_OBJECT
public:
public:
Line 64: Line 63:
         // third_party_bind_native_handle(wid);
         // third_party_bind_native_handle(wid);
     }
     }
};
};</syntaxhighlight>
</syntaxhighlight>


'''Notes:'''
'''Notes:'''
* setAttribute(Qt::WA_NativeWindow) and winId() are **two separate approaches**; usually either one is sufficient.
* setAttribute(Qt::WA_NativeWindow) and winId() are '''two separate approaches'''; usually either one is sufficient.
* winId() forces Qt to create a native window handle and implicitly sets Qt::WA_NativeWindow.
* winId() forces Qt to create a native window handle and implicitly sets Qt::WA_NativeWindow.
* setAttribute(Qt::WA_NativeWindow) only marks the widget as native; actual creation typically occurs during show() / create().
* setAttribute(Qt::WA_NativeWindow) only marks the widget as native; actual creation typically occurs during show() / create().
* When triggering an embedded native node, the widget is generally required to have a **non-null parent** (as the embedding container).
* When triggering an embedded native node, the widget is generally required to have a '''non-null parent''' (as the embedding container).
* If the parent is a top-level window, the native node is attached directly to the root node level of that window.
* If the parent is a top-level window, the native node is attached directly to the root node level of that window.
* winId() is a **per-widget** forced creation method, while setting the environment variable QT_USE_NATIVE_WINDOWS=1 is a **global** method.
* winId() is a '''per-widget''' forced creation method, while setting the environment variable QT_USE_NATIVE_WINDOWS=1 is a '''global''' method.


== 4. Cross-Process Embedding (EmbeddedComponent / EmbeddedUIExtensionAbility) ==
== 4. Cross-Process Embedding (EmbeddedComponent / EmbeddedUIExtensionAbility) ==
Line 106: Line 104:
==== 4.1.2 Single Process, Multiple Instances (QBundledEmbeddedUiExtensionAbility) ====
==== 4.1.2 Single Process, Multiple Instances (QBundledEmbeddedUiExtensionAbility) ====
* '''Applicable to''': Multiple concurrent instances within the same Provider process.
* '''Applicable to''': Multiple concurrent instances within the same Provider process.
* '''Method''': Use a **binding key** to map each Host instance to a corresponding Qt window on the Provider side.
* '''Method''': Use a '''binding key''' to map each Host instance to a corresponding Qt window on the Provider side.
* '''Standard parameter name''': <code>io.qt.public.bundledAbilityAndQWindowBindingKey</code>.
* '''Standard parameter name''': <code>io.qt.public.bundledAbilityAndQWindowBindingKey</code>.


Line 160: Line 158:


* Embedded subwindows remain inside the same Qt top-level window; their Z-Order and clipping are affected by the parent node.
* Embedded subwindows remain inside the same Qt top-level window; their Z-Order and clipping are affected by the parent node.
* In multi-instance scenarios, binding **must be completed before the window is shown**.
* In multi-instance scenarios, binding must be '''completed before the window is shown'''.


== 7. References ==
== 7. References ==

Revision as of 02:30, 30 January 2026

English 中文

1. Concepts and Scope

1.1 What is an Embedded Subwindow

In-Process Embedding

  • It is not a system-level "window", but a child node under the root node of the current window.
  • An XComponent can be mounted inside the child node for custom rendering.
  • Layout, input events, and lifecycle are controlled by the Qt top-level window.

Cross-Process Embedding (EmbeddedComponent / EmbeddedUIExtensionAbility)

  • The host and the content run in separate processes; Qt can act as the Provider.
  • Qt as the Provider: The Qt side provides window content, while the Host side handles embedding and display.
  • A binding key can be used to map Host instances to Qt windows on the Provider side one-to-one (for multi-instance scenarios).

1.2 Differences from HarmonyOS System Subwindows

Type Key Differences
In-Process Embedding
  • Not a system subwindow: Not managed individually by the window manager, and has no system-level Z-Order.
  • No independent lifecycle: Created and destroyed along with the Qt top-level window.
  • Position and clipping constrained by the parent node: No system-level cross-screen or multi-window positioning capability.
Cross-Process Embedding
  • Not a system subwindow: Still not managed individually by the system window manager.
  • Lifecycle driven by the Host: Created and destroyed along with the EmbeddedComponent / EmbeddedUIExtensionAbility session.
  • Position and clipping controlled by the Host: The embedded area is constrained by the Host's layout and clipping.

2. Type Classification and Selection

Type Method Applicable Scenarios Key Qt Interfaces
In-Process Embedding winId() / Qt::WA_NativeWindow Embedding third-party renderers requiring native window handles, such as CEF, SDL QWidget::winId(), Qt::WA_NativeWindow
Cross-Process Embedding (Qt as Provider) EmbeddedComponent / EmbeddedUIExtensionAbility Embedding Qt content into other host applications QEmbeddedUiExtensionAbility / QtOhosExtras::setBundledAbilityAndQWindowBindingKeyForQWindow()

3. In-Process Embedding

3.1 Triggering a Native Node via winId()

Suitable for third-party frameworks that require a native window handle (e.g., CEF, SDL). Core point: Force the creation of a native window handle.

class NativeNodeHost : public QWidget {
    Q_OBJECT
public:
    explicit NativeNodeHost(QWidget *parent = nullptr)
        : QWidget(parent, Qt::Widget) {
        this->setAttribute(Qt::WA_NativeWindow); // Optional; not required if winId() is called
    }

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

Notes:

  • setAttribute(Qt::WA_NativeWindow) and winId() are two separate approaches; usually either one is sufficient.
  • winId() forces Qt to create a native window handle and implicitly sets Qt::WA_NativeWindow.
  • setAttribute(Qt::WA_NativeWindow) only marks the widget as native; actual creation typically occurs during show() / create().
  • When triggering an embedded native node, the widget is generally required to have a non-null parent (as the embedding container).
  • If the parent is a top-level window, the native node is attached directly to the root node level of that window.
  • winId() is a per-widget forced creation method, while setting the environment variable QT_USE_NATIVE_WINDOWS=1 is a global method.

4. Cross-Process Embedding (EmbeddedComponent / EmbeddedUIExtensionAbility)

Qt supports cross-process embedding. When Qt acts as the Provider, it can be divided into single-instance and multi-instance modes.

Two ExtensionAbility types are pre-configured in the Qt HarmonyOS project template:

  • QEmbeddedUiExtensionAbility: extensionProcessMode: "instance", single-instance mode.
  • QBundledEmbeddedUiExtensionAbility: extensionProcessMode: "bundle", multi-instance mode.

4.1 Qt as the Provider (Other Frameworks as Host)

4.1.1 Single Process, Single Instance (QEmbeddedUiExtensionAbility)

  • Applicable to: Only one instance is needed in the same Provider process.
  • Method: The Host creates an EmbeddedComponent, and the Provider creates and shows a top-level Qt window.

Minimal Provider-side (Qt) example:

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 Single Process, Multiple Instances (QBundledEmbeddedUiExtensionAbility)

  • Applicable to: Multiple concurrent instances within the same Provider process.
  • Method: Use a binding key to map each Host instance to a corresponding Qt window on the Provider side.
  • Standard parameter name:
    io.qt.public.bundledAbilityAndQWindowBindingKey
    
    .

Host-side (ArkUI) example key points: Set a unique binding key in want.parameters for each EmbeddedComponent.

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

Provider-side (Qt) example key points: Use the interface QtOhosExtras::setBundledAbilityAndQWindowBindingKeyForQWindow().

Item Details
Declaration qtohosextras/src/ohosextras/qohoswindowutils.h
Parameters window: The QWindow to bind; key: Unique binding key
Function Establishes a mapping for multi-instance correspondence
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. Frequently Asked Questions

  • Q: What is the difference between winId() and windowHandle()?
    • A: winId() forces the generation of a native window handle; windowHandle() may return null before the native handle is created.
  • Q: Why is a binding key required for multi-instance EmbeddedUIExtensionAbility?
    • A: It maps the Host's EmbeddedComponent to the corresponding Qt window on the Provider side, preventing incorrect bindings.

6. Notes

  • Embedded subwindows remain inside the same Qt top-level window; their Z-Order and clipping are affected by the parent node.
  • In multi-instance scenarios, binding must be completed before the window is shown.

7. References