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.
| Plattform | WId-Typ |
|---|---|
| macOS | NSView* |
| Windows | HWND |
| X11 | xcb_window_t |
| iOS | UIView* |
| Android | Anzeigen |
| WebAssembly | emscripten::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.

#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;
}
#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;
}
#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;
}
#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;
}
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;
}
#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");© 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.