Qt 布局管理器
在一个颜值当道的今天,无论买衣服,买车还是追星,颜值的高低已经变成了大家最看重的(不管男性女性都一样,千万别和我说你不是);而对于程序猿来说,开发一款软件,不再只注重逻辑和稳定性,美观和用户友好性也是我们不得不关注的一个重点了。
我们进入正题,今天主要和大家分享一下Qt方面关于布局管理器的使用;
一、基本概念
Qt 提供了几种在窗口部件上管理子窗口部件的基本方式。一共有3 种方法用于管理窗体上子窗口部件的布局:绝对位置法、人工布局法和布局管理器法。相比于使用固定尺寸和位置,布局提供了功能强大且极具灵活性的另一种方案。使用布局后,编程人员无需计算尺寸和位置,布局可以自动进行调整,符合用户屏幕、语言以及字体的要求。
1.绝对位置法
这种方法是最原始的拖放窗口部件的方法。它对窗体的各个子窗口部件分配固定的大小和位置,是通过调用基类QWidget 提供的setGeometry()函数来实现的。
所以绝对位置法有很多缺点:
1> 用户无法改变窗口的大小,当父窗口改变时,子窗口不能做出相应的调整。
2>如果用户选择的字体太大或者翻译成多国语言,特别是俄语,很多都会显示不全被截断。
3> 对于不同风格的平台,这些窗口部件可能会具有并不合适的尺寸大小。
4>必须人工计算这些位置和大小。这样做不仅非常枯燥而且极易出错,并且还会让后
期的维护工作变得痛苦万分。
很显然,使用这种方式管理GUI 应用程序大大降低了程序员的开发效率,降低了应用
程序的质量和适应性。
2.人工布局法
这种方法的核心是通过重载QWidget::resizeEvent(QResizeEvent*)函数来使得子窗口
的的大小尺寸总是和父窗口的大小成比例,也就在一定程度上减轻了计算量,但是在其中也
要通过setGeometry()函数来设置子窗口部件的位置和大小。在程序的规模比较小,并且不需要时常变更设计的情况下,绝对位置法勉强可以胜任。但是它就像前面的绝对位置法一样,仍然需要计算许多手写代码中的常量,尤其是当设计被改变的时候,这种情况更加突出,而且它并没有消除文本会被截断的危险。辅以社会自子窗口部件的大小提示,应该可以规避这种风险,但是这样会使代码变得尤为复杂。
3.布局管理器法
这种方式是使用Qt 设计用户界面、组织管理Qt 窗口部件的最好方法。布局管理器为
窗口部件提供了能变化的默认值(sensible default sizes),可以随着窗口部件大小的变化,对子窗口部件的大小和位置做出适当的调整。
二、详细使用说明
QLayout 类是Qt 的几何管理器的基类,它派生自QObject 类和QLayoutItem 类,是一
个抽象基类,必须被派生类所重新实现。它的派生类主要有QBoxLayout, QGridLayout, QFormLayout 以及QStackedLayout。而QBoxLayout
又有两个主要的Qt4 子类,QHBoxLayout 和QVBoxLayout
1、水平布局管理器:QHBoxLayout,按水平方向组织管理控件;
2、垂直布局管理器:QVBoxLayout,按垂直方向组织管理控件;
3、网格布局管理器:QGridLayout,按照二维网格组织管理控件;
4、表单布局管理器:QFormLayout,表单布局管理器主要用作管理界面上的输入窗口部件( input widgets)以及和它们相连的标签窗口部件(labels)。
5、栈布局管理器:QStackeLayout,类似于栈的方式管理控件,不过Qt设计器不知什么原因没有提供它的布局管理器(我认为开发人员觉得前几种已经能满足几乎所有的布局需要,栈布局使用太过复杂,不如用一个控件代替),提供了一个栈控件(QStackedWidget);在实际应用中使用前三种混合基本都能满足设计需求。
我们来看,第一种水平布局:
效果如图:1.1
[attachment=15390]
1.1
第二种垂直布局:
效果如下图1.2
[attachment=15391]
1.2
第三种 网格布局:
效果如下图 1.3
[attachment=15392]
1.3
第四种 表单布局
效果如下图 1.4
[attachment=15393]
1.4
第五种是栈布局,我的4.7.0 版本,Qt Designer 的窗口部件盒没有可视化的提供对栈布局管理器的支持,只提供了一个栈部件QStackedWidget,作用与栈布局管理器类似。因此,在使用Qt Designer 绘制GUI界面时,完全可以使用QStackedWidget 来代替QStackedLayout。在此不做赘述。
2.1下面来讲讲案例:
当然是用设计器拖出来最简单方便,我们后面再用代码写;
1.用设计器 添加五个控件;
2.选中是个button点击右键选择布局,我们选择栅格布局(你可以看情况自己选择合适的);
[attachment=15395]
2.1
3.将刚才布局的控件和文本框一起选中,点击右键再选择你需要的布局方式(我们选择水平);
[attachment=15395]
2.2
4.效果图如下:
2.3
这里我们就要注意调整空白和控件之间间距的问题;
2.4
1.空白(margin)和间距(spacing)
每种布局都有两个重要的属性,空白和间距。空白指的是整个布局四周距离窗体边缘
的距离;间距指的是布局管理器内部各个窗口部件之间的距离。空白属性即margin(),间距属性即spacing(),它们的默认值是有窗体的风格决定的。Qt 的默认风格下,子窗体部件的margin()的值是9 英寸。spacing()的值与margin()相同。如果要设置这两个值可以通过setMargin()和setSpacing()。注意,从Qt4.3 开始,margin()属性已经逐渐不再被Qt4 所推荐,更好的设置空白的方法是使用setContentsMargins()方法,
它的原型如下:
void QLayout::setContentsMargins ( int left, int top, int right, int bottom )
其中,left, top, right, 和bottom 表示环绕在布局周围的空白。对于QGridLayout 和QFormLayout,不要使用setSpacing()方法,而是要分别使用setHorizontalSpacing()和setVerticalSpacing()方法来设置水平和垂直方向
2.大小约束(size constraint)
影响布局方式的另一种方法是设置它的子窗口部件的最大大小、最小大小或固定大小。这些是通过设置sizeConstraint 属性来完成的。该属性值是一个枚举常量,定义了布局的大小约束的模式。表列出了它所有可能的取值,它的默认值是QLayout::SetDefaultConstraint。获取和设置该属性值可以通过QWidget::layout()来获取主窗口部件的布局管理器,然后可以调用QLayout::sizeConstraint()函数来查看当前的设置情况,然后再通过QLayout::setSizeConstraint()函数来设置该布局管理器的sizeConstraint 属性。这两种函数的原型如下:SizeConstraint sizeConstraint () const
void setSizeConstraint ( SizeConstraint )其中,SizeConstraint 的取值可以在QLayout类的枚举中得到;
QLayout::SetDefaultConstraint 0 主窗口部件的最小尺寸设置为minimumSize(),除非该窗口部件已经有一个最小尺寸
QLayout::SetFixedSize 3 主窗口部件的尺寸设置为sizeHint(),并且不允许改变该窗口部件的尺寸
QLayout::SetMinimumSize 2 主窗口部件的最小尺寸设置为minimumSize(),并且该窗口部件不能够变得更小
QLayout::SetMaximumSize 4 主窗口部件的最大尺寸设置为maximumSize(),并且该窗口部件不能够变得更大
QLayout::SetMinAndMaxSize 5 主窗口部件的最小尺寸设置为minimumSize(),最大尺寸设置为
3.大小策略(size policy)
一个窗口部件的大小策略会告诉布局系统应该如何对它进行拉伸或收缩。Qt 为它所有
的内置窗口部件都提供了合理的默认大小策略值,但是由于不可能为每一种可能产生的布局
都提供唯一的默认值,所以在一个窗体中,开发人员改变它上面的一个或两个窗口部件的大
小策略是非常普遍的现象。一个QSizePolicy 既包含一个水平分量也包含一个垂直分量。
可以通过QSizePolicy 找到对应的枚举值;
4.伸缩因子(stretch factor)
除了大小策略中包含的水平方向和垂直方向两个分量之外, QSizePolicy 类还保存了水平方向和垂直方向的一个伸缩因子。这些伸缩因子可以用来说明在增大窗体时,对不同的子窗口部件应使用的不同放大比例。即需要设置QSizePolicy::horizontalStretch 和
QSizePolicy::verticalStretch 的值来实现。默认情况下,被布局管理器组合在一起的窗
口部件的伸缩因子是相等的,都为0。
2.2 移除布局
选择想要移除的布局,点击右键或者如下图在设计器工具栏上有个“打破布局”
如图:
[attachment=15398]
2.5
2.3 一些快捷键
常见的布局操作所对应的快捷键。
水平布局Ctrl+1 将选中的界面元素置于一个水平布局中;
垂直布局Ctrl+2 将选中的界面元素置于一个垂直布局中;
栅格布局Ctrl+5 将选中的界面元素置于一个栅格布局中;
表单布局Ctrl+6 将选中的界面元素置于一个表单布局中;
分裂器水平布局Ctrl+3 创建一个分裂器水平布局,并将选中的界面元素置于其中;
分裂器垂直布局Ctrl+4 创建一个分裂器垂直布局,并将选中的界面元素置于其中;
调整大小Ctrl+J 调整布局的大小,以使得位于其中的元素能够恰当的显示自身内容。关于这方面的内容,可以参见QWidget::adjustSize()函数;
破除布局Ctrl+0 破除选中的布局;
2.4 手写代码
QWidget *pWidget = new QWidget;
pWidget->setWindowTitle("Calculator");
pWidget->show();
QLineEdit *pText = new QLineEdit(pWidget);
pText->setMinimumSize(150,100);
QPushButton *pBtnAdd = new QPushButton("+",pWidget);
QPushButton *pBtnSub = new QPushButton("-",pWidget);
QPushButton *pBtnMul= new QPushButton("*",pWidget);
QPushButton *pBtnDiv= new QPushButton("/",pWidget);
QVBoxLayout *pVBox = new QVBoxLayout(pWidget);
QGridLayout *pGBox = new QGridLayout();
pVBox->addWidget(pBtnAdd);
pVBox->addWidget(pBtnSub);
pVBox->addWidget(pBtnMul);
pVBox->addWidget(pBtnDiv);
pVBox->setSpacing(10);
pWidget->setLayout(pVBox);
pGBox->addWidget(pBtnAdd,0,0);
pGBox->addWidget(pBtnSub,0,1);
pGBox->addWidget(pBtnMul,1,0);
pGBox->addWidget(pBtnDiv,1,1);
pVBox->addWidget(pText);
pVBox->addLayout(pGBox);
pVBox->setMargin(12);
pWidget->setLayout(pVBox);
效果如下图2.6:
2.6
2.5 总结
当界面元素较为复杂时,应该毫不犹豫的尽量使用网格布局,而不是使用水平和垂直布局的组合或者嵌套的形式,因为在多数情况下,后者往往会使“局势”更加复杂而难以控制。网格布局赋予了界面设计器更大的自由度来排列组合界面元素,而仅仅带来了微小的复杂度开销。当要设计的界面是一种类似于两列和若干行组成的形式时,使用表单布局要比网格布局更为方便些。
上面分享了自己关于布局的基础使用方式的理解,若有不对之处敬请指正