Qt 像其他编辑器一样,在添加控件时,也可以自定义控件的坐标,让每个控件处于你希望的位置,但是这样相对麻烦,而 Qt 提供了一系列布局功能,本文介绍的就是水平布局 QHBoxLayout,他可以将一系列控件加入其布局中,然后将整个布局应用到窗口中。详见代码:

【代码实现】

注意:我们使用的都是自己继承的 QWidget 类来创建一个窗口,如果不清楚这个窗口是如何创建的,请参考“使用 Qt 构建一个简单的窗体程序”。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#ifndef CWIDGETS_H
#define CWIDGETS_H

#include <QWidget>
#include <QHBoxLayout>
#include <QPushButton>

class CWidgets : public QWidget
{
Q_OBJECT
public:
explicit CWidgets(QWidget *parent = 0);

// 水平布局框架
QHBoxLayout* _layout;

// 按钮
QPushButton* _button1;
QPushButton* _button2;
QPushButton* _button3;

signals:

public slots:
};

#endif // CWIDGETS_H
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include "cwidgets.h"

CWidgets::CWidgets(QWidget *parent) : QWidget(parent)
{
// 将成员变量 _layout new 出来
_layout = new QHBoxLayout;

// 将三个按钮也 new 出来并命名
_button1 = new QPushButton("button1");
_button2 = new QPushButton("button2");
_button3 = new QPushButton("button3");

// 将三个按钮添加到 _layout 布局中
_layout->addWidget(_button1);
_layout->addWidget(_button2);
_layout->addWidget(_button3);

// 调用 CWidget 成员函数 setLayout 将我们新建的布局应用到窗体中
setLayout(_layout);
}
1
2
3
4
5
6
7
8
9
10
11
12
#include <QApplication>
#include "cwidgets.h"

int main(int argc, char* argv[])
{
QApplication app(argc, argv);

CWidgets w;
w.show();

return app.exec();
}

通过以上代码,我们的窗口创建完成后就是下图的状态了: 2015-06-17_102543 当你拉伸窗口时,按钮也回跟随窗口变化,如下图: 2015-06-17_102742 如果你不希望拉伸窗口时控件跟随着变长,那么你可以调用 addStretch() 函数,增加一个“弹簧”,如下代码所示:

1
2
// 在布局中添加一个弹簧,让控件不会跟随窗口变大而变大
_layout->addStretch(1);

添加 addStretch 后,再拉伸窗体,按钮就不会跟着窗体拉长了: 2015-06-17_104140 那这个 addStretch() 函数到底是做什么用的?他是如何起到这样的作用的? 其实我们每个添加的控件都是可以设定在窗口中的比例的,如果你不指定窗口比例,那么就以控件默认的大小来显示,这个 addStretch() 函数相当于在水平布局中,增加了一个比例为 1 的控件,只不过这个控件是什么都不显示的,其他控件因为没有指定比例,所以保持原有大小不变,而一拉伸窗口,用 addStretch() 添加的“控件”就会跟随窗口变大而变大,给我们的错觉就是像一个弹簧一样,把三个没有指定大小的控件一直挤在左侧。 如果我们设定了控件的比例会怎么样呢?如下代码:

1
2
3
4
5
6
7
// 将三个按钮添加到 _layout 布局中
_layout->addWidget(_button1, 1); // 占整个窗口的 1/n
_layout->addWidget(_button2, 2); // 占整个窗口的 2/n
_layout->addWidget(_button3, 3); // 占整个窗口的 3/n

// 在布局中添加一个弹簧,让控件不会跟随窗口变大而变大
_layout->addStretch(1); // 占整个窗口的 1/n

我们在 addwidget() 函数中增加了第二个参数,设定了控件的比例,如注释所写,按钮 1 占用了 1/n 的比例,按钮 2 占用了 2/n 的比例,按钮 3 占用了 3/n 的比例,最后一个插入的“弹簧”占用了 1/n 的比例,此时相当于在一个水平布局中 n = 7,那按钮 1 就是占用 1/7 的比例,按钮 2 占用了 2/7 的比例,依次类推,效果就是下图这样了: 2015-06-17_105424

【在其他控件中间插入控件】

以上是比例相关的解释,下面我们来看一下如何在这些按钮中插入一个按钮。比如我希望将一个按钮 button4 插入到 button1 和 button2 中间,那么你可以通过 insertWidget() 函数来实现:

1
2
// 在控件 0 后面插入一个控件,这个控件被插入后就是在位置 1
_layout->insertWidget(1, new QPushButton("button4"));

2015-06-17_110058

【在控件之间增加一个间隔】

如果你希望两个控件之间能有一部分间隔,你可以通过 addSpacing() 函数来实现:

1
2
// button1 后面增加一个间隔,长度为50
_layout->addSpacing(50);

2015-06-17_110322

【设置 QHBoxLayout 的边距】

上面所有图中我们都可以看出,窗口和控件之间是有一点点距离的,这个距离我们也可以自己来控制,那就是调用 setMargin() 函数来实现:

1
2
// 设置 QHBoxLayout 边距为 0
_layout->setMargin(0);

2015-06-17_110610

【设置全局控件之间的距离】

如果你希望将所有控件之间的距离都控制在一个长度,那么你可以通过 setSpacing() 函数来实现,它不同与 addSpcing() 函数,setSpacing() 函数是设置所有控件之间的间距:

1
2
// 设置所有控件之间的间距为 0
_layout->setSpacing(0);

2015-06-17_110743 与上图相比,可以看出控件之间的间距没有了。

【总结】

最后我们来将所有功能重新梳理一下成为如下代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include "cwidgets.h"

CWidgets::CWidgets(QWidget *parent) : QWidget(parent)
{
// 将成员变量 _layout new 出来并设置父窗口,无需后面再调用setLayout()函数
_layout = new QHBoxLayout(this);
// 设置 QHBoxLayout 边距为 0
_layout->setMargin(0);
// 设置所有控件之间的间距为 0
_layout->setSpacing(0);

// 添加控件的同时直接在参数中将控件 new 出来,这样代码可以更简洁
_layout->addWidget(_button1 = new QPushButton("button1"), 1);
// 添加间距
_layout->addSpacing(50);
_layout->addWidget(_button2 = new QPushButton("button2"), 2);
_layout->addWidget(_button3 = new QPushButton("button3"), 3);

// 在布局中添加一个弹簧,让控件不会跟随窗口变大而变大
_layout->addStretch(1); // 占整个窗口的 1/n

// 在控件 0 后面插入一个控件,这个控件被插入后就是在位置 1
_layout->insertWidget(1, new QPushButton("button4"));
}