一晃快有半个月没有写博客了,但是其实每天还是或多或少的敲了些代码。最近主要是了解QT语言,然后再结合前阵所学的openCV的知识,包括高斯滤波啊,直线、圆的检测啊等等,做出可视化界面来,更加方便学习,也更加熟悉软件开发的流程。
QT基础之布局管理器
其实开始使用QT,发现它和Java编写界面的方式有一定程度上是很相似的,就比如说布局!首先我们探讨下为什么我们要使用布局?其实除了使用布局,还可以使用绝对位置来定位窗体上的各个控件,比如说,我要把一个QPushButton放在窗体的(100,100)这个位置,我们完全可以用
btn->setGeometry(100, 100, 10, 10);
或者
btn->move(100, 100);
但是,如果这个界面是可以随用户放缩的,那么问题就来了。这个组件永远在这个位置,而不是自适应窗体大小的变化,这样就会出现窗口“畸形”,控件大范围集中在一个地方。当然机智的你会说,那就不让窗体自由变大变小呗。。。哈哈,good idea,but 客户假设就有这种需求呢?------布局管理器来解决这一切!
布局管理器分类:
1. 水平布局
2. 垂直布局
3. 网格布局
(1)水平布局:言下之意就是将空间延水平方向摆开,比如说:
我们可以使用layout::addwidget(控件对象)来添加我们需要的控件;
(2)垂直布局:和水平布局类似,如下图:
同样的,我们可以用layout::addwidget(控件对象)来添加我们所需要的控件对象。
(3)网格布局:上述所说的水平布局、垂直布局相对来说比较单调,所以,在实际情况下,往往是应用网格布局或者网格布局配合水平垂直布局使用,可见网格布局相对来说更加灵活。如下图所示:
上述是一个3*3的网格,网格中可以是控件也可以是一个布局管理器!所以说网格布局非常使用也非常灵活!如果要加入控件,我们不但需要指出控件对象,而且要将布局位置设置清楚,这里布局位置行列均从0开始:
layout::addWidget(控件对象,行,列);
如果加入的是一个布局管理器,那么我们需要指定布局管理器对象和网格行列位置:
layout::addLayout(布局管理器对象,行列);
但是我们考虑到这样一个情况,某个控件很大,若按照正规网格来说,一个位置可能放不下,可能需要两个位置或者多个位置(即占用n行n列),如:
这时,控件5从第1行(从0开始)第1列算起,占用1行2列,于是该控件嵌入布局管理器中需要指定行列跨度:
layout::addWidget(控件对象, 1, 1, 1, 2);
这样网格布局就将更加方便灵活。
注:布局管理器添加问题:根据QMainWindow、QDialog、QWidget三种不同的窗体,添加布局管理器的方法是不同的。实际上就QMainWindow和QDialog、QWidget区别,那么首先我们要简单了解下这三种窗体的区别:
简单来说,QWidget是基类,QMainWindow和QDialog都是继承QWidget来的,既然QWidget是基类,那么意味着这个窗体是最基本的,类似于一张白纸。在这个最基础的窗体上接受鼠标事件、键盘事件等很多基础事件,同时可以在窗体上绘图。
QMainWindow顾名思义,这是一个主界面,主界面上往往有菜单栏、工具栏等,那么QMainWindow可以很好的提供。
QDialog是一个顶级窗体,也是对话框体的基类,既然是对话框,完成的就是一些简单的短期任务或者与用户进行沟通的功能,分为模态对话框和非模态对话框,这里后面会细说。
然而,QMainWindow还有一些不一样的地方,因为是主界面窗体,很多东西为了方便已经提供好了,实际上这个窗体已经含有了自己的布局管理器,要是直接加布局是不会成功的。如:
this->setLayout(layout);
对于QMainWindow是行不通的,我们需要在主窗体上的centralWidget层添加这个布局。代码如下:
QGroupBox* gb = new QGroupBox(this);
gb->setLayout(gl);//gl是定义的Layout对象
this->setCentralWidget(gb);
这样的布局设定才是成功的!!!!!!!!!
实战演练:
现在我想做如下窗体:
为了做相似性分析,我需要1、2分别显示原图片,3、4分别显示对应的直方图。右下角对应三个按钮分别是打开第一张图、打开第二张图、计算相似性。有了布局管理器的概念,我们将界面做如下分析:
整体使用网格布局,三个按钮处再使用垂直布局嵌入到网格布局中,这样就完美了!
代码实现如下:
//布局(总的是grid布局、加上垂直布局)
QGridLayout* gl = new QGridLayout(this);
gl->addWidget(imgLab1, 0, 0);
gl->addWidget(imgLab2, 0, 1);
gl->addWidget(imgLab3, 1, 0);
gl->addWidget(imgLab4, 1, 1);
QVBoxLayout* vl = new QVBoxLayout(this);
vl->addWidget(btn1);
vl->addWidget(btn2);
vl->addWidget(btn);
gl->addLayout(vl, 1, 2);
//两行1:1
gl->setRowStretch(0, 1);
gl->setRowStretch(1, 1);
QGroupBox* gb = new QGroupBox(this);
gb->setLayout(gl);
this->setCentralWidget(gb);
关于网格布局中的一些简单的设置:
1.行列按比例网格布局:网格布局每个网格的大小是不确定的,各个网格之间不是规范对称的,而是有大有小的,那么我们若需要网格布局的行列按比例生成,那么我们就要用到如下语句:
如第一行和第二行比例1:1 :
gl->setRowStretch(0, 1);
gl->setRowStretch(1, 1);
如第一列和第二列比例1:1 :
gl->setColumnStretch(0, 1);
gl->setColumnStretch(1, 1);
2.控件大小的调整:网格布局往往会适应其中控件的大小,而控件在网格中的填充方式也有几种(盗用API):
Constant | Value | Description |
---|---|---|
QSizePolicy::Fixed | 0 | The QWidget::sizeHint() is the only acceptable alternative, so the widget can never grow or shrink (e.g. the vertical direction of a push button). |
QSizePolicy::Minimum | GrowFlag | The sizeHint() is minimal, and sufficient. The widget can be expanded, but there is no advantage to it being larger (e.g. the horizontal direction of a push button). It cannot be smaller than the size provided by sizeHint(). |
QSizePolicy::Maximum | ShrinkFlag | The sizeHint() is a maximum. The widget can be shrunk any amount without detriment if other widgets need the space (e.g. a separator line). It cannot be larger than the size provided by sizeHint(). |
QSizePolicy::Preferred | GrowFlag | ShrinkFlag | The sizeHint() is best, but the widget can be shrunk and still be useful. The widget can be expanded, but there is no advantage to it being larger than sizeHint() (the defaultQWidget policy). |
QSizePolicy::Expanding | GrowFlag | ShrinkFlag | ExpandFlag | The sizeHint() is a sensible size, but the widget can be shrunk and still be useful. The widget can make use of extra space, so it should get as much space as possible (e.g. the horizontal direction of a horizontal slider). |
QSizePolicy::MinimumExpanding | GrowFlag | ExpandFlag | The sizeHint() is minimal, and sufficient. The widget can make use of extra space, so it should get as much space as possible (e.g. the horizontal direction of a horizontal slider). |
QSizePolicy::Ignored | ShrinkFlag | GrowFlag | IgnoreFlag | The sizeHint() is ignored. The widget will get as much space as possible. |
上面说了很多种,这里仅介绍其中几种,其他参照上述英文解释:
Preferred:最佳尺寸,控件将与控件上的字符长度匹配,不会太长或者太宽
Fixed:填充尺寸,控件将几乎充满整个网格。