如何轻松地散布一排Qt小部件,以使它们始终均匀分布?

时间:2018-10-01 19:17:34

标签: c++ qt layout

我有一个Qt窗口,在窗口的底部有一排小部件(主要是按钮和复选框)供用户进行交互。

我希望那行小部件看起来很漂亮(对我来说,“漂亮”定义为“均匀间隔”)-也就是说,无论用户为窗口选择什么宽度,该行中的小部件都应始终具有它们之间以及最左侧和最右侧小部件与窗口边缘之间的距离相等。

即该行应如下所示(其中XXX表示小部件):

 [      XXX  XXX  XXX  XXX  ]
  ^^^^^^                  ^^
  too much space on the left!

这看起来很容易做-即,我可以做这样的事情:

{{1}}

只要所有小部件都可见,该方法就起作用。

问题是有时我想隐藏行中的一些小部件,因为它们与手头的任务无关。

在这种情况下,其余可见的小部件最终以不均匀的间距结束,因为无法隐藏与当前隐藏的按钮关联的“拉伸”项。

例如,如果我要隐藏上面显示的行中的第一个和第二个小部件,那么剩下的小部件最终看起来像这样:

{{2}}

是否有一种简单的方法来获得所需的行为,还是需要深入研究显式处理隐式QSpacerItems?

1 个答案:

答案 0 :(得分:2)

解决方案

由于QBoxLayout不支持更改QLayoutItem的可见性,因此建议您执行以下操作:

  • 使用QLayout::takeAt删除并删除隐藏的小部件左侧的拉伸,如下所示:

    delete hbl->takeAt(ind - 1);
    
  • 使用QBoxLayout::insertStretch在小部件的左侧插入新的拉伸,如下所示:

    hbl->insertStretch(ind);
    

ind是要隐藏/显示的小部件的布局索引。

示例

这是我为您准备的最小示例,目的是演示建议的解决方案:

#include <QMainWindow>
#include <QBoxLayout>
#include <QPushButton>

class MainWindow : public QMainWindow
{
    Q_OBJECT
public:
    explicit MainWindow(QWidget *parent = nullptr) :
        QMainWindow(parent)
    {
        auto *widget = new QWidget(this);
        auto *hbl = new QHBoxLayout(widget);

        auto *btnLeft = new QPushButton(("Button"), widget);
        auto *btnRight = new QPushButton("Hide/Show", widget);

        hbl->addStretch();
        hbl->addWidget(btnLeft);
        hbl->addStretch();
        hbl->addWidget(new QPushButton("Unused", this));
        hbl->addStretch();
        hbl->addWidget(btnRight);
        hbl->addStretch();

        connect(btnRight, &QPushButton::clicked, [hbl, btnLeft](){
            int ind = 0;

            btnLeft->setVisible(!btnLeft->isVisible());

            for (int n = 0; n < hbl->count(); n++) {
                auto *w = hbl->itemAt(n)->widget();

                if (w && w == btnLeft)
                    ind = n;
            }

            if (btnLeft->isVisible())
                hbl->insertStretch(ind);
            else
                delete hbl->takeAt(ind - 1);
        });

        setCentralWidget(widget);
        resize(800, 600);
    }
};