Qt小知识4.QWindow和QWidget
1 引言
QWindow 和 QWidget 都是 Qt 框架中用于创建和管理窗口的类,但它们在设计上服务于不同的目的和场景。这两者的区别不仅体现在 API 设计上,还体现在它们在 Qt 框架中的角色和使用方式上。
2 典型区别
2.1 继承结构和依赖
- QWidget 继承自 QObject 和 QPaintDevice,是所有窗口部件的基类。它是 Qt Widgets 模块的一部分,主要用于传统的桌面应用程序,依赖于 Qt 的 QApplication。
- QWindow 直接继承自 QObject 和 QSurface,代表一个可以有可视化输出的窗口。它是 Qt GUI 模块的一部分,可以用于更接近系统底层的窗口创建,依赖于 Qt 的 QGuiApplication。
2.2 使用场景
- QWidget 适合于需要丰富交互界面的传统桌面应用程序开发,提供了按钮、文本输入框等内置界面元素,以及布局管理器来自动管理元素布局。
- QWindow 更多用于需要直接使用 OpenGL 或 Vulkan 这类底层图形API进行渲染的场景,或者是当需要创建一个不附加任何传统控件的轻量级窗口时。
2.3 绘图和渲染
- QWidget 支持 Qt 的绘图机制,可以通过重写 paintEvent 方法并使用 QPainter API 实现绘图。
- QWindow 的绘图通常依赖于更底层的图形系统,例如直接与 OpenGL 上下文集成。虽然 QWindow 也可以使用 QPainter 通过 QBackingStore 进行绘图,但这不是其主要用途。
3 为什么引入QWindow?
-
更清晰的分层架构
在 Qt 5 之前的版本中,所有的窗口部件都是基于 QWidget 构建的,这意味着即使是不需要复杂部件和布局系统的简单窗口,也需要引入整个 QWidget 系统。QWindow 的引入提供了一个更轻量级的选择,允许创建窗口而不必带上全部 QWidget 的开销。 -
支持现代图形APIs
QWindow 提供了一个平台无关的窗口句柄(handle),这使得开发者可以更直接地使用 OpenGL、Vulkan、DirectX 等现代图形API来进行底层渲染。这对于需要高性能渲染的应用程序,如游戏或高端图形模拟,是非常重要的。 -
促进 Qt Quick 的发展
随着 Qt Quick 和 QML 的引入,需要一个能够与新的场景图(scene graph)渲染系统无缝集成的窗口类。QWindow 扮演着这个角色,它可以容纳一个完整的 Qt Quick UI,与底层图形系统有效协作。 -
跨平台的窗口管理
QWindow 封装了操作系统的窗口管理功能,提供了跨平台的窗口创建、事件处理、窗口状态管理等,这使得开发者可以写出更加跨平台通用的代码,而不需要关心底层操作系统的特定实现。 -
变得更加模块化
随着开发者对模块化应用程序的需求日益增加,QWindow 类使得 Qt 框架能够提供更加模块化的组件。开发者可以选择只使用图形模块来创建窗口和管理底层图形,而不必加载和依赖更多的 QWidget 功能。
4 依赖关系
在 Qt 5 之前,Qt 的 Widgets 系统和其窗口系统是紧密耦合的,QWidget 直接处理所有与窗口相关的操作,如显示、事件处理等。随着 Qt 5 的推出以及 Qt Quick(基于 QML 的高性能界面技术)的引入,Qt 架构师重新设计了图形和窗口系统的底层架构来提高其性能和灵活性。QWindow 被引入为这个新架构的核心组件之一。
从 Qt 5 开始,QWidget 的实现在内部是依赖于 QWindow 的。这是 Qt 为了整合其图形和窗口系统架构做出的设计决策。这种依赖关系主要体现在:每个 QWidget(或者更具体地说,每个 QWidget 的顶层窗口)背后都有一个 QWindow 实例负责实际的窗口管理和底层图形操作。
4.1 如何理解?
-
窗口实例:当你创建一个 QWidget 并且使其成为一个窗口(即没有父对象或者通过调用 setWindowFlags 方法),Qt 内部会为这个 QWidget 创建一个 QWindow 实例。这个 QWindow 实例是实际上与操作系统层进行交互的对象,负责窗口的显示、事件的接收等。对于嵌入在其他 QWidget 中的 QWidget,它们共享同一个 QWindow 实例,因为在操作系统层面,它们实际上属于同一个窗口。
-
绘图与渲染:虽然 QWidget 和 QWindow 都可以进行绘图和渲染操作,但它们的目的和方法不同。QWidget 的绘图是基于 QPainter 的,更适合传统的 GUI 应用程序。而 QWindow 则给予了开发者直接使用 OpenGL 或 Vulkan 等现代图形 API 的能力。在 QWidget 中,绘图最终还是通过它关联的 QWindow 实现的,因为所有的图形输出都是通过操作系统的窗口系统完成的。
4.2 实际应用
在实际的应用程序设计中,开发者通常不需要直接处理 QWindow,除非他们在进行一些较为底层的图形操作或创建高度定制化的窗口。QWidget 和 QWindow 的设计让 Qt 能够支持从简单的桌面应用程序到复杂的图形密集型应用程序的广泛需求。
虽然从API使用者角度看 QWidget 和 QWindow 是分开的,但从 Qt 的内部实现来看,QWidget 的窗口展示功能是依赖 QWindow 的,这样做既保留了 Qt Widgets 的高层次抽象方便开发传统应用,又能从底层支持现代的图形显示需求。
5 总结
使用 QWidget 创建图形用户界面相对简单,并且可以直接利用 Qt 的丰富的控件和布局系统。而选择 QWindow 可能需要更多底层的操作,但它可以更灵活地与底层图形API集成,适用于特定的高性能渲染场景或当需要直接控制渲染循环时。
每一步踏出,都是一次探索,一次成长。