Search code examples
c++qtqscrollareaqlayout

Weird resizing behaviour of QScrollArea with QHBoxLayout inside


How to reproduce: Create a new Qt Widgets Application and replace its mainwindow.cpp with the following:

#include "mainwindow.h"
#include "ui_mainwindow.h"

#include <QHBoxLayout>
#include <QScrollArea>
#include <QToolButton>

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    QScrollArea *scrollArea = new QScrollArea;
    setCentralWidget(scrollArea);

    QFrame *scrollWidget = new QFrame;
    scrollArea->setWidget(scrollWidget);
    scrollArea->setWidgetResizable(true);

    QHBoxLayout *scrollLayout = new QHBoxLayout;
    scrollWidget->setLayout(scrollLayout);

    for(int i = 0; i < 10; ++i)
    {
        QToolButton *button = new QToolButton;
        button->setText(QString(20, QChar('a' + i)));
        scrollLayout->addWidget(button);
    }
}

MainWindow::~MainWindow()
{
    delete ui;
}

After you build the project, the resulting app's window will refuse to be vertically shrunk below this:

My question: How do I get rid of the empty space above and below the buttons? I tried manipulating size hints, size policies, and everything else remotely relevant, to no satisfactory result. The only way to affect it seems to be to hardcode the QScrollArea widget minimum height, which is hardly useful in practice.


Solution

  • Layouts use the minimumSizeHint() of the widgets as the minimum size, in the case of QScrollArea this is QSize(70, 70).

    This is the cause of the problem you see, in the case of the buttons minimumSizeHint() is QSize(24, 23).

    And as you say in your post a way to correct the above is to set the minimum size, for example I recommend using 48 as it is the minimum size of the button plus the QScrollBar:

    QScrollArea *scrollArea = new QScrollArea;
    setCentralWidget(scrollArea);
    scrollArea->setMinimumHeight(48);
    QFrame *scrollWidget = new QFrame;
    scrollWidget->setStyleSheet("background-color: rgb(0, 85, 0);");
    scrollWidget->setContentsMargins(0, 0, 0, 0);
    scrollArea->setWidget(scrollWidget);
    scrollArea->setWidgetResizable(true);
    QHBoxLayout *scrollLayout = new QHBoxLayout;
    scrollWidget->setLayout(scrollLayout);
    scrollLayout->setContentsMargins(0, 0, 0, 0);
    
    for(int i = 0; i < 10; ++i)
    {
        QToolButton *button = new QToolButton;
        button->setText(QString(20, QChar('a' + i)));
        scrollLayout->addWidget(button);
    }
    

    Note: In addition to setting the minimum size I recommend placing the layout margins to 0.

    Screenshot:

    enter image description here