首页 > 编程笔记 > C++笔记 阅读:30

Qt布局管理器详解(新手必看)

QLayout 类是 Qt 布局管理器的基类,它是一个抽象基类,继承自 QObject 和 QLayoutItem 类,其中 QLayoutItem 类提供了一个供 QLayout 操作的抽象项目。

QLayout 和 QLayoutItem 都是在设计自己的布局管理器时才使用的,一般只需要使用QLayout的几个子类即可,它们分别是:
下面先来看一个例子。新建 Qt Widgets 应用,项目名称为 mylayout,基类选择 QWidget,类名设为 MyWidget。

完成后打开 mywidget.ui 文件,在设计模式中向界面拖入一个字体选择框 Font Combo Box 和一个文本编辑器 Text Edit。然后单击主界面并按下 Ctrl+L 快捷键,或者单击设计器上部边栏中的图标来对主界面进行垂直布局管理。也可以在主界面上右击,在弹出的快捷菜单中选择“布局→垂直布局”。

这样便设置了顶层布局管理器(因为是对整个窗口设置的布局管理器,所以叫作顶层布局管理器),可以看到两个部件已经填满了整个界面。这时运行程序,然后拉伸窗口,两个部件会随着窗口的大小变化而变化,如下图所示:


图 1 垂直布局管理器运行效果

这就是布局管理器的作用。

Qt基本布局管理器

基本布局管理器 QBoxLayout 类可以使子部件在水平方向或者垂直方向排成一列,它将所有的空间分成一行盒子,然后将每个部件放入对应盒子中。

QBoxLayout 类有两个子类,分别是 QHBoxLayout(水平布局管理器)和 QVBoxLayout(垂直布局管理器)。

下面在设计模式中查看布局管理器的属性。先单击主界面,查看属性编辑器,最后面的部分是其使用的布局管理器的属性,如下表所示。

表:布局管理器常用属性说明
属性 说明
layoutName 现在所使用的布局管理器的名称
layoutLeftMargin 设置布局管理器到界面左边界的距离
layoutTopMargin 设置布局管理器到界面上边界的距离
layoutRightMargin 设置布局管理器到界面右边界的距离
layoutBottomMargin 设置布局管理器到界面下边界的距离
layoutSpacing 布局管理器中各个子部件间的距离
layoutStretch 伸缩因子,设置部件的大小比例
layoutSizeConstraint 设置大小约束条件,例如QLayout::SetFixedSize表示窗口无法改变大小

下面打破已有的布局,使用代码实现水平布局。先在界面上右击,然后在弹出的快捷菜单中选择“布局→分拆布局”,或者单击设计器上方边栏中的“分拆布局”图标。下面在 mywidget.cpp 文件中添加头文件 #include <QHBoxLayout>,并在 MyWidget 类的构造函数中添加如下代码:
QHBoxLayout *layout = new QHBoxLayout;     // 新建水平布局管理器
layout->addWidget(ui->fontComboBox);       // 向布局管理器中添加部件
layout->addWidget(ui->textEdit);
layout->setSpacing(50);                    // 设置部件间的间隔
layout->setContentsMargins(0, 0, 50, 100); // 设置布局管理器到边界的距离
setLayout(layout);                         // 将这个布局设置为MyWidget类的布局
这里使用了 addWidget() 函数向布局管理器的末尾添加部件,还有一个 insertWidget() 函数可以实现向指定位置添加部件,它比前者更灵活。前面使用的垂直布局管理器也可以通过相似的代码来实现。

QGridLayout栅格布局管理器

栅格布局管理器 QGridLayout 类使部件在网格中进行布局,它将所有的空间分隔成一些行和列,行和列的交叉处就形成了单元格,然后将部件放入一个确定的单元格中。

先往界面上拖放一个 Push Button,然后在 mywidget.cpp 中添加头文件 #include <QGridLayout>,再注释掉前面添加的关于水平布局管理器的代码,最后添加如下代码:
QGridLayout *layout = new QGridLayout;
// 添加部件,从第0行0列开始,占据1行2列
layout->addWidget(ui->fontComboBox, 0, 0, 1, 2);
// 添加部件,从第0行2列开始,占据1行1列
layout->addWidget(ui->pushButton, 0, 2, 1, 1);
// 添加部件,从第1行0列开始,占据1行3列
layout->addWidget(ui->textEdit, 1, 0, 1, 3);
setLayout(layout);
这里主要是设置部件在栅格布局管理器中的位置,将 fontComboBox 部件设置为占据 1 行 2 列,而 pushButton 部件占据 1 行 1 列,这主要是为了将 fontComboBox 部件和 pushButton 部件的长度设置为 2:1。这样一来,textEdit 部件要想占满剩下的空间,跨度要为 3 列。

这里需要说明,当部件加入一个布局管理器中,然后这个布局管理器放到一个窗口部件上时,这个布局管理器以及它包含的所有部件都会自动重新定义自己的父对象(parent)为这个窗口部件,所以在创建布局管理器和其中的部件时并不用指定父部件。

QFormLayout窗体布局管理器

窗体布局管理器 QFormLayout 类用来管理表单的输入部件以及与它们相关的标签。

窗体布局管理器将它的子部件分为两列,左边是一些标签,右边是一些输入部件,比如行编辑器或者数字选择框等。其实,如果只是起到这样的布局作用,那么用 QGridLayout 就完全可以做到了,之所以添加 QFormLayout 类,是因为它有独特的功能。下面我们看一个例子。

先将前面在 MyWidget 类的构造函数中自己添加的代码全部删除,然后进入设计模式,这里使用另外一种方法来使用布局管理器。从部件列表窗口中找到 Form Layout,将其拖入界面,然后双击,或者右击并在弹出的快捷菜单中选择“添加窗体布局行”。

在弹出的“添加表单布局行”对话框中填入标签文字“姓名(&N):”,这样下面便自动填写了“标签名称”“字段类型”“字段名称”等,并且设置了伙伴关系。

这里使用了 QLineEdit 行编辑器,当然也可以选择其他部件。填写的标签文字中的“(&N)”必须使用英文半角的括号,表明快捷键是 Alt+N。设置伙伴关系表示当按下Alt+N时,光标会自动跳转到标签后面对应的行编辑器中。

单击“确定”按钮,则会在布局管理器中添加一个标签和一个行编辑器。按照这种方法,再添加 3 行:性别(&S),字段类型选择 QComoBox;年龄(&A),字段类型选择 QSpinBox;邮箱(&M),字段类型选择 QLineEdit。

完成后运行程序,可以按下快捷键 Alt+N,这样光标就可以定位到“姓名”标签后的行编辑器中。

上面添加表单行是在设计器中完成的,其实也可以在代码中使用 addRow() 函数来完成。窗体布局管理器为设计表单窗口提供了多方面的支持。窗体布局管理器也可以像普通管理器一样使用,但是,如果不是为了设计这样的表单,一般会使用栅格布局管理器。

Qt布局管理器的实际应用

前面讲到了3种布局管理器,真正使用时一般将它们综合起来应用。

现在继续设计前面的界面,按下 Ctrl 键的同时选中界面上的字体选择框 fontComboBox 和按钮 pushButton,然后按下 Ctrl+H 快捷键将它们放入一个水平布局管理器中(其实也可以从部件列表窗口中拖入一个 Horizontal Layout,然后将这两个部件放进去,效果是一样的)。

再从部件列表窗口中拖入一个垂直分隔符 Vertical Spacer,用来在部件间产生间隔,将它放在窗体布局管理器与水平布局管理器之间。

最后单击主界面并按下 Ctrl+L 快捷键,让整个界面处于一个垂直布局管理器中。这时可以在右上角的对象查看器中选择 MyWidget 对象,然后在属性编辑器的最后将 layoutStretch 设置为“4,1,1,10”。运行程序,可以看到分隔符是不显示的。

这里综合使用了窗体布局管理器、水平布局管理器和垂直布局管理器,其中垂直布局管理器是顶级布局管理器,因为它是主界面的布局管理器,其他两个布局管理器都包含在它里面。如果要使用代码将一个子布局管理器放入一个父布局管理器之中,可以使用父布局管理器的 addLayout() 函数。 

设置部件大小

在介绍如何设置部件大小之前,我们先来阐释两个概念:大小提示(sizeHint)和最小大小提示(minimumSizeHint)。

凡是继承自 QWidget 的类都有这两个属性,其中:
可以在程序中使用 sizeHint() 函数来获取 sizeHint 的值,使用 minimumSizeHint() 函数获取 minimumSizeHint 的值。需要说明的是,如果使用 setMinimumSize() 函数设置了部件的最小大小,那么最小大小提示将会被忽略。这两个属性在使用布局时起到了很重要的作用。

下面再来看一下大小策略(sizePolicy)属性,它也是 QWidget 类的属性。这个属性保存了部件的默认布局行为,在水平和垂直两个方向分别起作用,控制着部件在布局管理器中的大小变化行为。

QSizePolicy 类大小策略的取值如下表所示。

表:QSizePolicy类大小策略的取值
常量 描述
QSizePolicy::Fixed 只能使用sizeHint()提供的值,无法伸缩
QSizePolicy::Minimum sizeHint()提供的大小是最小的,部件可以被拉伸
QSizePolicy::Maximum sizeHint()提供的大小是最大的,部件可以被压缩
QSizePolicy::Preferred sizeHint()提供的大小是最佳的,部件可以被压缩或拉伸
QSizePolicy::Expanding sizeHint()提供的是合适的大小,部件可以被压缩,不过它更倾向于被拉伸来获得更多的空间
QSizePolicy::MinimumExpanding sizeHint()提供的大小是最小的,部件倾向于被拉伸来获取更多的空间
QSizePolicy::Ignored sizeHint()的值被忽略,部件将尽可能被拉伸来获取更多的空间

可扩展窗口

一个窗口可能有很多选项是扩充的,只有在必要的时候才显示出来,这时可以使用一个按钮来隐藏或者显示多余的内容,就是所谓的可扩展窗口。

可扩展窗口依赖于布局管理器的特性,那就是当子部件隐藏时,布局管理器自动缩小,当子部件重新显示时,布局管理器再次放大。下面我们看一个具体的例子。

依然在前面的程序中进行更改。首先在设计模式将 textEdit 的 maximumSize 的高度设置为 100,将 pushButton 的显示文本更改为“显示可扩展窗口”,并在属性编辑器中选中其 checkable 选项。然后转到它的 toggled(bool) 信号的槽,更改如下:
void MyWidget::on_pushButton_toggled(bool checked)
{
   ui->textEdit->setVisible(checked);
   if(checked) {
      setFixedHeight(270);
      ui->pushButton->setText(tr("隐藏可扩展窗口"));
   } else {
      setFixedHeight(170);
      ui->pushButton->setText(tr("显示可扩展窗口"));
   }
}
这里使用按钮的按下与否两种状态来设置文本编辑器是否显示,并且相应地更改按钮的文本。为了让文本编辑器在一开始是隐藏的,还要在 MyWidget 类的构造函数中添加如下代码:
ui->textEdit->hide();  
setFixedHeight(170);  
这时运行程序,可扩展窗口显示时如下图所示。


图 2 可扩展窗口显示时效果

关于可扩展窗口,也可以参考 Qt 自带的示例程序 Extension Example。

相关文章