布局管理器簡介
- QT中提供了對界面組件進行布局管理的類,用於對界面組件進行管理,
- 能夠自動排列窗口中的界面組件
- 窗口大小變化后,便會自動更新界面組件的大小。
- 布局管理器可以自定義,從而達到更加個性化界面布局的效果
- 布局管理器可以相互嵌套,完成所有常用的界面布局
- QLayout是Qt中布局管理器的抽象基類,如下圖所示:

QBoxLayout水平/垂直布局
QBoxLayout有兩個子類:QHBoxLayout(水平)和QVBoxLayput(垂直)
比如垂直布局,表示將垂直方向分為一個個格子,如下圖所示:

QVBoxLayput使用
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(); }
QHBoxLayput使用
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(); }
QBoxLayput相互嵌套
之前,我們寫了QHBoxLayout(水平)和QVBoxLayput(垂直),但是只是單方面自動布局.
接下來,我們來使用嵌套,來實現水平+垂直自動布局,如下圖所示:

示例代碼如下:
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
示例代碼如下:
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.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); 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:設置的第幾行
示例代碼:
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相互嵌套
QGridLayout也支持布局管理器嵌套,比如,如下圖所示:

示例代碼:
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: 示字段信息總在標簽下面列出(占據整個行大小)
示例代碼:
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 ); //更換當前顯示的組件
代碼試驗,通過定時器自動切換QStackedLayout
Widget.h
#ifndef WIDGET_H #define WIDGET_H #include <QtGui> #include <QWidget> #include <QObject>
class Widget : public QWidget { Q_OBJECT QTimer *timer; QStackedLayout *Stack; QPushButton btn1; QPushButton btn2; QPushButton btn3; QPushButton btn4; private slots: void time_handler(); public: explicit Widget(QWidget *parent = 0); }; #endif // WIDGET_H
Widget.cpp
#include "Widget.h" #include <QDebug> #include <QTimer> Widget::Widget(QWidget *parent) : QWidget(parent), btn1("test1",this), btn2("test2",this), btn3("test3",this), btn4("test4",this) { btn1.setMinimumSize(80,40); Stack = new QStackedLayout; Stack->addWidget(&btn1); Stack->addWidget(&btn2); Stack->addWidget(&btn3); Stack->addWidget(&btn4); Stack->setCurrentIndex(0); this->setLayout(Stack); /*啟動定時器*/ QTimer *timer = new QTimer(this); connect(timer, SIGNAL(timeout()), this, SLOT(time_handler())); timer->start(1000); //1000ms } void Widget::time_handler() { static int index=1; Stack->setCurrentIndex((index++)%4); //切換頁面 qDebug()<<"Timer out"; }
main.cpp
int main(int argc, char *argv[]) { QApplication app(argc,argv); Widget w; w.show(); return app.exec(); }
效果:

接下來試驗間接嵌套
修改構造函數
Widget::Widget(QWidget *parent) : QWidget(parent), btn1("test1",this), btn2("test2",this), btn3("test3",this), btn4("test4",this) { btn1.setMinimumSize(80,40); QWidget *w = new QWidget; /*設置多個子組件的父類*/ btn3.setParent(w); btn4.setParent(w); btn3.setMinimumSize(120,60); btn4.setMinimumSize(120,60); /*通過其它布局管理器來管理*/ QVBoxLayout *Vlyt = new QVBoxLayout; Vlyt->addWidget(&btn3); Vlyt->addWidget(&btn4); Vlyt->setSpacing(10); w->setLayout(Vlyt); Stack = new QStackedLayout; Stack->addWidget(&btn1); Stack->addWidget(&btn2); Stack->addWidget(w); Stack->setCurrentIndex(0); this->setLayout(Stack); /*啟動定時器*/ QTimer *timer = new QTimer(this); connect(timer, SIGNAL(timeout()), this, SLOT(time_handler())); timer->start(1000); //1000ms
}
效果

