「Qt Widget中文示例指南」如何实现窗口嵌入?

📅 2026/7/6 20:48:29
「Qt Widget中文示例指南」如何实现窗口嵌入?
Qt是目前最先进、最完整的跨平台C开发工具。它不仅完全实现了一次编写所有平台无差别运行更提供了几乎所有开发过程中需要用到的工具。如今Qt已被运用于超过70个行业、数千家企业支持数百万设备及应用。本文中的示例主要演示如何将非Qt UI元素嵌入到Qt应用程序中。Qt为Qt Widget和基于Qt Quick的应用程序提供了广泛的UI控件但有时可能需要使用来自其他UI工具包的控件例如平台的本地UI工具包。为了集成这些控件我们建立在Qt的QWindow抽象之上通过创建原生UI控件的QWindow表示然后将其嵌入到Qt UI中。以这种方式创建的窗口在Qt中称为外部窗口因为它表示由外部对Qt UI工具包创建的控件。创建外部窗口要创建QWindow表示我们使用QWindow::fromWinId()传递对本机窗口句柄的引用该句柄由不透明的WId类型表示。每个平台定义WId不透明类型映射到的本机类型。结果是一个表示本机窗口句柄的QWindow。注意Qt在创建外部窗口时不会独占拥有本机窗口句柄因此应用程序负责在外部QWindow的生命周期内保持本机窗口的激活。现在在使用QWindow::fromWinId() 创建QWindow 之前我们需要一个本机窗口句柄。在本例中我们将嵌入一个月历控件因为大多数平台在其原生UI工具包中都有它或者其他随时可用的控件。下面的代码片段显示了如何在每个平台上创建日历的细节。为了确保本机句柄保持激活状态并在应用程序退出时正确清理我们维护了一个清理函数列表这些函数在从main()返回之前执行。除了创建本机窗口句柄并将其转换为QWindow之外我们还在生成的QWindow上设置了最小大小基于此本机工具包可以告诉我们日历控件的首选最小大小这允许Qt正确地布局嵌入的外部窗口。macOSWindowsX11iOSAndroid#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; }嵌入外部窗口现在我们有了一个外部的QWindow可以将它嵌入到Qt UI中。在这里有几个选项如下所述。在Qt Gui中嵌入在最底层我们可以通过QWindow::setParent()将外部窗口嵌入到另一个QWindow中这种方法让应用程序开发人员来处理定位、调整大小和管理嵌入子窗口的其他方面所以我们通常建议不要在这个级别上进行集成如果可能的话。在这个例子中我们首先创建一个最小的容器窗口实现。class ContainerWindow : public QRasterWindow { protected: bool event(QEvent *event) override { if (event-type() QEvent::ChildWindowAdded) { auto *childWindow static_castQChildWindowEvent*(event)-child(); childWindow-resize(childWindow-minimumSize()); setMinimumSize(childWindow-size().grownBy(contentsMargins)); resize(minimumSize()); } return QRasterWindow::event(event); } void showEvent(QShowEvent *) override { findChildQWindow*()-setVisible(true); } void resizeEvent(QResizeEvent *) override { auto *containedWindow findChildQWindow*(); 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); } };然后我们就可以重新打开外部窗口。ContainerWindow window; window.setTitle(Qt Gui); auto *calendarWindow createCalendarWindow(); calendarWindow-setParent(window);嵌入Qt小部件对于建立在Qt Widgets UI堆栈上的应用程序我们遵循与QWindow::fromWinId()相同的方法通过QWidget::createWindowContainer()创建QWindow的一个QWidget表示。然后我们可以通过QWidget::setParent()将这个小部件重命名为另一个小部件与上面Qt Gui的例子一样必须手动管理定位、调整大小等。在本例中我们倾向于将窗口容器小部件添加到QVBoxLayout,这允许我们自动将外部窗口居中于顶级小部件内。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);在Qt Quick中嵌入最后对于构建在Qt Quick UI堆栈上的应用程序我们使用WindowContainer项来管理外部窗口。Window { title: Qt Quick color: #2CDE85 required property QtObject calendarWindow; property int contentsMargins: 20 minimumWidth: calendarWindow.minimumWidth contentsMargins * 2 minimumHeight: calendarWindow.minimumHeight contentsMargins * 2 WindowContainer { id: calendar window: calendarWindow width: window.minimumWidth height: window.minimumHeight anchors.centerIn: parent } }在本例中外部窗口作为上下文属性公开给QML引擎但这可以根据应用程序的需要以不同的方式解决。QQmlApplicationEngine engine; engine.setInitialProperties({{ calendarWindow, QVariant::fromValue(createCalendarWindow()) }}); engine.loadFromModule(windowembedding, Main);