pythonpython-3.xlayoutpyqtqscrollarea

PyQt: How to make widget scrollable


I am trying to make my QGroupBox scrollable once it grows higher than 400px. The contents in the QGroupBox are generated using a for-loop. Here is an example of how it is done:

mygroupbox = QtGui.QGroupBox('this is my groupbox')
myform = QtGui.QFormLayout()
labellist = []
combolist = []
for i in range(val):
    labellist.append(QtGui.QLabel('mylabel'))
    combolist.append(QtGui.QComboBox())
    myform.addRow(labellist[i],combolist[i])
mygroupbox.setLayout(myform)

Since the value of val depends on some other factors, the myform layout size could not be determined. In order to solve this, I added a QScrollableArea like this:

scroll = QtGui.QScrollableArea()
scroll.setWidget(mygroupbox)
scroll.setWidgetResizable(True)
scroll.setFixedHeight(400)

Unfortunately, that doesn't seem to have any effect on the groupbox: there's no sign of a scrollbar. Am I missing something?


Solution

  • Other than the obvious typo (I'm sure you meant QScrollArea), I can't see anything wrong with what you've posted. So the problem must lie elsewhere in your code: a missing layout maybe?

    Generally speaking, problems with scroll-areas are most often caused by failing to call setWidgetResizable(True) and/or failing to ensure all the relevant widgets are properly managed by layouts. Also, when dynamically adding widgets to a scroll-area it's usually desirable to add a stretchable spacer to the end of a vertical/horizontal layout so that the widgets retain their positions during resizing. (This implies dynamically created widgets should be inserted after the terminating spacer, like this: layout.insertWidget(layout.count() - 1, widget)).

    Just to make sure we're on the same page, a minimal script based on the example code in the question works as expected for me:

    screenshot

    PyQt5/PyQt6

    from PyQt5 import QtWidgets
    # from PyQt6 import QtWidgets
    
    class Window(QtWidgets.QWidget):
        def __init__(self, val):
            super().__init__()
            mygroupbox = QtWidgets.QGroupBox('this is my groupbox')
            myform = QtWidgets.QFormLayout()
            labellist = []
            combolist = []
            for i in range(val):
                labellist.append(QtWidgets.QLabel('mylabel'))
                combolist.append(QtWidgets.QComboBox())
                myform.addRow(labellist[i],combolist[i])
            mygroupbox.setLayout(myform)
            scroll = QtWidgets.QScrollArea()
            scroll.setWidget(mygroupbox)
            scroll.setWidgetResizable(True)
            scroll.setFixedHeight(200)
            layout = QtWidgets.QVBoxLayout(self)
            layout.addWidget(scroll)
    
    if __name__ == '__main__':
    
        app = QtWidgets.QApplication(['Test'])
        window = Window(12)
        window.setGeometry(500, 300, 300, 200)
        window.show()
        app.exec_()
    

    PyQt4

    from PyQt4 import QtGui
    
    class Window(QtGui.QWidget):
        def __init__(self, val):
            QtGui.QWidget.__init__(self)
            mygroupbox = QtGui.QGroupBox('this is my groupbox')
            myform = QtGui.QFormLayout()
            labellist = []
            combolist = []
            for i in range(val):
                labellist.append(QtGui.QLabel('mylabel'))
                combolist.append(QtGui.QComboBox())
                myform.addRow(labellist[i],combolist[i])
            mygroupbox.setLayout(myform)
            scroll = QtGui.QScrollArea()
            scroll.setWidget(mygroupbox)
            scroll.setWidgetResizable(True)
            scroll.setFixedHeight(200)
            layout = QtGui.QVBoxLayout(self)
            layout.addWidget(scroll)
    
    if __name__ == '__main__':
    
        app = QtGui.QApplication(['Test'])
        window = Window(12)
        window.setGeometry(500, 300, 300, 200)
        window.show()
        app.exec()