当前位置: 首页 > news >正文

「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正确地布局嵌入的外部窗口。

macOS

Windows

X11

iOS

Android

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

然后我们就可以重新打开外部窗口。

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");
http://www.jsqmd.com/news/1136997/

相关文章:

  • AI-Scientist:全自动科研助手的3大核心模板与实战指南
  • 界面控件Telerik UI for WPF 2024 Q3亮点 - 支持禁用数据过滤等
  • SQL注入攻防实战:从原理到靶场复现与系统化防御
  • EventReduce与传统数据库优化的对比:为什么94%的事件可以被优化?
  • Path of Building:流放之路玩家必备的终极离线Build规划神器
  • EhViewer开源Android应用:如何解决现代画廊浏览器的架构挑战?
  • 为什么选择Gas Town?企业级AI工作流管理的7大核心优势
  • Inspector Spacetime:动画设计师的终极数据提取神器,5步彻底告别手动记录
  • YOLO目标检测实战:从环境搭建到自定义模型训练全流程指南
  • 如何从零开始掌握STM32机器人嵌入式开发:20个实战例程完整指南
  • hifi3dface项目详解:如何从RGB-D自拍照创建高保真3D数字人?完整指南
  • 时间序列分解实战:Python statsmodels 0.14 加法与乘法分解 5 步代码详解
  • django-role-permissions核心功能解析:角色定义、权限检查与用户管理全攻略
  • DevExpress中文教程 - 如何使用AI模型检查HTML编辑中的语法?
  • Sketch Simplification完全指南:从安装到生成高质量线稿的完整流程
  • M3u8Downloader_H高级技巧:自定义请求头与代理配置的10个实用技巧
  • 3分钟上手!assessment-mindset思维导图快速使用指南(附XMind导入教程)
  • Gemini API接入全指南:GCP项目配置、服务账号认证与多模态调用实战
  • NiGui未来路线图:即将到来的macOS支持与新特性预览
  • FutureKit网络请求封装:从Alamofire到URLSession的异步转换
  • 工业自动化中的多路信号采集与MC74HC165A应用
  • 「Java开发指南」如何自定义Spring代码生成?(一)
  • 高效准备Java面试:避开这5个常见误区
  • EhViewer:终极开源漫画浏览器 - 免费无广告的Android漫画阅读神器
  • 如何帮助旅行社老板打造个人IP品牌?
  • 硬件 TCP/IP 加持的以太网单片机,MicroPython 零门槛开发
  • DataEase开源BI工具:如何在3分钟内做出明智的版本选择决策
  • 逆向工程实战:解密网易云音乐NCM加密格式
  • 「Qt Widget中文示例指南」如何创建一个窗口标志?(一)
  • SDC命令详解:使用get_nets命令进行查询