zl程序教程

您现在的位置是:首页 >  工具

当前栏目

QT creator使用(四):布局管理系统

Qt管理系统 布局 Creator 使用
2023-09-14 09:15:10 时间

目录

4.0 本章介绍

4.1 布局管理系统

4.1.1 布局管理器

4.1.2 设置部件大小 

4.1.3 可扩展窗口 

4.1.4 分裂器(QSplitter) 

4.2 设置伙伴(buddy)

4.3 设置Tab键顺序

4.4 Qt Creator中的定位器

4.5 小结 


4.0 本章介绍

        第3章讲述了一些窗口部件,当时往界面上拖放部件时都是随意放置的,这对于学习部件的使用没有太大的影响,但是,对于一个完善的软件,布局管理却是必不可少的。无论是想要界面中的部件有一个整齐的排列,还是想要界面能适应窗口的大小变化,都要进行布局管理。

        Qt主要提供了QLayout类及其子类来作为布局管理器,它们可以实现常用的布局管理功能,QLayout及其子类的关系如下图所示。本章还会涉及Buddy 、Tab键顺序设置等内容。

4.1 布局管理系统

        Qt的布局管理系统提供了强大的机制来自动排列窗口中的所有部件,确保它们有效地使用空间。

        Qt包含了一组布局管理类,从而在应用程序的用户界面中对部件进行布局,比如 QLayout的几个子类,这里将它们称作布局管理器。所有QWidget的子类的实例(对象)都可以使用布局管理器管理位于它们之中的子部件,QWidget : ; setLayout()函数可以在一个部件上应用布局管理器。一旦一个部件上设置了布局管理器,那么它会完成以下几种任务:

1.定位子部件;
2.感知窗口默认大小;

3.感知窗口最小大小;
4.窗口大小变化时进行处理;

5.当内容改变时自动更新;
        字体大小、文本或子部件的其他内容随之改变;

        隐藏或显示子部件;
        移除一个子部件。

        下面将在具体例子中讲解布局管理器的这些功能,本节主要讲述QLayout类的几个子类,最后会涉及QSplitter类,它也可以作为一种布局管理器。本节内容可以在帮助索引中通过Layout Management关键字查看。

4.1.1 布局管理器

        QLayout类是布局管理器的基类,是一个抽象基类,继承自QObject和 QLayoutItem类,QLayoutItem类提供了一个供QLayout操作的抽象项目。QLayout 和QLayoutItem都是在设计自己的布局管理器时才使用的,一般只需要使用QLayout的几个子类即可,它们分别是QBoxLayout(基本布局管理器)、QGridLayout(栅格布局管理器)、QFormLayout(窗体布局管理器)和QStackedLayout(栈布局管理器)。这里的QStackedLayout与第3章讲述的栈部件QStacked Widget用法相同,不再赘述。

        下面先来看一个例子。打开Qt Creator,新建Qt Widgets应用,项目名称为mylayout,基类选择QWidget,类名设为MyWidget。完成后打开 mywidget. ui文件,在设计模式中向界面上拖入一个字体选择框Font Combo Box和一个文本编辑器Text Edit部件。

        然后单击主界面并按下Ctrl+L快捷键,或者单击设计器上部边栏中的目图标来对主界面进行垂直布局管理。也可以在主界面上右击如下图:

在弹出的级联菜单中选择“布局→垂直布局”。这样便设置了顶层布局管理器(因为是对整个窗口设置的布局管理器,所以叫顶层布局管理器),可以看到两个部件已经填满了整个界面。这时运行程序,然后拉伸窗口,两个部件会随着窗口的大小变化而变化,如下图所示。这就是布局管理器的作用。

1.基本布局管理器

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

        它有两个子类QHBoxLayout水平布局管理器和QVBoxLayout垂直布局管理器,编程中经常用到。再回到设计模式中看看布局管理器的属性。先单击主界面,查看它的属性栏,最后面的部分是其使用的布局管理器的属性,如下表所列。

表 布局管理器常用属性说明
属性说明
layoutName现在所使用的布局管理器的名称
layoutLeftMargin设置布局管理器到界面左边界的距离
layoutTopMargin设置布局管理器到界面上边界的距离
layoutRightMargin设置布局管理器到界面右边界的距离
layoutBottomMargin设置布局管理器到界面下边界的距离
layoutSpacing布局管理器各个子部件的距离
layoutStretch伸缩因子
layoutSizeConstraint设置大小的约束条件

         下面打破已有的布局,使用代码实现水平布局。在界面上右击,然后在弹出的级联菜单中选择“打破布局”,或者单击设计器上方边栏中的打破布局图标。在 mywidget.cpp文件中添加头文件#include <QHBoxLayout>,并在 MyWidget类的构造函数中添加如下代码:

MyWidget::MyWidget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::MyWidget)
{
    ui->setupUi(this);
    //新建水平布局管理器
    QHBoxLayout * layout = new QHBoxLayout;
    //向布局管理器中添加部件
    layout -> addWidget(ui -> fontComboBox);
    layout -> addWidget(ui -> textEdit);
    //设置部件间的间隔
    layout -> setSpacing(50);
    //设置布局管理器到边界的距离 左上右下
    layout -> setContentsMargins(0,0,50,100);
    //将这个布局设置为MyWidget类的布局
    setLayout(layout);
}

         这里使用了addWidget()函数向布局管理器的末尾添加部件,还有一个insertWidget()函数可以实现向指定位置添加部件,它比前者更灵活。前面使用的垂直布局管理器也可以通过相似的代码来实现。

2.栅格布局管理器(QGridLayout)

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

        先往界面上拖放一个Push Button,然后在mywidget. cpp中添加头文件#include<QGridLayout>,再注释掉前面添加的关于水平布局管理器的代码,添加的如下代码:

MyWidget::MyWidget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::MyWidget)
{
    ui->setupUi(this);
//    //新建水平布局管理器
//    QHBoxLayout * layout = new QHBoxLayout;
//    //向布局管理器中添加部件
//    layout -> addWidget(ui -> fontComboBox);
//    layout -> addWidget(ui -> textEdit);
//    //设置部件间的间隔
//    layout -> setSpacing(50);
//    //设置布局管理器到边界的距离 左上右下
//    layout -> setContentsMargins(0,0,50,100);
//    //将这个布局设置为MyWidget类的布局
//    setLayout(layout);
    QGridLayout * layout = new QGridLayout;
    //添加部件,从第0行0列开始,占据一行二列
    layout -> addWidget(ui->fontComboBox,0,0,1,2);
    //添加部件,从第0行2列开始,占据一行一列
    layout -> addWidget(ui->pushButton,0,2,1,1);
    //添加部件,从第1行0列开始,占据一行三列
    layout -> setSpacing(50);
    layout -> addWidget(ui->textEdit,1,0,1,3);
    setLayout(layout);
}

        这里主要是设置部件在栅格布局管理器中的位置,将fontComboBox部件设置为占据1行2列,而pushButton部件占据1行1列,这主要是为了将fontComboBox部件和 pushButton部件的长度设置为2:1。这样一来, textEdit部件要想占满剩下的空间,就要使它的跨度为3列。        

        这里需要说明,当部件加入到一个布局管理器中,然后将这个布局管理器再放到一个窗口部件上时,这个布局管理器以及它包含的所有部件都会自动重新定义自己的父对象( parent)为这个窗口部件,所以在创建布局管理器和其中的部件时并不用指定父部件。此外,也可以直接在设计模式时使用前面讲过的方法来使用栅格布局管理器。

3.窗体布局管理器(QFormLayout) 

        窗体布局管理器QFormLayout类用来管理表单的输入部件以及与它们相关的标签。窗体布局管理器将它的子部件分为两列,左边是一些标签,右边是一些输入部件,比如行编辑器或者数字选择框等。

        其实,如果只是起到这样的布局作用,那么用QGridLayout就完全可以做到了,之所以添加QFormLayout类,是因为它有独特的功能。下面看一个例子。

        先将前面在MyWidget类的构造函数中自己添加的代码全部注释掉,然后进入设计模式,这里使用另外一种方法来使用布局管理器。从部件栏中找到Form Layout,将其拖入到界面上,然后双击或者在它上面右击并在弹出级联菜单中选择“添加窗体布局行”。在弹出的“添加表单布局行”对话框中填入标签文字“姓名(&N):”,这样下面便自动填写了“标签名称”,“字段类型”和“字段名称”等,并且设置了伙伴关系。这里使用了QLineEdit行编辑器,当然也可以选择其他部件。填写的标签文字中的“(&N)”必须是英语半角的括号,表明它的快捷键是Alt+N。设置伙伴关系表示按下Alt+N时,光标自动跳转到标签后面对应的行编辑器中。单击“确定”键,则会在布局管理器中添加一个标签和一个行编辑器。按照这种方法,再添加3行:性别(&S),使用QComoBox;年龄(&A),使用QSpinBox;邮箱(&M),使用QLineEdit。完成后运行程序,可以按下快捷键Alt+N,这样光标就可以定位到“姓名”标签后的行编辑器中。

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

4.综合使用布局管理器

        前面讲到了3种布局管理器,真正使用时一般是将它们综合起来应用。现在将前面的界面再进行设计:按下Ctrl键的同时选中界面上的字体选择框fontComboBox和按钮pushButton,然后按下Ctrl+H快捷键将它们放入一个水平布局管理器中(其实也可以从部件栏中拖入一个 Horizontal Layout,然后再将这两个部件放进去,效果是一样的)。

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

        最后单击主界面并按下Ctrl+L快捷键,让整个界面处于一个垂直布局管理器中。

        这时可以在右上角的对象列表中选择分隔符Spacer,然后在属性栏中设置它的高度为100,如下图所示。这时运行程序可以看到,分隔符是不显示的。

         这里综合使用了窗体布局管理器,水平布局管理器和垂直布局管理器,其中,垂直布局管理器是顶级布局管理器,因为它是主界面的布局,其他两个布局管理器都包含在它里面。        

        如果要使用代码来实现将一个子布局管理器放入一个父布局管理器之中,则可以使用父布局管理器的addLayout()函数。

4.1.2 设置部件大小 

        讲解之前要先了解两个概念:大小提示(sizeHint)和最小大小提示(minimumSizeHint)。凡是继承自QWidget的类都有这两个属性,其中,sizeHint属性保存了部件的建议大小,对于不同的部件,默认拥有不同的sizeHint;

        而 minimumSizeHint保存了一个建议的最小大小提示。可以在程序中使用sizeHint()函数来获取sizeHint的值,使用minimumSizeHint()函数获取 minimumSizeHint的值。需要说明的是,如果使用setMinimumSize()函数设置了部件的最小大小,那么最小大小提示将会被忽略。这两个属性在使用布局时起到了很重要的作用。

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

QSizePolicy类大小策略的取值
常量描述
QSizePolicy::Fixed只能使用sizeHint()的值,无法伸缩
QSizePolicy::MinimumsizeHint()提供的大小是最小的,部件可以被拉伸
QSizePolicy::MaximumsizeHint()提供的大小是最大的,部件可以被压缩
QSizePolicy::PreferredsizeHint()提供的大小是最佳大小的,部件可以被压缩被拉伸
QSizePolicy::ExpandingsizeHint()提供的大小是最合适的大小,部件可以被压缩,不过更倾向于被拉伸
QSizePolicy::MinimumExpandingsizeHint()提供的大小是最小的,更倾向于被拉伸
QSizePolicy::IgnoredsizeHint()的值被忽略,更倾向于被拉伸

        可以看到,大小策略与sizeHint()的值息息相关。对于布局管理器来说,大小策略对于布局效果也起到了很重要的作用。

        下面来看一下它们的效果。还在前面的程序中进行操作。单击界面上那个分隔符Spacer,当时将其属性中的sizeHint的高度设置为100,可是实际界面上的分隔符高度并没有到达100。这时可以看到它的sizeType属性设置为Expanding,如果将它更改为Fixed,这样界面上的分隔符马上增高了,现在它的实际高度才是sizeHint的高度值。

         下面再来了解一下伸缩因子(stretch factor)的概念。前面讲垂直布局管理器时曾提到过它,其实它是用来设置部件间比例的。

        界面上的字体选择框和一个按钮处于一个水平布局管理器中,现在想让它们的宽度比例为2:1 ,那么就可以单击对象栏中的horizontalLayout水平布局管理器对象,然后在它的属性栏中将layoutStretch属性设置为“2,1”,这样这个水平布局管理器中的两个部件的宽度就是2:1的比例了。如果要在代码中进行设置,则可以在使用布局管理器的addWidget()函数添加部件的同时,在第二个参数中指定伸缩因子。

         现在再来看一下窗体布局管理器中的一些属性。单击对象栏中的formLayout,其属性栏中几个属性的说明如下表所列。

说明说明
指定部件的大小变化方式AlINonFixedFieldsGrow所有的部件都被拉伸,这是默认值
FieldsStayAtSizeHint所有的部件都使用sizeHint()提供的大小
ExpandingFieldsGrow大小策略为Expanding的部件会被拉伸
设置是否换行:如果需要换行,则将输入部件放到相应的标签下面DontWrapRows不换行,这是默认值
WrapLongRows将较长的行进行换行
WrapAllRows将所有行都换行,这样所有的输入部件都会放置在相应的标签下面
设置标签的对其方式,分为水平方向和垂直方向水平方向AlignLeft左对齐
AlignRight右对齐
AlignHCenter水平居中对齐
AlignJustify两端对齐
垂直方向AlignTop向上对齐
AlignBottom向下对齐
AlignVCenter垂直居中对齐
设置部件在表单中的对齐方式同layoutLabelAlignment属性同layoutLabelAlignment属性

        对于layoutFieldGrowthPolicy属性,这里选择ExpandingFieldsGrow选项,这样性别和年龄两个输入框就没有那么宽了,更符合美观要求。然后将界面中的“邮箱”标签更改为“邮箱地址”,在 layoutLabelAlignment属性中选择AlignRight。

         下面来看一下QWidget类及其子类部件的设置大小的相关属性。单击主界面,查看一下其属性栏,其最开始便是几个与大小有关的属性。这里的高度与宽度属性是现在界面的大小;下面的sizePolicy属性可以设置大小策略以及伸缩因子; minimumSize属性用来设置最小值,这里改为200×150;maximumSize属性设置最大值,将其设置为500×350 ;sizeIncrement属性和 baseSize属性是设置窗口改变大小的,一般不用设置。

         最后看一下布局管理器的 layoutSizeConstraint属性,它是用来约束窗口大小的,也就是说,这个只对顶级布局管理器有用,因为它只对窗口有用,对其他子部件没有效果。它的几个值及其含义如表所列。这个属性的默认值是SetDefaultConstraint。可以将界面的顶级布局管理器设置为SetFixedSize,这样运行程序可以看到,窗口就无法再变化大小了。

QLayout类的大小约束属性的取值
常量描述
QLayout::setDefaultConstraint主窗口大小设置为minimumSize()值,除非该部件已经有一个最小大小
QLayout::setFixedSize主窗口大小设置为sizeHint()值,无法改变大小
QLayout::setMinimumSize主窗口最小大小设置为minimumSize()的值,无法缩小
QLayout::setMaximumSize主窗口最大大小设置为maximumSize()的值,无法放大
QLayout::setMinAndMaxSize主窗口最小大小设置为minimumSize()的值,最大大小设置为maximumSize()的值
QLayout::setMinimunSizeNoConstraint部件不被约束

4.1.3 可扩展窗口 

        一个窗口可能有很多选项是扩充的,只有在必要的时候才显示出来,这时就可以使用一个按钮来隐藏或者显示多余的内容,就是所谓的可扩展窗口。要实现可扩展窗口,就要得力于布局管理器的特性,那就是当子部件隐藏时,布局管理器自动缩小,当子部件重新显示时,布局管理器再次放大。下面看一个具体的例子。

        依然在前面的程序中进行更改。首先将界面上的 pushButton显示文本更改为“显示可扩展窗口”,并在其属性栏选中 checkable选项。

         然后转到它的 toggled(bool)信号的槽,更改如下:

void MyWidget::on_pushButton_2_toggled(bool checked)
{
    //设置文本编辑器的显示和隐藏
    ui -> textEdit -> setVisible(checked);
    if(checked)
    {
        ui -> pushButton_2 -> setText("隐藏可拓展窗口");
    }
    else
    {
        ui -> pushButton_2 -> setText("显示可拓展窗口");
    }
}

        这里使用按钮的按下与否两种状态来设置文本编辑器是否显示,并且相应地更改按钮的文本。为了让文本编辑器在一开始是隐藏的,还要在 MyWidget类的构造函数中添加一行代码:

ui->textEdit->hide();

        这时运行程序。可扩展窗口隐藏时效果如下图所示,可扩展窗口显示时如下图所示。也可以参考Qt自带的示例程序Extension Example。

4.1.4 分裂器(QSplitter) 

        分裂器QSplitter类提供了一个分裂器部件。和QBoxLayout类似,可以完成布局管理器的功能,但是包含在它里面的部件,默认是可以随着分裂器的大小变化而变化的。比如一个按钮放在布局管理器中,它的垂直方向默认是不会被拉伸的,但是放到分裂器中就可以被拉伸。还有一点不同就是,布局管理器继承自QObject类,而分裂器却是继承自QFrame类,QFrame类又继承自QWidget类,也就是说,分裂器拥有QWid-get类的特性,它是可见的,而且可以像QFrame一样设置边框。

       新建Qt Widgets应用,项目名称为mysplitter,基类选择QWidget,类名设为MyWidget。建好项目后打开mywidget.ui 文件,然后往界面上拖入4个Push Button,同时选中这4个按钮,右击并在弹出的级联菜单中选择“布局→使用分裂器水平布局”,将这4个按钮放到一个分裂器中。将分裂器拉大点,并在属性栏中设置其frameShape为 Box,frameShadow为Raised,lineWidth为5。此时运行程序,效果如下图所示。

4.2 设置伙伴(buddy)

        前面讲述窗体布局管理器时提到了设置一个标签和一个部件的伙伴关系。其实,伙伴(buddy)是在QLabel类中提出的一个概念。因为一个标签经常用作一个交互式部件的说明,就像在讲窗体布局管理器时看到的那样,一个 lineEdit部件前面有一个标签说明这个lineEdit的作用。为了方便定位,QLabel提供了一个有用的机制,那就是提供了助记符来定位键盘焦点到对应的部件上,而这个部件就叫这个QLabel 的伙伴。其中,助记符就是我们所说的加速键。使用英文标签时,在字符串的一个字母前面添加“8.”符号,就可以指定这个标签的加速键是Alt加上这个字母;对于中文,需要在小括号中指定加速键字母,这个前面已经见过多次了。Qt设计器中也提供了伙伴设计模式,下面看一个例子。

        新建Qt Widgets应用,项目名称为mybuddy ,基类选择QWidget ,类名设为MyWidget。

        完成后打开mywidget.ui 文件,往界面上拖放4个标签Label,再在标签后面依次放上PushButton、 CheckBox、LineEdit和SpinBox。然后将PushButton前面的标签文本改为“&Button:”,CheckBox前面的标签文本改为“C&heckBox:”,LineEdit前面的标签文本改为“行编辑器(&L):”,SpinBox前面的标签文本改为“数字选择框(&N):”。

        单击设计器上方边栏中的伙伴图标进入伙伴设计模式。

        分别将各个标签与它们后面的部件关联起来,如下图所示。然后按下F3键回到正常编辑模式,可以看到所有的&符号都不显示了。

          现在运行程序,按下Alt+B组合键,则可以看到按钮被按下了,而字母下面多了一个横杠,表示这个标签的加速键就是Alt加这个字母。如果要在代码中设置伙伴关系,则只需要使用QLabel的 setBuddy()函数就可以了。本小节内容可以在帮助索引中通过Qt Designer's Buddy Editing Mode关键字查看。

4.3 设置Tab键顺序

        对于一个应用程序,有时总希望使用Tab键将焦点从一个部件移动到下一个部件。在设计模式中,设计器提供了Tab键的设置功能。

        在前面程序的设计模式中,按下上方边栏的编辑Tab顺序国按钮进入编辑Tab键顺序模式,这时已经显示出了各个部件的Tab键顺序,只需要单击这些数字就可以更改顺序。设置好之后,可以运行一下程序测试效果。需要说明,当程序启动时,焦点会在 Tab键顺序为1的部件上。

         关于在设计器中设置Tab键顺序,也可以在帮助索引中通过Qt Designer's TabOrder Editing Mode关键字查看。

4.4 Qt Creator中的定位器

        第1章中介绍Qt Creator时已经提到了定位器,它位于主界面的左下方。使用定位器可以很方便地打开指定文件、定位到文档的指定行、打开一个特定的帮助文档、进行项目中函数的查找等。更多的功能可以在帮助索引中通过Searching With the Locator关键字查看。
        定位器中提供了多个过滤器来实现不同的功能,按下Ctrl+K快捷键就会在定位器中显示各个过滤器的前缀及其功能,如下图所示。使用方法是“前缀符号+空格+要定位的内容”。

        下面举两个简单的例子。在Qt Creator中,按下Ctrl+K快捷键打开定位器,这时
输人“1 8"(英文字母1和一个空格,然后是数字8),按下Enter回车键,就会跳转到编辑
模式的当前打开文档的第8行。

        再次按下Ctrl + K快捷键,输入“? qla" ,这时已经查
找到了QLabel,按下回车键,就会跳转到帮助模式中,并打开QLabel类的帮助文档。

4.5 小结 

        这一章讲述了一些关于界面布局的知识,其实只是提到了最基本的应用,更多的布局知识还要参考帮助文档。以后的章节还是以讲解知识点为主,所以对界面的布局操作不会涉及太多。但是这并不表明布局不重要,对于一个软件,良好的布局是必须的。