QT之布局管理器(十九)
我们在之前的 GUI 开发中都是使用的是绝对定位,何谓绝对定位呢?就是我们直接在像素级指定各个组件的位置和大小。比如我们之前使用的 void QWidget::move(int x, int y);void QWidget::resize(int w, int h);这样存在的问题就是组件的位置和大小无法自适应父窗口的变化。
我们先来看看绝对定位的代码和效果是怎样的?头文件代码如下:
#include <QWidget> #include <QPushButton> class Widget : public QWidget { Q_OBJECT private: QPushButton TestBtn1; QPushButton TestBtn2; QPushButton TestBtn3; QPushButton TestBtn4; void initControl(); public: Widget(QWidget *parent = 0); ~Widget(); };
具体函数代码如下:
void Widget::initControl() { TestBtn1.setText("Test Button 1"); TestBtn1.move(20, 20); TestBtn1.resize(160, 30); TestBtn2.setText("Test Button 2"); TestBtn2.move(20, 70); TestBtn2.resize(160, 30); TestBtn3.setText("Test Button 3"); TestBtn3.move(20, 120); TestBtn3.resize(160, 30); TestBtn4.setText("Test Button 4"); TestBtn4.move(20, 170); TestBtn4.resize(160, 30); }
图一为构建运行后得到的原始界面,图二为我们放大后的效果图:
图一 图二
那么有什么解决方法吗?答案就是布局管理器,它能够提供相关的类对界面组件进行布局管理。能够自动排列窗口中的界面组件,窗口变化后自动更新界面组件的大小。
QLayout 是 Qt 中布局管理器的抽象基类,通过继承 QLayout 实现了功能各异且互补的布局管理器、Qt 中可以根据需要自定义布局管理器。注意:布局管理器不是界面部件,而是界面部件的定位策略!!!
关系如下所示:
QBoxLayout 布局管理器: 以水平或者垂直的方式管理界面组件,如下:
我们下面来进行一组实验,我们先来以垂直的方式进行排布,代码如下:
void Widget::testVBoxLayout() { QVBoxLayout* layout = 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); 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(20); // 设置间距为20个像素 layout->addWidget(&TestBtn1); // 添加 TestBtn1 layout->addWidget(&TestBtn2); layout->addWidget(&TestBtn3); layout->addWidget(&TestBtn4); setLayout(layout); }
图三为构建运行后得到的原始界面,图四为我们放大后的效果图:
图三 图四
我们再试下水平布局,在上面代码中仅仅只是将 QVBoxLayout 改成 QHBoxLayout,继续构建运行后效果如下:
那么我们的布局管理器还可以相互嵌套,形成更加复杂的布局方式。布局嵌套几乎可以完成所有常用的界面布局,我们还可以定义布局类以达到个性化布局的效果。下来我们就做个 QBoxLayout 嵌套示例,如下:
代码如下:
void Widget::testVHBoxLayout() { QHBoxLayout* hLayout1 = new QHBoxLayout(); // 设置水平方向 hLayout1 QHBoxLayout* hLayout2 = new QHBoxLayout(); // 设置水平方向 hLayout2 QVBoxLayout* vLayout = new QVBoxLayout(); // 设置垂直方向 vLayout 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->addWidget(&TestBtn1); // 水平方向添加 TestBtn1 hLayout1->addWidget(&TestBtn2); // 水平方向添加 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->addLayout(hLayout1); // 竖直方向添加 hLayout1 vLayout->addLayout(hLayout2); // 竖直方向添加 hLayout2 setLayout(vLayout); }
构建运行效果如下:
那么本次我们学习了布局管理相关的知识。绝对定位的布局方式是无法适应窗口的变化的,在 Qt 中提供了相关的类对界面组件进行布局管理。Qt 预定义了功能各异的且互补的布局管理器,布局管理器能够相互嵌套形成复杂的布局。在后面我们会接着对 Qt 的布局管理方式进行学习。