QT中主要提供了QLayout类及其子类作为布局管理器,如下图所示主要的布局类及其继承关系
所有的QWidget类的子类的实例都可以使用布局管理器来管理位于它们之中的子部件,QWidget::setLayout()函数可以在一个部件上应用布局管理器。
一旦一个部件上设置了布局管理器,那么它会完成以下几种任务:
QLayout类是布局管理器的基类,它是一个抽象基类。该类继承自QObject和QLayoutItem类,而QLayoutItem类提供了一个供QLayout操作的抽象项目。 QLayout和QLayoutItem都是在设计自己的布局管理器时才使用,有一些常用的布局管理器:
基本布局管理器QBoxLayout类可以使子部件在水平方向或者垂直方向排成一列,它有两个子类QHBoxLayout水平布局管理器和QVBoxLayout垂直布局管理器。
QHBoxLayout *layout = new QHBoxLayout; // 新建水平布局管理器
layout->addWidget(ui->textEdit); // 向布局管理器中添加部件
layout->setSpacing(50); // 设置部件间的间隔,所有的部件之间都是这个间距
layout->setContentsMargins(0, 0, 50, 100); // 设置布局管理器到边界的距离,
// 四个参数顺序是左,上,右,下
layout->addSpacing(50); // 与setSpacing不一样,仅仅是前后两个的间距
layout->addStretch(); // 增加一个可伸缩空间
setLayout(layout); // 在父窗口添加布局管理器
栅格布局管理器,它将所有的空间分隔成一些行和列,行和列的交叉处就形成了单元格,然后将部件放入一个确定的单元格中,示例代码如下:
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);
表单布局管理器QFormLayout类用来管理表单的输入部件和与它们相关的标签,它将子部件分为两列,左边是一些标签,右边是一些输入部件,比如行编辑器或者数字选择框等,左右两边有对应关系。
在设计模式,从部件栏中找到Form Layout,将其拖入到界面上,然后双击它,或者在它上面点击鼠标右键,选择“添加窗体布局行”菜单。
然后在弹出的“添加表单布局行”对话框中填入标签文字,这样下面便自动填写了“标签名称”、“字段类型”和“字段名称”等,并且设置了伙伴关系。
伙伴关系表示当按下“Alt+设置标签的快捷字母,即(&符号后面的字母)“”时,光标会自动跳转到标签后面对应的行编辑器中。
QStackedLayout栈式布局管理器管理的所有组件在垂直于屏幕的方向上,每次只有一个界面组件会显示在屏幕上,只要最顶层的界面组件会被显示。 QStackedLayout栈式布局管理器的特点如下:
void LayoutWidget::StackedLayout()
{
//创建组件并设置显示标签
QPushButton *button1 = new QPushButton();
QPushButton *button2 = new QPushButton();
QPushButton *button3 = new QPushButton();
QPushButton *button4 = new QPushButton();
button1->setText("1st");
button2->setText("2rd");
button3->setText("3th");
button4->setText("4th");
//创建栈式布局管理器并添加组件
sLayout = new QStackedLayout();
sLayout->addWidget(button1);
sLayout->addWidget(button2);
sLayout->addWidget(button3);
sLayout->addWidget(button4);
//设置当前栈顶显示的组件
connect(button1, &QPushButton::clicked, this, &LayoutWidget::btn1_clicked);
connect(button2, &QPushButton::clicked, this, &LayoutWidget::btn2_clicked);
connect(button3, &QPushButton::clicked, this, &LayoutWidget::btn3_clicked);
connect(button4, &QPushButton::clicked, this, &LayoutWidget::btn4_clicked);
sLayout->setCurrentIndex(0);
//设置栈式布局管理器到窗口
setLayout(sLayout);
}
void LayoutWidget::btn1_clicked()
{
sLayout->setCurrentIndex(1);
}
void LayoutWidget::btn2_clicked()
{
sLayout->setCurrentIndex(2);
}
void LayoutWidget::btn3_clicked()
{
sLayout->setCurrentIndex(3);
}
void LayoutWidget::btn4_clicked()
{
sLayout->setCurrentIndex(0);
}
它和QBoxLayout很相似,可以完成布局管理器的功能,但是包含在它里面的部件,默认是可以随着分裂器的大小变化而进行相应大小变化的。QSplitter有以下特点
QSplitter *splitterMain = new QSplitter(Qt::Horizontal,0);
QTextEdit *textLeft = new QTextEdit(QObject::tr("Left Widget"),splitterMain);
textLeft->setAlignment(Qt::AlignCenter);
//右部分分割窗口
QSplitter *splitterRight = new QSplitter(Qt::Vertical,splitterMain);
splitterRight->setOpaqueResize(true);
//表示分割窗口拖拽时边界是否实时显示
QTextEdit *textUp = new QTextEdit(QObject::tr("Top Widget"),splitterRight);
textUp->setAlignment(Qt::AlignCenter);
QTextEdit *textBottom = new QTextEdit(QObject::tr("Bottom Widget"),splitterRight);
textBottom->setAlignment(Qt::AlignCenter);
splitterMain->setStretchFactor(1,1);
//SetStretchFactor()方法用于设定可伸缩控件,它的第一个参数指定设置的控件序号,
//控件序号按插入的先后次序进行编号;第二个参数为大于0的值表示此控件为可伸缩控件。
splitterMain->setWindowTitle(QObject::tr("Splitter"));
凡是继承自QWidget的类都有这两个属性:大小提示(sizeHint)和最小大小提示(minimumSizeHint)。
它是用来设置部件间的比例的。
例如,界面上的字体选择框和一个按钮处于一个水平布局管理器中,现在想让它们的宽度比例为2:1,
那么就可以点击对象栏中的horizontalLayout水平布局管理器对象,然后在它的属性栏中将layoutStretch属性设置为“2,1”,这样这个水平布局管理器中的两个部件的宽度就是2:1的比例了。
如果要在代码中进行设置,可以在使用布局管理器的addWidget()函数添加部件的同时,在第二个参数中指定伸缩因子。
伙伴(buddy)是在QLabel类中提出的一个概念。
因为一个标签经常用作一个交互式部件的说明,就像表单布局管理器时看到的那样,一个lineEdit部件前面有一个标签说明这个lineEdit的作用。为了方便定位,QLabel提供了一个有用的机制,那就是提供了助记符来设置键盘焦点到对应的部件上,而这个部件就叫做这个QLabel的伙伴。
其中助记符就是我们所说的加速键。在使用英文标签时,在字符串的一个字母前面添加“&”符号,那么就可以指定这个标签的加速键是Alt加上这个字母,而对于中文,需要在小括号中指定加速键字母。
对于一个应用程序,当希望使用Tab键来将焦点从一个部件移动到下一个部件。在设计模式,设计器提供了Tab键的设置功能。在UI设计模式中,按下上边栏的编辑Tab顺序按钮进入编辑Tab键顺序模式,这时已经显示出了各个部件的Tab键顺序,只需要用鼠标点击这些数字,就可以更改它们。
代码实现方式如下:
//lineEdit在spinBox前面
setTabOrder(ui->lineEdit,ui->spinBox);
//spinBox在pushButton前面
setTabOrder(ui->spinBox,ui->pushButton);
//pushButton在checkBox前面
setTabOrder(ui->pushButton,ui->checkBox);
对于一个APP应用,需要最开始框架一层层深入到交互的每一层窗口,每个窗口使用哪些部件元素,如何布局,需要花一点心思,但是总体思路是框架设计由整体到局部,布局细化由局部到整体,尽量在每一层的局部就把布局昨晚,这样每一层只关心同等层次的布局,与软件开发类似。
本篇文章借用了QT社区的一些内容,欢迎访问Qt开源社区