(十)布局管理器

绝对定位(直接在像素级指定各组件的位置与大小)有一些缺点:

1、对于某些平台,窗口部件的大小可能并不合适(无法自适应父窗口的变化)

2、位置与大小需要人工计算,难以维护

 

布局管理器

提供相关类对界面组件进行布局管理

使用布局管理器:

1、任意容器类的组件都可以指定布局管理器

2、能够自动排列窗口中的界面组件

3、窗口变化后自动更新界面组件的大小


此处组件1与组件2拥有相同的父对象(QWidget对象)

 

布局管理器特性:

1、统一布局管理器中的所有组件拥有相同的父组件(为使用管理器的组件)

2、设置布局管理器的同时隐式的指定了父子关系

 

布局管理器的抽象基类QLayout


1、  通过继承QLayout实现了功能各异且互补的预定义布局管理器(QBoxLayout、QGridLayout、QFormLayout、QStackedLayout)

2、  布局管理器之间可以相互嵌套,形成更加复杂的布局方式(QStackedLayout内不能直接嵌套其他布局管理器)

3、通过继承自QLayout类可以根据需要自定义布局管理器(需要继承自QLayout)

         0)、定义一个数据结构作为类成员,数据结构用于储存要被布局管理的项,每个项都是一个QLayoutItem对象

1)、重写

virtual void

addItem ( QLayoutItem * item ) = 0

如何添加一个项到布局管理器

2)、重写

virtual void

setGeometry ( const QRect & r )

如何控制布局管理器的布局

3)、重写

virtual QSize

sizeHint () const = 0

布局管理器的首选大小

4)、重写

virtual QLayoutItem *

itemAt ( int index ) const = 0

如何遍历布局管理器

5)、重写

virtual QLayoutItem *

takeAt ( int index ) = 0

如何删除布局管理器中的项

6)、重写

virtual QSize

minimumSize () const

项最小大小

4、需要注意的是,布局管理器不是界面组件,而是界面组件的定位策略

 

QBoxLayout布局管理器

以水平(QHBoxLayout)或垂直(QVBoxLayout)的方式管理界面组件


布局方式:


水平布局管理器例子:

 QHBoxLayout*layout = new QHBoxLayout();
 
   TestBtn1.setText("Test Button 1");
   TestBtn1.setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);     //设置TestBtn1被布局时的大小策略
   TestBtn1.setMinimumSize(160, 30);
 
   TestBtn2.setText("Test Button 2");
   TestBtn2.setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
   TestBtn2.setMinimumSize(160, 30);
 
   TestBtn3.setText("Test Button 3");
   TestBtn3.setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
   TestBtn3.setMinimumSize(160, 30);
 
   TestBtn4.setText("Test Button 4");
   TestBtn4.setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
   TestBtn4.setMinimumSize(160, 30);
 
   layout->setSpacing(30);                     //各个BUTTON组件之间的间隔
   layout->addWidget(&TestBtn1);
   layout->addWidget(&TestBtn2);
   layout->addWidget(&TestBtn3);
   layout->addWidget(&TestBtn4);
 
   setLayout(layout);   //别忘了使用布局管理器

 

嵌套布局(垂直嵌套水平)的例子:

QHBoxLayout*hLayout1 = new QHBoxLayout();             //构造水平布局管理器
   QHBoxLayout* hLayout2 = new QHBoxLayout();
   QVBoxLayout* vLayout = new QVBoxLayout();                 //构造垂直布局管理器
 
   TestBtn1.setText("Test Button 1");
   TestBtn1.setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);    
   TestBtn1.setMinimumSize(160, 30);
 
   TestBtn2.setText("Test Button 2");
   TestBtn2.setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
   TestBtn2.setMinimumSize(160, 30);
 
   hLayout1->setSpacing(10);               //指定布局管理器hLayout1管理的组件之间的间隔
   hLayout1->addWidget(&TestBtn1);
   hLayout1->addWidget(&TestBtn2);
 
   TestBtn3.setText("Test Button 3");
   TestBtn3.setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
   TestBtn3.setMinimumSize(160, 30);
 
   TestBtn4.setText("Test Button 4");
   TestBtn4.setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
   TestBtn4.setMinimumSize(160, 30);
 
   hLayout2->setSpacing(10);
   hLayout2->addWidget(&TestBtn3);
   hLayout2->addWidget(&TestBtn4);
 
   vLayout->setSpacing(10);                  //设置布局管理器vLayout管理的布局(水平布局管理器hLayout1与hLayout2)间间隔
   vLayout->addLayout(hLayout1);      //向布局管理器中添加布局(嵌套布局管理器的方式)
   vLayout->addLayout(hLayout2);
 
   setLayout(vLayout);                                     //设置布局管理器布局当前对象


 

嵌套之后是这样的


QBoxLayout与QGridLayout可以设置布局管理器伸展时的比例系数

1、默认情况下以等比例的方式更新组件大小

2、可以自定义组件大小更新时的比例系数

3、比例系数决定组件大小的相对变化

 

注:由于组件的初始大小是独立于布局管理器设置的,因此不能保证组件的大小始终符合比例系数

 

QBoxLayout中比例系数设置函数

void

setStretch ( int index, int stretch )

bool

setStretchFactor ( QWidget * widget, int stretch )

bool

setStretchFactor ( QLayout * layout, int stretch )

 

 

网格布局管理器(QGridLayout)

以网格(二维)的方式管理界面组件

 

QGridLayout中比例系数:

void

setColumnStretch ( int column, int stretch )

void

setRowStretch (int row,int stretch )

 

例子:

QGridLayout*layout = new QGridLayout();    //构造一个网格布局
//……..
layout->setSpacing(10);
   layout->addWidget(&TestBtn1, 0, 0);              //向网格布局对象中0行0列的位置添加组件
   layout->addWidget(&TestBtn2, 0, 1);
   layout->addWidget(&TestBtn3, 1, 0);
   layout->addWidget(&TestBtn4, 1, 1);
   layout->setRowStretch(0, 1);                         //设置0行随窗口伸展时的系数
   layout->setRowStretch(1, 3);
   layout->setColumnStretch(0, 1);                        //设置0列随窗口伸展时的系数
   layout->setColumnStretch(1, 3);
 
   setLayout(layout);
 
QGridLayout中的组件可以根据需要跨越多个网格
void QGridLayout::addWidget ( QWidget * widget,int fromRow, int fromColumn, int rowSpan,int columnSpan,Qt::Alignment alignment =0 )
 
例子:
QGridLayout*layout = new QGridLayout();
//……
layout->setSpacing(10);
//在网格布局器的第0行,0列处开始,添加占用2行,1列的组件TestBtn1
   layout->addWidget(&TestBtn1, 0, 0, 2, 1);                       
layout->addWidget(&TestBtn2,0, 1, 2, 1);                       
//第0行,第1行被TestBtn1占用,所以只能从第2行开始
   layout->addWidget(&TestBtn3, 2, 0, 1, 2);                       
   layout->addWidget(&TestBtn4, 3, 0, 1, 2);
 


 

表单布局管理器(QFormLayout)

1、以表单的方式管理界面组件

2、表单布局中的标签与组件是相互对应的关系


QFormLayout成员:

添加组件

void

addRow ( QWidget * label, QWidget * field )

void

addRow ( QWidget * label, QLayout * field )

void

addRow ( const QString & labelText, QWidget * field )

void

addRow ( const QString & labelText, QLayout * field )

void

addRow ( QWidget * widget )

void

addRow ( QLayout * layout )

控制样式

void

setRowWrapPolicy ( RowWrapPolicy policy )

void

setLabelAlignment (Qt::Alignment alignment )

 

例子:

QLineEdit*nameEdit = new QLineEdit();
   QLineEdit* mailEdit = new QLineEdit();
   QLineEdit* addrEdit = new QLineEdit();
   QFormLayout* layout = new QFormLayout(); //构建一个表单布局管理器
 
   layout->addRow("Name:", nameEdit);   //使用指定的 label "Name:"与组件nameEdit向布局管理器中添加新行
   layout->addRow("Email:", mailEdit);
   layout->addRow("Address:", addrEdit);
   layout->setRowWrapPolicy(QFormLayout::WrapLongRows);                  //设置组件排布方式
    layout->setLabelAlignment(Qt::AlignRight);   //设置标签的对齐方式
   layout->setSpacing(10);
 
   setLayout(layout);                                                           //设置布局
   setWindowTitle("FTP");
 


 

栈式布局管理器(QStackedLayout):

1、所有组件在垂直屏幕的方向上被管理

2、每次只有一个组件会显示在屏幕上

3、只有顶层的组件会被显示

 

栈式布局管理器特点:

组件大小一致且充满父组件的显示区域

不能直接嵌套其他布局管理器

能够自由切换需要显示的组件

每次能且仅能显示一个组件

 

QStackedLayout的几个成员:

int

addWidget ( QWidget * widget )

QWidget *

currentWidget () const

void

setCurrentIndex ( int index )

int

currentIndex () const

 

由于栈式布局管理器的特点(不能直接嵌套其他布局管理器),要形成复杂的布局就必须借用中间组件

例子:

Widget::Widget(QWidget *parent) :QWidget(parent),
   TestBtn1(this), TestBtn2(this), TestBtn3(this), TestBtn4(this)
{
   initControl();
}
 
void Widget::initControl()
{
   QStackedLayout* sLayout = new QStackedLayout();       //创建栈布局管理器
QHBoxLayout*hLayout = new QHBoxLayout();                //创建水平布局管理器
//创建对象widget使用水平布局管理器,以便栈布局管理器间接嵌套水平布局管理器
   QWidget* widget = new QWidget();                                   
   QTimer* timer = new QTimer(this);                          
 
   TestBtn1.setText("1st Button");
   TestBtn2.setText("2rd Button");
   TestBtn3.setText("3th Button");
   TestBtn4.setText("Test Button 4");
 
   TestBtn2.setParent(widget);                     //由于往布局管理器中添加组件时也会更改父组件(将被添加的子组件的父对象设置为使用布局管理器的对象,组件只能以组件作为父对象)
   TestBtn3.setParent(widget);                     //所以此处不用修改父组件亦可
 
   hLayout->addWidget(&TestBtn2);           //将组件TestBtn2加入布局管理器hLayout
   hLayout->addWidget(&TestBtn3);
 
    widget->setLayout(hLayout);                    //在组件widget中使用布局管理器hLayout
 
   sLayout->addWidget(&TestBtn1); // 0             //将组件TestBtn1加入到栈布局管理器中,同时组件TestBtn1为下标0组件
   sLayout->addWidget(widget); // 1           //将组件widget加入到布局管理器中,下标1,下标被布局管理器内部记录,不用额外使用变量
   sLayout->addWidget(&TestBtn4); // 2
 
   sLayout->setCurrentIndex(0); //设置当前下标值为0,即使下标为0的组件在当前显示
 
   setLayout(sLayout);                                                                           //使用布局管理器
 
   connect(timer, SIGNAL(timeout()), this, SLOT(timerTimeout()));  
 
   timer->start(2000);          //启动定时器并设定触发信号时间间隔为2s(2000ms)
}
 
void Widget::timerTimeout()
{       
   QStackedLayout* sLayout = dynamic_cast<QStackedLayout*>(layout());
   if( sLayout != NULL )        
    {//currentIndex函数返回布局管理器中当前组件的下标   count函数获取布局管理器中组件数量
       int index = (sLayout->currentIndex() + 1) % sLayout->count();                 //防止下标越界
 
       sLayout->setCurrentIndex(index);                     //显示下标值为index的组件
    }
}
 
Widget::~Widget()
{
   
}


 

 

 

 声明:

此文根据 狄泰学院唐老师的《QT实验分析教程》创作,并根据自身理解对其进行了少许的扩展

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值