Qt窗口部件与布局之二:布局管理


第3章讲述了一些窗口部件,当时往界面上拖放部件时都是随意放置的,这对于学习部件的使用没有太大的影响,但是,对于一个完善的软件,布局管理却是必不可少的。 无论是想要界面中部件有一个很整齐的排列,还是想要界面能适应窗口的大小变化,都 要进行布局管理。Qt中主要提供了 QLayout 类及其子类来作为布局管理器,它们可以实现常用的布局管理功能,QLayout及其子类的关系如下图所示。



一、布局管理系统

Qt的布局管理系统提供了简单而强大的机制来自动排列一个窗口中的部件,确保它们有效地使用空间。Qt包含了一组布局管理类来描述怎样在应用程序的用户界面中对部件进行布局,比如QLayout的几个子类,这里将它们称作布局管理器。所有 QWidget 类的子类的实例(对象)都可以使用布局管理器来管理位于其中的子部件, QWidget::setLayOut()函数可以在一个部件上应用布局管理器。一旦一个部件上设置了布局管理器,那么它会完成以下几种任务:

  • 定位子部件;
  • 感知窗口默认大小;
  • 感知窗口最小大小;
  • 改变大小处理;
  • 当内容改变时自动更新:
    • 字体大小,文本或子部件的其他内容随之改变;
    • 隐藏或显示子部件;
    • 移除一个子部件。

1.1 布局管理器

QLayout类是布局管理器的基类,是一个抽象基类,继承自 QObject 和 QLayoutItem 类,而 QLayoutltem 类提供了 一个供 QLayout 操作的抽象项目。QLayout 和 QLayoutItem 都是在设计自己的布局管理器时才使用的,一般只需要使用 QLayout 的几个子类就可以了,分别是 QBoxLayout(基本布局管理器)、QGridLayout(栅格布局管理器)、QFormLayout(表单布局管理器)和QStackedLayout(栈布局管理器)。

下面先来看一个例子。新建 QtGui 应用,项目名称为 myLayout,类名 MyWidget,基类选择 QWidget。然后打开 mywidget. ui 文件,在设计模式中向界面拖人一个字体选择框 Font Combo Box 和文本编辑器 Text Edit 部件。然后单击主界面并按下 Ctrl + L 快捷键,或者单击设计器上边栏中的“垂直布局”图标来对主界面进行垂直布局管理。也可以在主界面上右击,在弹出的菜单中选择“布局→垂直布局”,这样便设置了顶层布局管理器,可以看到两个部件已经填满了整个界面。这时运行程序,然后拉伸窗口,两个部件会随着窗口的大小变化而变化,如下图所示。这就是布局管理器在起作用。


1. 基本布局管理器(QBoxLayout)

基本布局管理器 QBoxLayout 类可以使子部件在水平方向或者垂直方向排成一列,将所有的空间分成一行盒子,然后将每个部件放入一个盒子中。它有两个子类 QHBoxLayont 水平布局管理器和 QVBoxLayout 垂直布局管理器。单击主界面,查看它的属性栏,最后面的部分是其使用的布局管理器的属性,如下图所示。

下面打破已有布局,使用代码实现水平布局。在界面上右击,然后在右键菜单中选择“打破布局”,或者单击设计器上边栏中的打破布局图标。在 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() 函数可以实现向指定位置添加部件,它比前者更灵活。


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

栅格布局管理器QGridLaycnit类使得部件在网格中布局,它将所有的空间分隔成一些行和列,行和列的交叉处就形成了单元格,然后将部件放人一个确定的单元格中。下面编写代码来使用栅格布局管理器。先往界面上拖放一个 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);

这里主要是设置了部件在栅格布局管理器中的位罝,将 fontComBox 部件设置为占据1行2列,而 pushBimon 部件占据1行1列,这主要是为了将 fontComBox 部件和 pushBuuon 部件的长度设置为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快捷键将它们放人一个水平布局管理器中 。然后再从部件栏中拖入一个 Vertical Spacer 垂直分隔符,它们是用来在部件间产生间隔的,将它放在表单布局管理器与水平布局管理器之间。然后单击主界面,然后按下Ctrl + L快捷键,让整个界面处于一个垂直布局管理器中。这时可以在右上角的对象列表中选择分隔符Spacer,然后在属性栏中设置它的高度为100。这时运行程序,效果如下图所示。

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


1.2 可扩展窗口

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

依然在前面的程序中进行更改。首先将界面上 pushBimon 的显示文本更改为“显示可扩展窗口”,然后在其属性栏中选中 checkable 选项。然后转到它的 toggled(bool) 信号的槽,更改如下:

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

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

ui->textEdit->hide();      // 让文本编辑器隐藏,也可以使用setVisible(false)函数

运行程序。可扩展窗口隐藏时效果如下图1所示,可扩展窗口显示时如下图2所示。也可以参考Qt自带的示例程序 Extension Dialog,它在 Dialogs 分类中。



1.3 分裂器

分裂器 QSplitter 类提供了一个分裂器部件,和 QBoxLayout 很相似,可以完成布局管理器的功能,但是包含在它里面的部件,默认是可以随着分裂器的大小变化而进行相应大小变化的。比如一个按钮放在布局管理器中,它的垂直方向默认是不会被拉伸的,但是放到分裂器中就可以被拉伸。还有一个不同就是,布局管理器是继承自 QObject 类的,而分裂器却是继承自 QFrame 类,QFrame 类又是继承自 QWidget 类,也就是说,分裂器拥有 QWidget 类的特性,它是可见的,而且可以像 QFrame —样设置边框。下面看一个例子。
新建Qt Gui应用,项目名称为mySplitter,类名My Widget,基类选择QWidget。 建好项目后打开 mywidget. ui 文 件,然后往上面拖人4个 Push Button, 同时选中这4个按钮然后右击,选择 “布局—使用分裂器水平布局”菜单项, 将这4个按钮放到一个分裂器中。将分裂器拉大点,并在属性栏中设置其 frameShape 为 Box,frameShadow 为 Raised,line Width为5。此时运行程序,效果如下图所示。



二、设置伙伴

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

新建Qt Gui应用,项目名称为myBuddy, 类名MyWidget,基类选择 QWidget。建好项目后打开 mywidget. ui 文件,然后往界面上拖放4个标签 Label,再在标签后面依次放上 PushButton、CheckBox、LineEdit和 SpinBox。然后将 PushButton 前面的标签的文本改为“&Button:”;CheckBox 前面的标签文本改为“C&heckBox:”; LineEdit 前面的标签的文本改为“行编辑器(&L):”;SpinBox前面的标签文本改为“数字选择框(&N):”。单击下设计器顶部栏中的“编辑伙伴图标“进人伙伴设计模式,分别将各个标签与它们后面的部件连起来,如下图所示。然后按下F3回到正常编辑模式,可以看到所有的&符号都没有了,只是在字母下面多了一 个横杠,表示这个标签的加速键就是Alt加这个字母。

现在可以运行程序,使用加速键测试效果。如果要在代码中设置伙伴关系,只需要使用 QLabel 的 setBuddy() 函数就可以了。对应于本小节内容可以在帮助索引中查看 Qt Designer's Buddy Editing Mode 关键字。


三、设置Tab顺序

对于一个应用程序,我们有时总希望使用Tab键来将焦点从一个部件移动到下一个部件。在设计模式,设计器提供了Tab键的设置功能。上面程序的设计模式中,单击上边栏的“编辑Tab顺序(Edit Tab Order)”按钮进人编辑Tab键顺序模式,这时已经显示出了各个部件的Tab键顺序,只需要单击这些数字即可以更改。需要说明,当程序启动时,焦点会在Tab键顺序为1的部件上。这里进行的设置等价于在MyWidget类的构造函数中使用如下代码:

    setTabOrder(ui->lineEdit, ui->spinBox);    //lineEdit,在spinBox前面
    setTabOrder(ui->spinBox, ui->pushButton);    //spinBox,在pushButton前面
    setTabOrder(ui->pushButton, ui->checkBox);    //pushButton,在checkBox前面

关于在设计器中设置Tab键顺序,读者也可以在帮助索引中查看 Qt DeSigner's Tab Order Editing Mode 关键字。



免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM