Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

Dynamically adding child widgets inside a central widget with scrollable behavior



  • Hello,

    I need to dynamically add widgets into a QHBoxLayout inside the centralWidget of my QMainWindow. At first, I simply added an "add" button, connected it to a slot and and appended the new widgets into the layout --> no problem, they automatically appeared without the need to update anything.

    The problem now is, that the user should be able to append more widgets then the visible area of the central widget measures. But, the widget itsself does not handle this by adding a scrollbar. Instead, they are "cut" when they exeed the total width of the central widget. So I did a google recherche and I found QScrollArea.
    Question 1: Is QScrollArea the right thing for this purpose? It works so far, but with its grey background and its documentation I get the view that I am abusing this widget with my purpose...

    Well, I added the QScrollArea at first, but nothing happend when adding a layout to it and trying to append widgets. So I did more google recherche and I found that I need to set a "container" widget to the QScrollArea and set the layout to this widget. Well --> it worked, but only when setting the widget to the scroll area after static appending widgets into the layout. If I tried to set the container widget as an empty widget to the QScrollArea and dynamically append widgets later --> nothing happend. So I did google recherche again and I read in the documentation that I need to pass QLayout::SetMinAndMaxSize() to the layout inside the container widget --> now everything works well.
    Question 2: What is the sense of setting this "MinAndMaxSize" to the layout of the container widget? Why is it needed?

    One final thing: the main layout of the central widget of QMainWindow is a horizontal layout containing 2 items: the QScrollArea and the "Add"-button.
    Question 3: Why does QScrollArea, even if empty, take much more space then the PushButton? Shouldn't it be 50:50 percent without setting individual stretch factors?

    Thank you very much for your help.
    Binary


  • Lifetime Qt Champion

    Hi,

    Question 1: QScrollArea is indeed a "container" widget. You usually interact with the one you set on it.

    Question 2: don't know, I never needed to use it when having dynamic content shown through a QScrollArea.

    Question 3: without the code you are using, there's no way to answer.



  • Thanks for your fast reply.

    Again for question 2 & question 3, here is the code I use:

    clsTabLayout::clsTabLayout(QWidget *parent) : QWidget(parent)
    {
        this->layoutMain = new QHBoxLayout;
        this->setLayout(this->layoutMain);
        this->saGroupContainer = new QScrollArea;
        this->layoutMain->addWidget(this->saGroupContainer);
        this->wGroupContainer = new QWidget;
        this->layoutGroupContainer = new QHBoxLayout;
        this->wGroupContainer->setLayout(this->layoutGroupContainer);
    
        for(int i = 0; i < 50; i++) this->layoutGroupContainer->addWidget(new QPushButton);  // works, because the container widget is set to the QScrollBar afterwards --> no chance to dynamically add QPushButtons
        this->saGroupContainer->setWidget(this->wGroupContainer); // <-- magic code line, must appear after adding the widgets OR in comination with setMinAndMaxSize (see code example #2)
    
        this->layoutRight = new QVBoxLayout;
        this->layoutMain->addLayout(this->layoutRight);
        this->pbAppendGroup = new QPushButton("Add group");
        connect(this->pbAppendGroup, SIGNAL(clicked()), this, SLOT(slotPBAppendGroupClicked()));
        this->layoutRight->addWidget(this->pbAppendGroup);
    }
    

    In the example above, I add the widgets (static) and set the widget to the QScrollArea afterwards. After setting the container widget, further tries to add widgets (by the same way as above) won't have any effect.

    clsTabLayout::clsTabLayout(QWidget *parent) : QWidget(parent)
    {
        this->layoutMain = new QHBoxLayout;
        this->setLayout(this->layoutMain);
        this->saGroupContainer = new QScrollArea;
        this->layoutMain->addWidget(this->saGroupContainer);
        this->wGroupContainer = new QWidget;
        this->layoutGroupContainer = new QHBoxLayout;
        this->wGroupContainer->setLayout(this->layoutGroupContainer);
        this->layoutGroupContainer->setSizeConstraint(QLayout::SetMinAndMaxSize); // needed to correct display dynamically added contents (child widgets) of the widget container
        this->saGroupContainer->setWidget(this->wGroupContainer);
        for(int i = 0; i < 50; i++) this->layoutGroupContainer->addWidget(new QPushButton);
        this->layoutRight = new QVBoxLayout;
        this->layoutMain->addLayout(this->layoutRight);
        this->pbAppendGroup = new QPushButton("Add group");
        connect(this->pbAppendGroup, SIGNAL(clicked()), this, SLOT(slotPBAppendGroupClicked()));
        this->layoutRight->addWidget(this->pbAppendGroup);
    }
    

    Instead, using the setSizeConstraint() to the layout, I can add the child widgets whereever I like to, even in other member methods afterwards. The documentation also recommends to do so.
    You say, you can add widgets dynamically without using this? Can you tell me how you do that? I'd also like to know why the QScrollArea does not adjust its size to the contents of its widget as mentioned in question #3. Do I have to reimplement QScrollArea and catch resize-events of its widget?


  • Lifetime Qt Champion

    I did not do anything special. Just append the new widget to the layout used in the container widget.

    I can't comment for your code as it's not complete and thus I can't test it to see what might be going on.

    QScrollArea does not adjust its size to its content, it provides a mean to scroll its content if this one is bigger than the scroll area itself.


Log in to reply