Qt 布局之一:布局初探
前言
对于一个完善的软件,布局管理是必不可少的。 无论是想要界面中部件有一个很整齐的排列,还是想要界面能适应窗口的大小变化,都要进行布局管理。Qt 提供了 QLayout 类及其子类来作为布局管理器,它们可以实现常用的布局管理功能。
水平、垂直、网格、表单布局
为窗口提供一个好布局的最佳方式是使用内置的布局管理器:QHBoxLayout、QVBoxLayout、QGridLayout 和 QFormLayout。这些类都派生自 QLayout,QLayout 又派生自 QObject(非 QWidget),布局窗口自动地把子窗口按照它们被构造地顺序进行布局。要生成更复杂的布局,可以在其它布局里面嵌入另一个布局。
(1)QHBoxLayout:把子窗口从左到右排列在一个水平行上。
QWidget *window = new QWidget;
QPushButton *button1 = new QPushButton("One");
QPushButton *button2 = new QPushButton("Two");
QPushButton *button3 = new QPushButton("Three");
QPushButton *button4 = new QPushButton("Four");
QPushButton *button5 = new QPushButton("Five");
QHBoxLayout *layout = new QHBoxLayout;
layout->addWidget(button1);
layout->addWidget(button2);
layout->addWidget(button3);
layout->addWidget(button4);
layout->addWidget(button5);
window->setLayout(layout);
window->show();
效果如下所示:
(2)QVBoxLayout:把子窗口从上到下排列在一个垂直列上。
...
QVBoxLayout *layout = new QVBoxLayout;
layout->addWidget(button1);
layout->addWidget(button2);
layout->addWidget(button3);
layout->addWidget(button4);
layout->addWidget(button5);
...
使用与 QHBoxLayout 区别不大。效果如下所示:
(3)QGridLayout:把子窗口排列在一个二维的网格中,窗口可占据多个单元格。
...
QGridLayout *layout = new QGridLayout;
layout->addWidget(button1, 0, 0);
layout->addWidget(button2, 0, 1);
layout->addWidget(button3, 1, 0, 1, 2);
layout->addWidget(button4, 2, 0);
layout->addWidget(button5, 2, 1);
...
对于 QGridLayout 有点不同,因为需要指定子控件的行和列的位置。第三个 QPushButton 占据 2 列。通过指定 QGridLayout:: addWidget() 的第五个参数为 2 来实现。效果如下所示:
(4)QFormLayout:把子窗口按照 “标签-输入框” 的形式排列在两列。
QWidget *window = new QWidget;
QPushButton *button1 = new QPushButton("One");
QLineEdit *lineEdit1 = new QLineEdit();
QPushButton *button2 = new QPushButton("Two");
QLineEdit *lineEdit2 = new QLineEdit();
QPushButton *button3 = new QPushButton("Three");
QLineEdit *lineEdit3 = new QLineEdit();
QFormLayout *layout = new QFormLayout;
layout->addRow(button1, lineEdit1);
layout->addRow(button2, lineEdit2);
layout->addRow(button3, lineEdit3);
window->setLayout(layout);
window->show();
QFormLayout 将在一行上添加两个控件,通常是 QLabel 和 QLineEdit。在同一行中添加 QLabel 和 QLineEdit,将把 QLineEdit 设置为 QLabel 的伙伴。下面的代码将使用 QFormLayout 将三个 QPushButton 和相应 QLineEdit 排列起来。效果如下所示:
使用布局提示
当使用布局的时候,构建子控件的时候不需要指定 parent,布局将会自动的指定 parent(使用QWidget::setParent()),使它们成为安装了该布局的界面的子控件。
注意:布局中的控件是安装了该布局的界面的子控件,而非布局自身的,控件只能以控件作为parent,不能是布局。
也可以在布局中使用 addLayout() 来添加布局,内部的布局就会变成它的子布局。
为布局添加控件的过程分析
当添加一个控件到一个布局中,布局过程工作如下:
-
所有的控件将最初根据它们的 QWidget::sizePolicy() 和 QWidget::sizeHint() 而被分配到一定空间中。
-
如果任何一个控件有一个伸展因素设置,而且数值大于零,那么它们就会被根据它们的伸展因素的比例分配空间。
-
如果任何一个控件有一个伸展因素设置而且数值为零,那么只有当其它控件不再需要空间的时候才会得到更多的空间。在这当中,空间会首先被根据延展大小策略分配给控件。
-
任何控件被分配的空间的大小如果小于它们的最小大小(或者是在没有规定最小大小时的最小大小的提示),它们就会被按它们所需要的最小大小分配空间。(如果控件的伸展因素是它们的决定因素的情况下,它们不必有最小大小或者最小大小的提示。)
-
任何控件被分配的空间的大小如果大于它们的最大大小,它们就会被按它们所需要的最大大小分配空间。(如果控件的伸展因素是它们的决定因素的情况下,它们不必有最大大小。)
伸展因素
控件通常是在没有伸展因素设置的情况下被生成的。当它们被布置到一个布局中时,控件会被根据它们的 QWidget::sizePolicy() 或者它们的最小大小的提示中大的那一个分配给整个空间的一部分。伸展因素是用来根据控件互相的比例来改变它们所被分配的空间。
如果你使用一个 QHBoxLayout 来布置没有伸展参数设置的三个控件,我们就会得到像下面这样的布局:
如果我们给每个控件设置一个伸展因素,它们就会被按比例布置(但是不能小于最小大小的提示),举例来说:
自定义控件的布局
当你创建自己的控件类时,也应该传递它的布局属性。如果这个控件有一个 QLayout,这样的话就已经被处理了。如果这个控件不包括任何子控件,或者使用自定义布局,需要重新实现下面这些 QWidget 的成员函数:
- QWidget::sizeHint() 返回控件的优先选用的大小。
- QWidget::minimumSizeHint() 返回控件所能有的最小大小。
- QWidget::setSizePolicy() 指定控件所需要的空间。
只要大小提示、最小大小提示或者大小策略发生改变,都要调用 QWidget::updateGeometry()。这会引起布局的重新计算。对 updateGeometry() 的多重调用只会引起一次重新计算。
[扩展] Qt 布局学习资料
下面分析我在学习过程中看到的靠谱文章,学习Qt的布局,这几篇文章就足够入门了。
Qt 的官方文档:https://doc.qt.io/qt-5/layout.html.
参考:
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
2018-09-27 使用单向链表保存大量数据的基础程序框架