(十)布局管理器

部署运行你感兴趣的模型镜像

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

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实验分析教程》创作,并根据自身理解对其进行了少许的扩展

您可能感兴趣的与本文相关的镜像

Linly-Talker

Linly-Talker

AI应用

Linly-Talker是一款创新的数字人对话系统,它融合了最新的人工智能技术,包括大型语言模型(LLM)、自动语音识别(ASR)、文本到语音转换(TTS)和语音克隆技术

<think>嗯,用户这次想了解布局管理器在编程中的存在意义和优势。从引用材料看,用户已经接触了Java、Qt和Android的布局管理器示例,但需要系统性的理论解释。用户可能是个刚开始学习GUI编程的开发者,正被手动计算控件坐标的痛苦折磨着。布局管理器的核心价值其实可以用四个字概括:解放生产力。早期编程中,开发者必须像绣花一样精确计算每个按钮的位置(x=35,y=120这种),不仅耗时,更可怕的是适配不同分辨率时全部要重算。引用[3]提到的外边距控制就是个典型例子——如果不用QLayout的setContentsMargins,光调个间距就得写几行计算代码。注意到用户上次提到“不是学习资料”,说明ta更关注实践价值。所以重点要突出“自动化”和“响应式”这两个王牌特性。比如引用[2]的pack布局,明明只是.pack()两个按钮,就能自动左右分列且保留间距,这比手动设置frame几何属性高效倍。而引用[4]的RelativeLayout更是妙,通过相对定位描述(“在A控件下方”“与B控件左对齐”),完全规避了像素级坐标指定。不过用户可能没意识到的是,布局管理器还有隐藏优势:团队协作标准化。比如Android的XML布局文件,任何开发者看到<RelativeLayout>就知道要用相对定位规则,比口头传递坐标规范可靠得多。这点值得在回答里强调。最后要提醒跨平台场景的重要性。就像引用[1]提到Java是互联网产物,现在程序往往要运行在从手机到4K显示器的不同设备上。没有布局管理器的弹性分配机制,做多分辨率适配简直是不可能任务。</think> 布局管理器在GUI编程中广泛应用的核心原因在于其解决了界面自适应与跨平台兼容的难题,主要优势体现在以下方面: ### 一、核心使用原因 1. **自适应界面需求** 手动设置组件坐标(如`x=35, y=120`)难以适应窗口大小变化。当用户调整窗口尺寸时,布局管理器会自动重新计算控件位置和大小(如Java的`GridLayout`自动等分区域)[^2]。 2. **跨平台显示一致性** 不同系统的显示效果差异显著。Qt的布局管理器通过`setContentsMargins()`统一控件外边距(如Windows/macOS默认间距不同),避免界面错位[^3]。 3. **开发效率优化** 以Java Swing的`BorderLayout`为例,仅需`add(button, BorderLayout.EAST)`即可实现按钮固定在右侧,免去像素级计算。 ### 二、核心优势 1. **响应式布局自动化** ```java // Java示例:按钮自动填充可用空间 JPanel panel = new JPanel(new GridLayout(2,3)); panel.add(new JButton("自适应按钮")); ``` 当父容器尺寸改变时,`GridLayout`自动调整网格内组件大小[^2]。 2. **代码维护简化** 安卓开发中,`RelativeLayout`通过XML属性(如`android:layout_toRightOf="@id/btn1"`)建立组件间相对关系,删除控件不会影响整体结构[^4]。 3. **屏幕适配能力** 通过权重分配(如Qt的`QBoxLayout.setStretch()`)实现比例划分。例如: ```python # Python Tkinter示例:输入框占70%宽度 entry.pack(side="left", fill="both", expand=True, padx=5, pady=5) ``` 4. **内外边距统一控制** 全局设置组件间隔: ```cpp // Qt示例:设置布局内边距为10px layout->setContentsMargins(10,10,10,10); ``` 避免逐一手动添加空白组件[^3]。 ### 三、典型案例说明 1. **WEB框架(如CSS Flexbox)**:媒体查询响应屏幕尺寸 2. **移动端(Android XML布局)**:`LinearLayout`权重分配屏幕区域 3. **桌面应用(Qt/WPF)**:布局嵌套实现复杂界面(如QQ设置面板) > 📌 **本质作用**:将UI描述从绝对坐标的「硬编码」转变为基于规则(比例、相对位置、对齐)的「弹性约束」,是GUI开发的范式革新[^1][^4]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值