Auf dieser Seite

Beispiel für das Einbinden von Fenstern

Eine Demonstration, wie Nicht-Qt-UI-Elemente in Qt-Anwendungen eingebunden werden können.

Qt bietet eine breite Palette an UI-Steuerelementen sowohl für Qt Widgets- als auch für „ Qt Quick “-basierte Anwendungen, doch manchmal kann es wünschenswert sein, Steuerelemente aus anderen UI-Toolkits zu verwenden, wie beispielsweise das native UI-Toolkit der Plattform.

Um diese Steuerelemente zu integrieren, bauen wir auf der „ QWindow “-Abstraktion in Qt auf, indem wir eine „ QWindow “-Darstellung des nativen UI-Steuerelements erstellen, die dann innerhalb der Qt-Benutzeroberfläche eingebettet werden kann. Ein auf diese Weise erstelltes Fenster wird in Qt als „Foreign Window“ bezeichnet, da es ein Steuerelement darstellt, das von einem (für Qt) fremden UI-Toolkit erstellt wurde.

Erstellen eines fremden Fensters

Um die „ QWindow “-Darstellung zu erstellen, verwenden wir ` QWindow::fromWinId()` und übergeben dabei eine Referenz auf ein natives Fenster-Handle, das durch den undurchsichtigen Typ `WId` repräsentiert wird.

Jede Plattform definiert, welchem nativen Typ der opake Typ `WId` zugeordnet ist.

PlattformWId-Typ
macOSNSView*
WindowsHWND
X11xcb_window_t
iOSUIView*
AndroidAnzeigen
WebAssemblyemscripten::val*

Das Ergebnis ist ein ` QWindow `, das das native Fenster-Handle repräsentiert.

Hinweis: Qt übernimmt beim Erstellen eines fremden Fensters nicht die (exklusive) Verantwortung für das native Fenster-Handle, daher ist die Anwendung dafür verantwortlich, das native Fenster für die gesamte Lebensdauer des fremden „ QWindow “ am Leben zu erhalten.

Bevor wir nun mit ` QWindow::fromWinId()` ein ` QWindow ` erstellen können, benötigen wir ein natives Fenster-Handle. In diesem Beispiel werden wir ein Monatskalender-Steuerelement hosten, da die meisten Plattformen dieses in ihren nativen UI-Toolkits enthalten oder es anderweitig leicht verfügbar ist. Die Einzelheiten zur Erstellung des Kalenders auf den einzelnen Plattformen sind in den folgenden Codeausschnitten dargestellt.

Um sicherzustellen, dass das native Handle bestehen bleibt, aber beim Beenden der Anwendung ordnungsgemäß bereinigt wird, führen wir eine Liste von Bereinigungsfunktionen, die wir ausführen, bevor wir von ` main()` zurückkehren.

Neben der Erstellung des nativen Fenster-Handles und dessen Umwandlung in ein ` QWindow` legen wir außerdem eine Mindestgröße für das resultierende ` QWindow` fest, basierend auf der vom nativen Toolkit gemeldeten bevorzugten Mindestgröße des Kalender-Steuerelements. Dies ermöglicht es

Qt, das eingebettete fremde Fenster korrekt anzuordnen.

Qt GUI, Qt Widgets und Qt Quick-Fenster, in denen ein macOS-Kalender eingebettet ist

#include <AppKit/NSDatePicker.h>
#include <AppKit/NSLayoutConstraint.h>

QWindow *createCalendarWindow()
{
    auto *datePicker = [NSDatePicker new];
    cleanupFunctions.push_back([=]{ [datePicker release]; });

    datePicker.datePickerStyle = NSDatePickerStyleClockAndCalendar;
    datePicker.datePickerElements = NSDatePickerElementFlagYearMonthDay;
    datePicker.drawsBackground = YES;
    datePicker.dateValue = [NSDate now];

    auto *calendarWindow = QWindow::fromWinId(WId(datePicker));
    calendarWindow->setMinimumSize(QSizeF::fromCGSize(datePicker.fittingSize).toSize());

    return calendarWindow;
}

Qt GUI, Qt Widgets und Qt Quick-Fenster, in denen ein Windows-Kalender eingebettet ist

#include <windows.h>
#include <commctrl.h>

QWindow *createCalendarWindow()
{
    static bool initializedDateControl = []{
        INITCOMMONCONTROLSEX icex;
        icex.dwSize = sizeof(icex);
        icex.dwICC = ICC_DATE_CLASSES;
        return InitCommonControlsEx(&icex);
    }();
    Q_ASSERT(initializedDateControl);

    HWND monthCalendar = CreateWindow(MONTHCAL_CLASSW,
        nullptr, MCS_NOTODAYCIRCLE | MCS_NOTODAY, 0, 0, 0, 0,
        nullptr, nullptr, GetModuleHandle(nullptr), nullptr);
    cleanupFunctions.push_back([=]{ DestroyWindow(monthCalendar); });

    auto *calendarWindow = QWindow::fromWinId(WId(monthCalendar));

    RECT minimumSize;
    MonthCal_GetMinReqRect(monthCalendar, &minimumSize);
    const auto dpr = calendarWindow->devicePixelRatio();
    calendarWindow->setMinimumSize(QSize(
        minimumSize.right / dpr,minimumSize.bottom / dpr));

    return calendarWindow;
}

Qt GUI, Qt Widgets und Qt Quick-Fenster, in denen ein GTK-Kalender eingebettet ist

#include <gtk/gtk.h>
#include <gtk/gtkx.h>

QWindow *createCalendarWindow()
{
    static bool initializedGTK = []{
        qputenv("GDK_BACKEND", "x11");
        return gtk_init_check(nullptr, nullptr);
    }();
    Q_ASSERT(initializedGTK);

    auto *plug = gtk_plug_new(0);
    g_signal_connect(GTK_WIDGET(plug), "delete-event", G_CALLBACK(+[]{
        return true; // Don't destroy on close
    }), nullptr);
    cleanupFunctions.push_back([=]{ gtk_widget_destroy(GTK_WIDGET(plug)); });

    auto *calendar = gtk_calendar_new();
    gtk_container_add(GTK_CONTAINER(plug), GTK_WIDGET(calendar));
    gtk_widget_show_all(plug);

    auto *calendarWindow = QWindow::fromWinId(gtk_plug_get_id(GTK_PLUG(plug)));

    GtkRequisition minimumSize;
    gtk_widget_get_preferred_size(calendar, &minimumSize, NULL);
    calendarWindow->setMinimumSize(QSize(minimumSize.width, minimumSize.height));

    return calendarWindow;
}

Qt GUI, Qt Widgets und Qt Quick-Container, in denen ein iOS-Kalender eingebettet ist

#include <UIKit/UIDatePicker.h>

QWindow *createCalendarWindow()
{
    auto *datePicker = [UIDatePicker new];
    cleanupFunctions.push_back([=]{ [datePicker release]; });

    datePicker.datePickerMode = UIDatePickerModeDate;
    datePicker.preferredDatePickerStyle = UIDatePickerStyleInline;
    datePicker.backgroundColor = UIColor.systemBackgroundColor;

    auto *calendarWindow = QWindow::fromWinId(WId(datePicker));
    calendarWindow->setMinimumSize(QSizeF::fromCGSize(datePicker.frame.size).toSize());

    return calendarWindow;
}

Qt GUI, Qt Widgets und Qt Quick-Container, in denen ein Android-Kalender eingebettet ist

Q_DECLARE_JNI_CLASS(CalendarView, "android/widget/CalendarView")
Q_DECLARE_JNI_CLASS(Color, "android/graphics/Color")

QWindow *createCalendarWindow()
{
    using namespace QtJniTypes;
    using namespace QNativeInterface;

    auto *androidApp = qGuiApp->nativeInterface<QAndroidApplication>();
    Q_ASSERT(androidApp);

    auto *calendarView = new CalendarView(androidApp->context());
    cleanupFunctions.push_back([=]{ delete calendarView; });

    // Resolving Android default colors is not trivial, so let's ask Qt
    QColor paletteColor = qGuiApp->palette().color(QPalette::Window);
    int backgroundColor = Color::callStaticMethod<int>("rgb",
        paletteColor.red(), paletteColor.green(), paletteColor.blue());
    calendarView->callMethod<void>("setBackgroundColor", backgroundColor);

    auto *calendarWindow = QWindow::fromWinId(WId(calendarView->object()));
    calendarWindow->setMinimumSize(QSize(200, 220));

    return calendarWindow;
}

Qt GUI, Qt Widgets und Qt Quick-Fenster, in denen ein Kalender auf einem WebAssembly-Kalender eingebettet ist

#include <emscripten.h>
#include <emscripten/val.h>
using emscripten::val;
using emscripten::EM_VAL;

EM_JS(EM_VAL, createCalendarElement, (), {
    var calendar = document.createElement("calendar-date");
    calendar.innerHTML = "<calendar-month></calendar-month>";
    return Emval.toHandle(calendar);
});

QWindow *createCalendarWindow()
{
    static bool initializedCalendarComponent = []{
        return EM_ASM_INT(
            var script = document.createElement('script');
            script.src = "https://unpkg.com/cally";
            script.type = "module";
            document.head.appendChild(script);
            return true;
        );
    }();
    Q_ASSERT(initializedCalendarComponent);

    val *calendarElement = new val(val::take_ownership(createCalendarElement()));
    cleanupFunctions.push_back([calendarElement]{ delete calendarElement; });

    QWindow *window = QWindow::fromWinId(WId(calendarElement));
    window->setMinimumSize(QSize(250, 300));
    return window;
}

Ein externes Fenster einbinden

Da wir nun über ein fremdes QWindow verfügen, können wir es in einer Qt-Benutzeroberfläche einbinden. Hierfür stehen uns mehrere Optionen zur Verfügung, die im Folgenden beschrieben werden.

Einbindung in Qt GUI

Auf der untersten Ebene können wir das fremde Fenster einbinden, indem wir es über ` QWindow::setParent()` einem anderen ` QWindow` zuordnen. Bei diesem Ansatz bleibt es dem Anwendungsentwickler überlassen, die Positionierung, Größenanpassung und andere Aspekte der Verwaltung des eingebundenen untergeordneten Fensters zu regeln; daher raten wir generell davon ab,

, die Integration auf dieser Ebene zu vermeiden, sofern dies möglich ist.

In diesem Beispiel erstellen wir zunächst eine minimale Implementierung eines Containerfensters.

class ContainerWindow : public QRasterWindow
{
protected:
    bool event(QEvent *event) override
    {
        if (event->type() == QEvent::ChildWindowAdded) {
            auto *childWindow = static_cast<QChildWindowEvent*>(event)->child();
            childWindow->resize(childWindow->minimumSize());
            setMinimumSize(childWindow->size().grownBy(contentsMargins));
            resize(minimumSize());
        }

        return QRasterWindow::event(event);
    }

    void showEvent(QShowEvent *) override
    {
        findChild<QWindow*>()->setVisible(true);
    }

    void resizeEvent(QResizeEvent *) override
    {
        auto *containedWindow = findChild<QWindow*>();
        containedWindow->setPosition(
            (width() / 2)  - containedWindow->width() / 2,
            (height() / 2) - containedWindow->height() / 2
        );
    }

    void paintEvent(QPaintEvent *) override
    {
        QPainter painter(this);
        painter.fillRect(0, 0, width(), height(), "#00414A");
    }
};

In dieses können wir dann unser fremdes Fenster einbinden.

ContainerWindow window;
window.setTitle("Qt Gui");

auto *calendarWindow = createCalendarWindow();
calendarWindow->setParent(&window);
Hosting in Qt Widgets

Bei Anwendungen, die auf dem UI-Stack „ Qt Widgets “ basieren, verfolgen wir denselben Ansatz wie bei QWindow::fromWinId(), indem wir eine „ QWidget “-Darstellung des „ QWindow “ über QWidget::createWindowContainer() erstellen.

Anschließend könnten wir das Widget über QWidget::setParent() in ein anderes Widget einbinden, wobei dieselben Einschränkungen gelten wie im obigen Beispiel Qt GUI, nämlich dass Positionierung, Größenanpassung usw. manuell verwaltet werden müssen. In diesem Beispiel ziehen wir es vor, das Fenster-Container-Widget zu einem QVBoxLayout hinzuzufügen, wodurch wir das fremde Fenster automatisch innerhalb des Widgets der obersten Ebene zentrieren können.

QWidget widget;
widget.setPalette(QColor("#CDB0FF"));
widget.setWindowTitle("Qt Widgets");
widget.setLayout(new QVBoxLayout);
widget.layout()->setContentsMargins(contentsMargins);
widget.layout()->setAlignment(Qt::AlignCenter);

auto *calendarWidget = QWidget::createWindowContainer(createCalendarWindow());
widget.layout()->addWidget(calendarWidget);
Einbindung in Qt Quick

Schließlich verwenden wir für Anwendungen, die auf dem UI-Stack „ Qt Quick “ basieren, das Element „ WindowContainer “, um das fremde Fenster zu verwalten.

Window {
    id: root
    title: "Qt Quick"
    color: "#2CDE85"

    property alias calendarWindow: calendar.window

    property int contentsMargins: 20

    minimumWidth: calendarWindow.minimumWidth + contentsMargins * 2
    minimumHeight: calendarWindow.minimumHeight + contentsMargins * 2

    WindowContainer {
        id: calendar
        width: window.minimumWidth
        height: window.minimumHeight
        anchors.centerIn: parent
    }
}

In diesem Beispiel wird das fremde Fenster der QML-Engine als „initial“-Eigenschaft zur Verfügung gestellt, doch je nach den Anforderungen der Anwendung gibt es auch andere Lösungsansätze.

QQmlApplicationEngine engine;
engine.setInitialProperties({{ "calendarWindow", QVariant::fromValue(createCalendarWindow()) }});
engine.loadFromModule("windowhosting", "Main");

Beispielprojekt @ code.qt.io

© 2026 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.