11.QT-布局管理器(Box,Grid,Form,Stacked)
布局管理器简介
- QT中提供了对界面组件进行布局管理的类,用于对界面组件进行管理,
- 能够自动排列窗口中的界面组件
- 窗口大小变化后,便会自动更新界面组件的大小。
- 布局管理器可以自定义,从而达到更加个性化界面布局的效果
- 布局管理器可以相互嵌套,完成所有常用的界面布局
- QLayout是Qt中布局管理器的抽象基类,只能使用它的子类,如下图所示:
QBoxLayout水平/垂直布局
QBoxLayout有两个子类:QHBoxLayout(水平)和QVBoxLayout(垂直)
垂直布局,表示将垂直方向分为一个个格子,如下图所示:
水平布局如下图所示:
QVBoxLayout使用
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QWidget w;
QVBoxLayout *layout=new QVBoxLayout;
QPushButton btn1("test1",&w);
QPushButton btn2("test2",&w);
QPushButton btn3("test3",&w);
btn1.setMaximumSize(600,360);
btn1.setMinimumSize(100,60);
btn2.setMaximumSize(600,360);
btn2.setMinimumSize(100,60);
btn3.setMaximumSize(600,360);
btn3.setMinimumSize(100,60);
layout->addWidget(&btn1); //向布局管理器添加组件,实现自动布局
layout->addWidget(&btn2);
layout->addWidget(&btn3);
w.setLayout(layout); //为部件设置布局管理器
layout->setSpacing(10);
w.show();
return a.exec();
}
QHBoxLayout使用
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QWidget w;
QHBoxLayout *layout=new QHBoxLayout;
QPushButton btn1("test1",&w);
QPushButton btn2("test2",&w);
QPushButton btn3("test3",&w);
btn1.setMaximumSize(600,360);
btn1.setMinimumSize(100,60);
btn2.setMaximumSize(600,360);
btn2.setMinimumSize(100,60);
btn3.setMaximumSize(600,360);
btn3.setMinimumSize(100,60);
layout->addWidget(&btn1); //向布局管理器添加组件,实现自动布局
layout->addWidget(&btn2);
layout->addWidget(&btn3);
w.setLayout(layout); //为部件设置布局管理器
layout->setSpacing(10);
w.show();
return a.exec();
}
QBoxLayout相互嵌套
之前,我们写了QHBoxLayout(水平)和QVBoxLayout(垂直),但是只是单方面自动布局.
其实任何BoxLayout都可以相互嵌套,比如水平+垂直布局,本质就是一个QGridLayout(后面会讲)
示例代码如下:
#include <QHBoxLayout> #include <QVBoxLayout> #include <QPushButton> #include <QApplication> int main(int argc, char *argv[]) { QApplication a(argc, argv); QHBoxLayout *Hlayout1=new QHBoxLayout; QHBoxLayout *Hlayout2=new QHBoxLayout; QVBoxLayout *Vlayout=new QVBoxLayout; QWidget w; QPushButton btn1("test1",&w); QPushButton btn2("test2",&w); QPushButton btn3("test3",&w); QPushButton btn4("test4",&w); btn1.setMaximumSize(600,360); btn1.setMinimumSize(100,60); btn2.setMaximumSize(600,360); btn2.setMinimumSize(100,60); btn3.setMaximumSize(600,360); btn3.setMinimumSize(100,60); btn4.setMaximumSize(600,360); btn4.setMinimumSize(100,60); Hlayout1->addWidget(&btn1); //水平布局: btn1 btn2 Hlayout1->addWidget(&btn2); Hlayout1->setSpacing(10); Hlayout2->addWidget(&btn3); //水平布局: btn3 btn4 Hlayout2->addWidget(&btn4); Hlayout2->setSpacing(10); Vlayout->addLayout(Hlayout1); //垂直布局: Hlayout1 Hlayout2 Vlayout->addLayout(Hlayout2); Vlayout->setSpacing(10); w.setLayout(Vlayout); //设置布局管理器,由于Vlayout管理着Hlayout1 Hlayout2,所以只填写一个即可 w.show(); return a.exec(); }
效果如下所示:
布局管理器比例系数
默认情况下,组件之间以等比例的方式改变组件大小.
其实用户也可以自定义组件之间比例系数,当窗口放大时,便来更新比例系数.
常用函数:
QBoxLayout::setStretch ( int index, int stretch ); //设置具体组件的拉伸系数
// index:表示布局管理器里的第几个组件
// stretch :拉伸系数
bool QBoxLayout::setStretchFactor ( QWidget * widget, int stretch );
//设置部件拉伸系数,如果存在*widget这个组件,则设置成功,返回true
bool QBoxLayout::setStretchFactor ( QLayout * layout, int stretch );
//设置布局拉伸系数, ,如果存在*layout这个组件,则设置成功,返回true
示例代码如下:
#include <QHBoxLayout> #include <QVBoxLayout> #include <QPushButton> #include <QApplication> int main(int argc, char *argv[]) { QApplication a(argc, argv); QHBoxLayout *Hlayout1=new QHBoxLayout; QHBoxLayout *Hlayout2=new QHBoxLayout; QVBoxLayout *Vlayout=new QVBoxLayout; QWidget w; QPushButton btn1("test1",&w); QPushButton btn2("test2",&w); QPushButton btn3("test3",&w); QPushButton btn4("test4",&w); btn1.setMaximumSize(600,360); btn1.setMinimumSize(100,60); btn2.setMaximumSize(600,360); btn2.setMinimumSize(100,60); btn3.setMaximumSize(600,360); btn3.setMinimumSize(100,60); btn4.setMaximumSize(600,360); btn4.setMinimumSize(100,60); //设置大小策略,Expanding表示组件可扩展 btn1.setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Expanding); btn2.setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Expanding); btn3.setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Expanding); btn4.setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Expanding); Hlayout1->addWidget(&btn1); //水平布局: btn1 btn2 Hlayout1->addWidget(&btn2); Hlayout1->setSpacing(10); Hlayout2->addWidget(&btn3); //水平布局: btn3 btn4 Hlayout2->addWidget(&btn4); Hlayout2->setSpacing(10); Vlayout->addLayout(Hlayout1); //垂直布局: Hlayout1 Hlayout2 Vlayout->addLayout(Hlayout2); Vlayout->setStretchFactor(Hlayout1,1); Vlayout->setStretchFactor(Hlayout2,3); Vlayout->setSpacing(10); w.setLayout(Vlayout); //设置布局管理器,由于Vlayout管理着Hlayout1 Hlayout2,所以只填写一个即可 w.show(); return a.exec(); }
拉伸窗口后:
QGridLayout网格布局
以网格的方式管理界面组件,类似于:上面嵌套方式来使用QBoxLayout.
常用函数:
void addWidget ( QWidget * widget, int row, int column, Qt::Alignment alignment = 0 );
// row column :表示将widget这个部件放在网格哪个位置
void addWidget ( QWidget * widget, int fromRow, int fromColumn, int rowSpan, int columnSpan, Qt::Alignment alignment = 0 );
// row column :表示将widget这个部件放在网格哪个位置
// rowSpan: widget这个部件占多少行
// columnSpan: widget这个部件占多少列
void setColumnStretch(int column,int stretch); //设置列拉伸系数
// column:设置布局管理器里的第几列,第1列为0
void setRowStretch(int row,int stretch); //设置行拉伸系数
// row:设置的第几行
示例代码:
#include <QGridLayout> #include <QPushButton> #include <QApplication> int main(int argc, char *argv[]) { QApplication a(argc, argv); QGridLayout *layout=new QGridLayout; QWidget w; QPushButton btn1("test1",&w); QPushButton btn2("test2",&w); QPushButton btn3("test3",&w); QPushButton btn4("test4",&w); btn1.setMinimumSize(100,60); btn2.setMinimumSize(100,60); btn3.setMinimumSize(100,60); btn4.setMinimumSize(100,60); //设置大小策略,Expanding表示组件可扩展 btn1.setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Expanding); btn2.setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Expanding); btn3.setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Expanding); btn4.setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Expanding); layout->addWidget(&btn1,0,0); layout->addWidget(&btn2,0,1); layout->addWidget(&btn3,1,0); layout->addWidget(&btn4,1,1); layout->setRowStretch(0,1); //设置第0行,比例为1 layout->setRowStretch(1,2); //设置第1行,比例为2 layout->setColumnStretch(0,1); //设置第0列,比例为1 layout->setColumnStretch(1,2); //设置第1列,比例为2 w.setLayout(layout); //设置布局管理器 w.show(); return a.exec(); }
拉伸窗口后:
QGridLayout相互嵌套
之前讲过任何BoxLayout都可以相互嵌套,所以QGridLayout也支持布局管理器嵌套,比如QGridLayout+ QVBoxLayout嵌套:
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QGridLayout *layout=new QGridLayout;
QVBoxLayout *Vlyt=new QVBoxLayout;
QWidget w;
QPushButton btn1("test1",&w);
QPushButton btn2("test2",&w);
QPushButton btn3("test3",&w);
QPushButton btn4("test4",&w);
QPushButton btn5("test5",&w);
btn1.setMinimumSize(100,60);
btn2.setMinimumSize(100,60);
btn3.setMinimumSize(100,60);
btn4.setMinimumSize(100,30); //btn4 btn5按钮需要缩小高度
btn5.setMinimumSize(100,30);
//设置大小策略,Expanding表示组件可扩展
btn1.setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Expanding);
btn2.setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Expanding);
btn3.setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Expanding);
btn4.setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Expanding);
btn5.setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Expanding);
Vlyt->addWidget(&btn4);
Vlyt->addWidget(&btn5);
layout->addWidget(&btn1,0,0);
layout->addWidget(&btn2,0,1);
layout->addWidget(&btn3,1,0);
layout->addLayout(Vlyt,1,1);
layout->setRowStretch(0,1); //设置第0行,比例为1
layout->setRowStretch(1,2); //设置第1行,比例为2
layout->setColumnStretch(0,1); //设置第0列,比例为1
layout->setColumnStretch(1,2); //设置第1列,比例为2
w.setLayout(layout); //设置布局管理器
w.show();
return a.exec();
}
拉伸窗口后:
QFormLayout表单布局
以表单的方式管理界面组件,专为标签和字段(组件)的形式创建的
表单布局也支持嵌套,可以管理子布局
常用函数:
addRow ( QWidget * label, QWidget * field );
addRow ( QWidget * label, QLayout * field );
addRow ( const QString & labelText, QWidget * field );
addRow ( const QString & labelText, QLayout * field );
void setLabelAlignment ( Qt::Alignment alignment );
//设置标签对齐方式,比如标签左对齐
void setRowWrapPolicy ( RowWrapPolicy policy );
//设置字段包装策略
//比如参数WrapLongRows:表示给标签足够长空间,如果一行满足不了标签和字段显示,则将字段放在下行显示
//参数QFormLayout::WrapAllRows: 示字段信息总在标签下面列出(占据整个行大小)
示例代码:
#include <QLineEdit> #include <QFormLayout> #include <QApplication> int main(int argc, char *argv[]) { QApplication a(argc, argv); QWidget w(0,Qt::WindowCloseButtonHint); QLineEdit line1(&w); QLineEdit line2(&w); QLineEdit line3(&w); QFormLayout *layout= new QFormLayout; layout->addRow("姓名:",&line1); layout->addRow("邮箱:",&line2); layout->addRow("地址:",&line3); layout->setRowWrapPolicy(QFormLayout::WrapAllRows); //设置字段总在标签下面 w.setLayout(layout); w.show(); return a.exec(); }
效果:
QStackedLayout栈式布局
- 将所有组件进行垂直管理
- 并且每次只能有一个组件现在在屏幕上
- 只有最顶层的组件才会被最终显示
- 常用于图片播放,安装向导等
特点
- 组件大小一致且充满父组件的显示区
- 能够自由切换需要显示的组件
- 不能直接嵌套其它布局管理器,只能间接嵌套
常用函数:
int addWidget ( QWidget * widget ); //顺序添加组件
int insertWidget ( int index, QWidget * widget ); //插入组件
void removeWidget ( QWidget * widget ); //删除组件
QWidget * currentWidget() ; //返回当前组件
int currentIndex(); //返回当前组件索引值
void setCurrentIndex ( int index ); //切换当前组件
void setCurrentWidget ( QWidget * widget ); //更换当前显示的组件
代码试验,实现按钮切换页效果
Widget.h
#ifndef WIDGET_H #define WIDGET_H #include <QWidget> #include <QPushButton> #include <QStackedLayout> class Widget : public QWidget { Q_OBJECT QStackedLayout *stack; QPushButton btn1; QPushButton btn2; QPushButton btn3; public: Widget(QWidget *parent = nullptr); ~Widget(); protected slots: void onBtn(); }; #endif // WIDGET_H
Widget.cpp
#include "widget.h" Widget::Widget(QWidget *parent) : QWidget(parent), btn1("第一页",this), btn2("第二页",this), btn3("第三页",this) { btn1.setFixedSize(100,38); btn2.setFixedSize(100,38); btn3.setFixedSize(100,38); QHBoxLayout *Hlyt = new QHBoxLayout; QVBoxLayout *Vlyt = new QVBoxLayout; QSpacerItem *vSpacer = new QSpacerItem(100, 20, QSizePolicy::Minimum, QSizePolicy::Expanding); // 使用了一个垂直弹簧 Vlyt->addWidget(&btn1); Vlyt->addWidget(&btn2); Vlyt->addWidget(&btn3); Vlyt->addItem(vSpacer); Vlyt->setSpacing(5); stack = new QStackedLayout; QWidget *page1 = new QWidget(this); page1->setStyleSheet("background: rgb(255,0,0);"); QWidget *page2 = new QWidget(this); page2->setStyleSheet("background: rgb(0,255,0);"); QWidget *page3 = new QWidget(this); page3->setStyleSheet("background: rgb(0,0,255);"); stack->addWidget(page1); stack->addWidget(page2); stack->addWidget(page3); Hlyt->addLayout(Vlyt); Hlyt->addLayout(stack); // 建立信号槽 connect(&btn1, SIGNAL(clicked()), this, SLOT(onBtn())); connect(&btn2, SIGNAL(clicked()), this, SLOT(onBtn())); connect(&btn3, SIGNAL(clicked()), this, SLOT(onBtn())); this->setLayout(Hlyt); this->resize(700,500); } void Widget::onBtn() { QObject *obj = this->sender(); // 获取信号发送者 if (obj == &btn1) { stack->setCurrentIndex(0); } else if (obj == &btn2) { stack->setCurrentIndex(1); } else { stack->setCurrentIndex(2); } } Widget::~Widget() { }
main.cpp
#include "widget.h" #include <QApplication> int main(int argc, char *argv[]) { QApplication a(argc, argv); Widget w; w.show(); return a.exec(); }
效果:
人间有真情,人间有真爱。