Search code examples
pythonpyqtpyqt5qscrollarea

Using QScrollArea collapses children widgets


I am trying to create a dynamic GUI with multiple Groupbox objects in a QVBoxLayout. As there are a lot of them, I will be needing a scroll area to make them available to the end user. So I tried to change to top widget of this tab from a QWidget to a QScrollArea.

Before the change:

Before modification

This is the kind of result I want but with a scroll bar because the window is too high.

After the change to QScrollArea: After the modification

My GroupBoxs are now "collapsed" and there is not scrollbar. I tried setting their size but it is not adequate because they are not fixed. I searched the documentation and tried to use WidgetResizable or I tried to set a fixed height or the sizehint but nothing worked as I wanted.

After creating the the Groupbox, the sizeHint for my QScrollArea is already very low (around 150px of height) so I think I'm missing a parameter.

It would be complicated to provide code as it is intricate. If necessary I could recreate the problem in a simpler way.

How to reproduce:

from PyQt5 import QtWidgets, QtGui, QtCore
from PyQt5.QtWidgets import *
import sys

class Example(QMainWindow):

    def __init__(self):
        super().__init__()

        self.initUI()


    def initUI(self):
        
        v_layout = QVBoxLayout()
        scroll_area = QScrollArea()
        self.layout().addWidget(scroll_area)
        scroll_area.setLayout(v_layout)
        # v_layout.setSizeConstraint(QLayout.SetMinimumSize)

        for i in range(50):
            box = QGroupBox()
            grid = QGridLayout()
            box.setLayout(grid)
            grid.addWidget(QLabel("totototo"), 0, 0)
            grid.addWidget(QLineEdit(), 1, 0)
            grid.addWidget(QPushButton(), 2, 0)
            v_layout.addWidget(box)
        self.show()



app = QApplication(sys.argv)
ex = Example()
sys.exit(app.exec_())

Uncommenting # v_layout.setSizeConstraint(QLayout.SetMinimumSize) allows the content of the group boxes to deploy and fixes the first part of the issue. But there is still not scroll bar.


Solution

  • You have 2 errors:

    • A widget should not be added to the layout of a QMainWindow, but the setCentralWidget method should be used.

    • You should not add the layout to the QScrollArea but use a widget as a container for the other widgets, also if you use layouts then you have to activate the widgetResizable property.

    Considering the above, the solution is:

    def initUI(self):
    
        scroll_area = QScrollArea(widgetResizable=True)
        self.setCentralWidget(scroll_area)
    
        container = QWidget()
        scroll_area.setWidget(container)
    
        v_layout = QVBoxLayout(container)
    
        for i in range(50):
            box = QGroupBox()
            grid = QGridLayout()
            box.setLayout(grid)
            grid.addWidget(QLabel("totototo"), 0, 0)
            grid.addWidget(QLineEdit(), 1, 0)
            grid.addWidget(QPushButton(), 2, 0)
            v_layout.addWidget(box)
    
        self.show()