布局主要是用来管理多个组件如何排列的。如果没有布局的话,我们可能需要给每个组件都设置一下在界面中的位置,这样就比较麻烦了。有了布局,我们就可以将一些组件放在一个布局中,通过布局去管理各个组件的位置,我们就只需要给布局设置在界面中的位置即可。
在 QT 中一共有 5 种布局,他们的继承关系如下图:
此图来源于博客:QT 的QLayout布局属性
QVBoxLayout 其中的 “V” 就是单词 vertical 的简写,垂直的意思,就是该布局中的组件都是垂直方向排列的。
简单示例:
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Widget w;
QVBoxLayout layout;
QPushButton btn1("btn1",&w);//创建 3 个按钮
QPushButton btn2("btn2",&w);
QPushButton btn3("btn3",&w);
layout.addWidget(&btn1);//将按钮添加到布局管理器中
layout.addWidget(&btn2);
layout.addWidget(&btn3);
w.setLayout(&layout);//设置当前界面(widget)的布局管理器
w.show();
return a.exec();
}
水平布局与垂直布局相反,其中的各个组件按照水平方向进行排列。
简单示例:
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Widget w;
QHBoxLayout layout;
QPushButton btn1("btn1",&w);//创建 3 个按钮
QPushButton btn2("btn2",&w);
QPushButton btn3("btn3",&w);
layout.addWidget(&btn1);//将按钮添加到布局管理器中
layout.addWidget(&btn2);
layout.addWidget(&btn3);
w.setLayout(&layout);//设置当前界面(widget)的布局管理器
w.show();
return a.exec();
}
该方法用于设置布局容器中各个组件的距离。
layout.setSpacing(50);
我们将前面的水平布局的距离的 layout 设置 spacing 为 50 :
可以看到,三个按钮之间的距离变长了。
该方法不要与 setSpacing() 方法混淆了,addSpacing() 用于在布局容器的任意位置加上指定大小的区域。
layout.addWidget(&btn1);//将按钮添加到布局管理器中
layout.addWidget(&btn2);
layout.addSpacing(50);
layout.addWidget(&btn3);
上述代码表示在 btn2 和 btn3 之间增加 50 单位的区域:
该函数用于设置布局容器中某个组件的拉伸比例。
index:容器中某个组件的下标
stretch:拉伸比例
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Widget w;
QHBoxLayout layout;
QPushButton btn1("btn1",&w);//创建 3 个按钮
QPushButton btn2("btn2",&w);
QPushButton btn3("btn3",&w);
layout.addWidget(&btn1);//将按钮添加到布局管理器中
layout.addWidget(&btn2);
layout.addWidget(&btn3);
//设置拉伸比例
layout.setStretch(0,2);//btn1 拉伸比例设置为 2
layout.setStretch(1,2);//btn2 拉伸比例设置为 2
layout.setStretch(2,1);//btn3 拉伸比例设置为 1
w.setLayout(&layout);//设置当前界面(widget)的布局管理器
w.show();
return a.exec();
}
运行程序后,我们稍微调整一下窗口大小,如上图所示,btn1 和 btn2 都变大了,btn3 没有变化,但是 btn1 与 btn2 并没有变成 btn3 的 2 倍,因为此时的窗口大小还不足以显示 btn1 、btn2 扩大两倍后的情形。当我们再次调整窗口大小:
此时 btn1 与 btn2 差不多有 btn3 的两倍大了。如果我们再将窗口调大:
btn3 也变大了。整个过程中,btn1(btn2) 与 btn3 的大小比例一介于 btn3 <= btn1 <=2btn3。
setStretch ( int index, int stretch ) 方法还有两个类似的方法:
//设置部件拉伸系数,如果*widget存在,则设置成功,返回true
bool QBoxLayout::setStretchFactor ( QWidget * widget, int stretch );
//设置子布局拉伸系数,如果*layout存在,则设置成功,返回true
bool QBoxLayout::setStretchFactor ( QLayout * layout, int stretch );
layout.addWidget(&btn1);//将按钮添加到布局管理器中
layout.addWidget(&btn2);
layout.addWidget(&btn3);
layout.setStretchFactor(&btn1,2);
layout.setStretchFactor(&btn2,2);
layout.setStretchFactor(&btn3,1);
该段代码运行后的效果与前面的示例一致。
该函数用于设置布局容器中组件到容器的 4 个方向的距离。
layout.setContentsMargins(50,100,70,200);
该布局可以快速的帮我们完成一个表单界面,如下图:
这个布局比较简单,直接上代码:
int main(int argc, char *argv[]){
QApplication a(argc, argv);
Widget w;
QFormLayout layout;
QLineEdit* text1 = new QLineEdit();
QLineEdit* text2 = new QLineEdit();
QLineEdit* text3 = new QLineEdit();
layout.addRow("Name:",text1);
layout.addRow("Email:",text2);
layout.addRow("Adress:",text3);
layout.setSpacing(10);
layout.setLabelAlignment(Qt::AlignRight);//设置标签的对齐方式
w.setLayout(&layout);//设置当前界面(widget)的布局管理器
w.show();
return a.exec();
}
该布局将布局区域划分成很多个小格子,其中的组件占一个或多个格子。
常用函数:
//表示将 widget 放在网格的第几行第几列
void addWidget ( QWidget * widget, int row, int column, Qt::Alignment alignment = 0 );
//表示将 widget 放在网格的第几行第几列 , rowSpan 表示该组件占几行,columnSpan 表示该组件占几列
void addWidget ( QWidget * widget, int fromRow, int fromColumn, int rowSpan, int columnSpan, Qt::Alignment alignment = 0 );
//设置第几列的拉伸系数
void setColumnStretch(int column,int stretch);
//设置第几行的拉伸系数
void setRowStretch(int row,int stretch);
简单示例:
int main(int argc, char *argv[]){
QApplication a(argc, argv);
Widget w;
QGridLayout layout;
QPushButton btn1("btn1",&w);
QPushButton btn2("btn2",&w);
QPushButton btn3("btn3",&w);
QPushButton btn4("btn4",&w);
QPushButton btn5("btn5",&w);
QPushButton btn6("btn6",&w);
layout.addWidget(&btn1,0,0,1,2);//第一行,第一列,占一行两列
layout.addWidget(&btn2,1,0,1,1);//第二行,第一列,占一行一列
layout.addWidget(&btn3,1,1);//第二行,第二列,占一行一列
layout.addWidget(&btn4,2,0,2,3);//第三行,第一列,占两行三列
//由于 btn4 占了两行,所以后面的要从第五行开始
layout.addWidget(&btn5,4,0,1,2);//第五行,第一列,占一行两列
//由于 btn5 占了两列,所以 btn6 要从三列开始
layout.addWidget(&btn6,4,2,1,1);//第五行,第三列,占一行一列
w.setLayout(&layout);//设置当前界面(widget)的布局管理器
w.show();
return a.exec();
}
使用网格布局时需要注意的是,当前添加的 widget 所在的行和列位置,例如前面的 btn6 的列应该设置为 2 而不是 1。
布局嵌套就是指一个布局可以嵌套在另一个布局中,比如网格布局的某一行某一列可以设置为一个水平布局。
我们以前面的例子做一个简单示例,将一个水平布局作为界面的主布局,然后将前面表单示例代码与网格布局的示例代码都设置到这个水平布局上。
int main(int argc, char *argv[]){
QApplication a(argc, argv);
Widget w;
QHBoxLayout hlayout;//主布局
QGridLayout gridLayout;
QPushButton btn1("btn1",&w);
QPushButton btn2("btn2",&w);
QPushButton btn3("btn3",&w);
QPushButton btn4("btn4",&w);
QPushButton btn5("btn5",&w);
QPushButton btn6("btn6",&w);
gridLayout.addWidget(&btn1,0,2,1,2);
gridLayout.addWidget(&btn2,1,0,1,1);
gridLayout.addWidget(&btn3,1,1);
gridLayout.addWidget(&btn4,2,0,2,3);
gridLayout.addWidget(&btn5,4,0,1,2);
gridLayout.addWidget(&btn6,4,2,1,1);
QFormLayout formLayout;
QLineEdit* text1 = new QLineEdit();
QLineEdit* text2 = new QLineEdit();
QLineEdit* text3 = new QLineEdit();
formLayout.addRow("Name:",text1);
formLayout.addRow("Email:",text2);
formLayout.addRow("Adress:",text3);
//将表单布局、网格布局作为子布局添加到主布局中
hlayout.addLayout(&formLayout);
hlayout.addLayout(&gridLayout);
w.setLayout(&hlayout);//设置当前界面(widget)的布局管理器
w.show();
return a.exec();
}