Jumpy UI in a scroll area


  • Moderators

    Hi,
    I've got a series of custom widgets in a QScrollArea. These widgets have collapsible sections implemented with a QCheckBox and a content QWidget whose setVisible slot is connected to the toggled signal of the checkbox. Simple enought.

    Now the problem is that when I toggle the visibility of some section there's a 2 frame long UI "jump". It might not seem much but the kind of people that will use the app notice these things and complain.

    It seems that the widgets above the shown section get compressed for a moment to accomodate the newly shown widget and then the entire scroll area content gets resized to better fit the contents. At least that's what I suspect.

    The content is quite dynamic (different custom widgets) so I don't want to impose restrictions on it like fixed height. I actually tried setting fixed height to the line edits to test if it helps but the problem persists, seemingly ignoring the fixed value for the problematic frames.

    Here's a frame by frame picture of what happens and a mockup code I used to test it.
    Any ideas for a solution would be appreciated.

    Jumpy UI

    #include <QApplication>
    #include <QScrollArea>
    #include <QVBoxLayout>
    #include <QFormLayout>
    #include <QPushButton>
    #include <QCheckBox>
    #include <QLineEdit>
    #include <QToolButton>
    
    class CustomItemWidget : public QWidget {
    public:
        CustomItemWidget(QWidget* parent = nullptr) : QWidget(parent) {
            auto layout = new QHBoxLayout();
            setLayout(layout);
            layout->setContentsMargins(0,0,0,0);
            layout->addWidget(new QLineEdit("Some more text"));
            layout->addWidget(new QToolButton());
            layout->addWidget(new QToolButton());
        }
    };
    
    class CustomWidget : public QWidget
    {
    public:
        CustomWidget(QWidget* parent = nullptr) : QWidget(parent) {
            auto layout = new QVBoxLayout();
            layout->setContentsMargins(0,0,0,0);
            setLayout(layout);
    
            auto content = new QWidget();
            auto contentLayout = new QFormLayout();
            content->setLayout(contentLayout);
    
            for(int i=0; i< 5; ++i)
                contentLayout->addRow("Some label", new QLineEdit("Some text to edit"));
    
            auto cb = new QCheckBox("Stuff");
            cb->setChecked(true);
            connect(cb, &QCheckBox::toggled, content, &QWidget::setVisible);
    
            layout->addWidget(cb);
            layout->addWidget(content);
    
            auto cb2 = new QCheckBox("Advanced stuff");
            cb2->setChecked(true);
            contentLayout->addWidget(cb2);
    
            auto content2 = new QWidget();
            auto contentLayout2 = new QFormLayout();
            content2->setLayout(contentLayout2);
            contentLayout->addWidget(content2);
            connect(cb2, &QCheckBox::toggled, content2, &QWidget::setVisible);
    
            for(int i=0; i< 5; ++i)
                contentLayout2->addRow("Some label", new CustomItemWidget());
        }
    };
    
    int main(int argc, char *argv[])
    {
        QApplication a(argc, argv);
    
        QScrollArea scrollArea;
        scrollArea.setWidgetResizable(true);
    
        auto content = new QWidget();
        scrollArea.setWidget(content);
    
        auto contentLayout = new QVBoxLayout();
        content->setLayout(contentLayout);
    
        for(int i = 0; i < 10; ++i)
            contentLayout->addWidget(new CustomWidget());
    
        scrollArea.showMaximized();
    
        return a.exec();
    }
    

Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.