Revision control

Copy as Markdown

// Copyright (C) 2024 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
/*!
\title Window Hosting Example
\ingroup examples-widgets
\example demos/windowhosting
\examplecategory {User Interface Components}
\meta {tag} {demo,gui,quick,widgets}
\brief A demonstration of how to host non-Qt UI elements in Qt applications.
Qt offers a wide range of UI controls for both Qt Widget and Qt Quick-based
applications, but sometimes it may be desirable to use controls from other
UI toolkits, such as the platform's native UI toolkit.
To integrate these controls, we build upon the QWindow abstraction in Qt, by creating a
QWindow representation of the native UI control, that can then be hosted within the Qt UI.
A window created in this manner is known in Qt as a \e{foreign window}, as it represents a
control created by a foreign (to Qt) UI toolkit.
\section1 Creating a foreign window
To create the QWindow representation we use QWindow::fromWinId(), passing a reference to a
native window handle, represented by the opaque WId type.
Each platform defines what native type the WId opaque type maps to.
\include platformintegration.qdocinc winid-types
The result is a QWindow that represents the native window handle.
\include platformintegration.qdocinc winid-ownership-note
Now, before we can create a QWindow using QWindow::fromWinId() we need a native window handle.
In this example, we will host a month calendar control, as most platforms have it in their
native UI toolkits, or otherwise readily available. The specifics of how to create the
calendar on each platform are shown in the code snippets below.
To ensure that the native handle stays alive, but is also cleaned up properly on
application exit, we maintain a list of cleanup functions that we execute before
returning from \c main().
In addition to creating the native window handle and turning that into a QWindow,
we also set a minimum size on the resulting QWindow, based on what the native toolkit
reports as the preferred minimum size of the calendar control. This allows
Qt to lay out the hosted foreign window properly.
\if defined(onlinedocs)
\tab {from-win-id}{macos}{macOS}{checked}
\tab {from-win-id}{windows}{Windows}{}
\tab {from-win-id}{x11}{X11}{}
\tab {from-win-id}{ios}{iOS}{}
\tab {from-win-id}{android}{Android}{}
\tab {from-win-id}{webassembly}{WebAssembly}{}
\endif
\if defined(onlinedocs)
\tabcontent {macos}
\else
\section2 macOS
\endif
\inlineimage macos.webp {Qt GUI, Qt Widgets, and Qt Quick windows hosting a macOS calendar}
\snippet demos/windowhosting/main.cpp macos
\if defined(onlinedocs)
\endtabcontent
\endif
\if defined(onlinedocs)
\tabcontent {windows}
\else
\section2 Windows
\endif
\inlineimage windows.webp
{Qt GUI, Qt Widgets, and Qt Quick windows hosting a Windows calendar}
\snippet demos/windowhosting/main.cpp windows
\if defined(onlinedocs)
\endtabcontent
\endif
\if defined(onlinedocs)
\tabcontent {x11}
\else
\section2 X11
\endif
\inlineimage x11.webp {Qt GUI, Qt Widgets, and Qt Quick windows hosting a GTK calendar}
\snippet demos/windowhosting/main.cpp x11
\if defined(onlinedocs)
\endtabcontent
\endif
\if defined(onlinedocs)
\tabcontent {ios}
\else
\section2 iOS
\endif
\inlineimage ios.webp {Qt GUI, Qt Widgets, and Qt Quick containers hosting an iOS calendar}
\snippet demos/windowhosting/main.cpp ios
\if defined(onlinedocs)
\endtabcontent
\endif
\if defined(onlinedocs)
\tabcontent {android}
\else
\section2 Android
\endif
\inlineimage android.webp {Qt GUI, Qt Widgets, and Qt Quick containers hosting an Android calendar}
\snippet demos/windowhosting/main.cpp android
\if defined(onlinedocs)
\endtabcontent
\endif
\if defined(onlinedocs)
\tabcontent {webassembly}
\else
\section2 WebAssembly
\endif
\inlineimage webassembly.webp {Qt GUI, Qt Widgets, and Qt Quick windows hosting a calendar on a WebAssembly calendar}
\snippet demos/windowhosting/main.cpp webassembly
\if defined(onlinedocs)
\endtabcontent
\endif
\section1 Hosting a foreign window
Now that we have a foreign QWindow, we can host it in a Qt UI.
We have several options here, as described below.
\section2 Hosting in Qt GUI
At the lowest level, we can host the foreign window by reparenting it into
another QWindow, via QWindow::setParent(). This approach leaves it up to
the application developer to handle positioning, resizing, and other aspects
of managing the hosted child window, so we generally advise against
integrating on this level, if at all possible.
In this example we first create a minimal container window implementation.
\snippet demos/windowhosting/main.cpp qt-gui-container-window
Which we can then reparent our foreign window into.
\snippet demos/windowhosting/main.cpp qt-gui
\section2 Hosting in Qt Widgets
For applications built on the Qt Widgets UI stack we follow the same approach
as for QWindow::fromWinId(), by creating a QWidget representation of the
QWindow, via QWidget::createWindowContainer().
We could then reparent the widget into another widget, via QWidget::setParent(),
with the same caveats as the Qt GUI example above of having to manage positioning,
resizing, etc. manually. In this example we prefer to add the window container
widget to a QVBoxLayout, which allows us to automatically center the foreign
window inside the top level widget.
\snippet demos/windowhosting/main.cpp qt-widgets
\section2 Hosting in Qt Quick
Finally, for applications built on the Qt Quick UI stack, we use the WindowContainer
item to manage the foreign window.
\snippet demos/windowhosting/Main.qml qt-quick
In this example the foreign window is exposed to the QML engine as an initial property,
but this could be solved in different ways depending on the needs of the application.
\snippet demos/windowhosting/main.cpp qt-quick
*/