【Qt】窗口体系

在这里插入图片描述

竹杖芒鞋轻胜马,谁怕?一蓑烟雨任平生~
公众号: C++学习与探索  |  个人主页: rainInSunny  |  个人专栏: Learn OpenGL In Qt

窗口体系

WindowFlags

  使用 Qt 作为 UI 框架离不开 QWidget,Qt 作为一个跨平台框架,QWidget 具备了展示界面和响应用户事件的基本功能,但不同平台这两者的实现都是有差异的,下面探讨下 QWidget 是如何屏蔽差异以及 Qt 的窗口体系是怎样的。
  刚接触 QWidget 的时候基本都停留在使用层面,对 Qt 提供的 QWidget、QDialog、QPopup等差异不太了解,后来才发现它们之间是通过 Qt 中的 WindowFlags 区分的。
在这里插入图片描述
  图中给出了 Qt 中各种 WindowFlags 标识。对于 QDialog、QPopup、QTool 和 QToolTip 这类的标识比较容易理解,是表明了控件的基本形态,但是 QWindow 这个标识不太好理解,另外值得注意的是 QWidget 默认是不包含 QWindow 标识的,但很多表示例如 QDialog 是包含了 Window 标识的。那么到底什么样的 Widget 才算一个 Window 呢?
  要理解这一点得先看看 Qt 窗口体系的基本实现:
在这里插入图片描述
  图中大致表达了 Qt 窗口体系的层级关系。其中横向表示继承关系,纵向表示组合关系。这里以 Qt 在 iOS 平台上的封装实现举例子,其它平台是类似的。

  • 首先是最底层的 QUIView,继承了 iOS 平台原生的 UIView。显然在 iOS 平台上,所有的事件都会由操作系统传递给这里的 QUIView,然后经过 Qt 的层层封装后传递到 QWidget 体系。
  • 然后是 QIOSWindow 继承自 QPlatformWindow,并且包含了 QUIView 的实例,这里可以看出 QPlatformWindow 在各个平台上都会由子类来具体实现其中的接口。通过 QPlatformWindow 的抽象,Qt 屏蔽了不同操作系统底层的差异。
  • 其次是 QWidgewtWindow 继承自 QWindow,这里的 QWindowPrivate 可以理解为是为了保证良好的二进制兼容特性引入的,类似于 pImpl 模式。
  • 最后是 QWidgetPrivate(等价于 QWidget) 中包含了 QWidget。注意这里用了虚线箭头,表明不是所有的 QWidget 都包含了 QWidgetWindow。

  现在接着回到上一个问题,从窗口层级图中可以看出,当一个 Widget 需要包含一个原生窗口时,那么这个窗口就是一个 Window。例如一个顶层窗口(没有父窗体)或者 QDialog 内部都包含了 iOS 原生窗口 QUIView,而一个 Widget 内部的子控件通常不需要创建原生窗口,这样的子 Widget 不包含 Window 标识。

window函数

在这里插入图片描述
  QWidget 提供了 window() 接口,根据 Qt 说明,该接口会返回当前 Widget 父窗口中最近的具有 Window 标识的窗口。这也表明整个 Qwidget 体系中至少需要一个原生窗口与操作系统层面进行交互。

QWidget什么时候创建QWindow?

在这里插入图片描述
  一开始以为 QWidget 在构造函数中就会创建原生窗口,经过调试发现不是,是在 show() 函数调用后会创建原生窗口。可以通过 windowHandle() 接口获取对应的 QWindow。

能不能手动控制创建原生窗口?

在这里插入图片描述
  Qt 提供了 winId() 接口来强行创建原生窗口,任何 Widget 调用该接口后都会创建自己的原生窗口。但是要注意创建原生窗口会破坏 Qt 的跨平台特性。这类原生窗口的层级会高于非原生窗口的层级,这是因为 Qt 的非原生 Widget 不包含 QWindow,本质上是在父窗口上绘制上去的。如果其中一个子控件调用 winId 变成了原生窗口,那么它将不再是绘制在父窗口上,而是单独呈现在一个 UIView 上,可以理解为其它子控件都是绘制在下层窗口(UIView)上,但是变成原生窗口的子控件会单独绘制在上层的 UIView 上,这样它的同级控件都会被它遮挡住。

总结

  • Qt 通过 QPlatformWindow 屏蔽了不同系统窗口的实现差异,QPlatformWindow 以上是平台无关的实现,以下是平台相关的实现。
  • Qt 中不是所有 Widget 都具备 Window 标识,创建了 QWindow 以及底层原生窗口的 Widget 会具备 Window 标识。
  • QWidget 是在 show() 函数调用后会创建 QWindow 和底层原生窗口。
  • 通过 winId() 可以为任何 Widget 创建底层原生窗口,但是会破坏 Qt 窗口的跨平台特性,还会引入层级问题。

关注公众号:C++学习与探索,有惊喜哦~

### QT 窗口布局使用方法 在 Qt 中,窗口布局通过 `QLayout` 类及其子类实现。这些布局管理器可以自动调整控件的位置和大小,从而适应不同屏幕尺寸或分辨率的变化。以下是关于如何使用 Qt 布局系统的详细介绍。 #### 1. **基本概念** Qt 的布局系统由多个类组成,主要包括以下几种常见的布局方式: - 水平布局 (`QHBoxLayout`):将控件按水平方向排列。 - 垂直布局 (`QVBoxLayout`):将控件按垂直方向排列。 - 网格布局 (`QGridLayout`):将控件放置在一个二维表格中。 - 表单布局 (`QFormLayout`):适用于表单样式的界面设计。 每种布局都有其适用场景,开发者可以根据实际需求选择合适的布局方案[^1]。 #### 2. **设置外边距** 默认情况下,Qt 控件的外边距为 0。如果需要自定义边距,可以通过以下函数来设置: ```cpp setContentsMargins(int left, int top, int right, int bottom); ``` 或者更简洁的方式: ```cpp setContentsMargins(QMargins margins); ``` 这允许开发人员灵活控制窗口内部空间的设计[^3]。 #### 3. **示例代码** 下面是一个简单的例子,展示如何在 Qt 应用程序中应用不同的布局: ```cpp #include <QApplication> #include <QWidget> #include <QPushButton> #include <QVBoxLayout> #include <QHBoxLayout> #include <QGridLayout> int main(int argc, char *argv[]) { QApplication app(argc, argv); QWidget window; window.setWindowTitle("Qt Layout Example"); // 创建按钮实例 QPushButton* button1 = new QPushButton("Button 1"); QPushButton* button2 = new QPushButton("Button 2"); QPushButton* button3 = new QPushButton("Button 3"); QPushButton* button4 = new QPushButton("Button 4"); // 设置垂直布局 QVBoxLayout* vBox = new QVBoxLayout; // 添加按钮到垂直布局 vBox->addWidget(button1); vBox->addWidget(button2); // 设置水平布局 QHBoxLayout* hBox = new QHBoxLayout; // 将垂直布局嵌套到水平布局中 hBox->addLayout(vBox); // 继续向水平布局添加其他控件 hBox->addWidget(button3); hBox->addWidget(button4); // 设置网格布局作为顶层布局 QGridLayout* gridLayout = new QGridLayout; gridLayout->addLayout(hBox, 0, 0); // 设置窗口的内容区域并指定布局 window.setLayout(gridLayout); // 显示窗口 window.show(); return app.exec(); } ``` 此代码展示了如何组合使用多种布局类型(如 `QVBoxLayout`, `QHBoxLayout`, 和 `QGridLayout`),并通过嵌套实现复杂的 UI 设计[^1]。 #### 4. **注意事项** - 如果未显式设置任何布局,则当父窗口调整大小时,其中的控件不会随之改变位置或大小。 - 可以通过调用 `setLayout()` 方法将某个布局附加到容器部件上。 - 对于复杂的应用程序结构,建议合理规划层次化的布局体系,以便维护清晰性和可扩展性。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值