How to use QScrollArea to make scrollbars appear

Solution 1:

Since many questions wonder how to use a QScrollArea that many widgets have, I will take the license to explain the various forms in detail and use them as a canonical answer for future readers.

QScrollArea only allows placing a container widget so the other widgets must be placed as children of the container widget.

And to place the widgets as children of another there are 2 possibilities:

1. Use a QLayout:

QLayouts allow you to automate the geometry of the widgets based on the QSizePolicy, strecth, sizeHint, etc. So in that case it's simple: Just set the widgetResizable property to True.

import sys
from PyQt5 import QtWidgets


class Window(QtWidgets.QMainWindow):
    def __init__(self, parent=None):
        super(Window, self).__init__(parent)

        central_widget = QtWidgets.QWidget()
        self.setCentralWidget(central_widget)

        scroll_area = QtWidgets.QScrollArea(central_widget)
        scroll_area.setGeometry(360, 10, 420, 180)
        scroll_area.setWidgetResizable(True)

        container = QtWidgets.QWidget()
        scroll_area.setWidget(container)

        # Set widgets via layout
        lay = QtWidgets.QVBoxLayout(container)
        lay.setContentsMargins(10, 10, 0, 0)
        for letter in "ABCDE":
            text = letter * 100
            label = QtWidgets.QLabel(text)
            lay.addWidget(label)
        lay.addStretch()

        self.setGeometry(300, 300, 803, 520)


if __name__ == "__main__":
    app = QtWidgets.QApplication(sys.argv)
    win = Window()
    win.show()
    sys.exit(app.exec_())

2. Set the widgets directly without layouts:

In this case you must calculate the minimum geometry that contains the internal widgets and set the size in the container, also you must set the widgetResizable property to False:

import sys
from PyQt5 import QtCore, QtWidgets


class Window(QtWidgets.QMainWindow):
    def __init__(self, parent=None):
        super(Window, self).__init__(parent)

        central_widget = QtWidgets.QWidget()
        self.setCentralWidget(central_widget)

        scroll_area = QtWidgets.QScrollArea(central_widget)
        scroll_area.setGeometry(360, 10, 420, 180)
        scroll_area.setWidgetResizable(False)

        container = QtWidgets.QWidget()
        scroll_area.setWidget(container)

        # calculate geometry
        geometry = QtCore.QRect(10, 10, 0, 0)
        for letter in "ABCDE":
            text = letter * 100
            label = QtWidgets.QLabel(text, container)
            label.adjustSize()
            label.move(geometry.bottomLeft())
            geometry |= label.geometry()

        geometry.setTopLeft(QtCore.QPoint(0, 0))
        container.resize(geometry.size())

        self.setGeometry(300, 300, 803, 520)


if __name__ == "__main__":
    app = QtWidgets.QApplication(sys.argv)
    win = Window()
    win.show()
    sys.exit(app.exec_())