0

I have a QScrollArea with a QHBoxLayout and when I add a lot of widgets to the layout, they get condensed into a small size instead of adding a scroll bar as I intended, as the image below shows:

enter image description here

Here's the code I'm using:

from PyQt5.QtWidgets import QGroupBox, QHBoxLayout, QLabel, QVBoxLayout, QScrollArea


class LayerParamsBox(QGroupBox):
    def __init__(self):
        super().__init__()

        self.setTitle("Layer Parameters")
        self.setLayout(QHBoxLayout())
        self.scroll_area = QScrollArea()
        self.scroll_area.verticalScrollBar().setEnabled(False)
        self.scroll_area.setLayout(QHBoxLayout())
        self.layout().addWidget(self.scroll_area)

        test = Test("test test")

        for i in range(30):
            self.add_layer(test, i)

    def add_layer(self, layer, n):
        inner_box = QGroupBox()
        self.scroll_area.layout().addWidget(inner_box)
        inner_box.setLayout(QVBoxLayout())
        inner_box.setTitle(f"Layer {n}")

        label = QLabel(layer.type_name)
        inner_box.layout().addWidget(label)


class Test:
    def __init__(self, name):
        self.type_name = name

What I want to do is, I want the inner boxes to not get resized and be as large as necessary to show the labels within it, and if I add more inner boxes than the window can fit then a horizontal scrollbar should show up, how can I achieve this?

eyllanesc
  • 235,170
  • 19
  • 170
  • 241
Janilson
  • 1,042
  • 1
  • 9
  • 23
  • Try [`self.scroll_area.setWidgetResizable(True)`](https://doc.qt.io/qt-5/qscrollarea.html#widgetResizable-prop). – G.M. Oct 24 '21 at 17:42
  • @G.M. wouldn't `False` make more sense than `True` since I don't want to resize it? Anyway I tried with both true and false and neither changed anything. I also tried changing the `QSizePolicy` to Minimum on both the inner boxes and the `QLabel` and that didn't work either. – Janilson Oct 24 '21 at 17:53
  • @Janilson no, besides what I point out in my answer, the widgetResizable doesn't mean that "you don't want to resize it": it's based on the fact that all widgets *can* be resized based on their size hints, policies and constraints. Unless you explicitly set a minimum size for the content widget, the scroll area will try to "shrink" it in order to show it without the need for scrollbars, completely ignoring further resizing of the scrollarea itself. – musicamante Oct 24 '21 at 18:03
  • 1
    I'm voting to reopen this question, as while the proposed duplicate does indeed explain how to properly use a QScrollArea, the problem of this question has a different cause (using the layout of the scrollarea). – musicamante Oct 24 '21 at 18:05
  • @musicamante In the duplicate I explain how to use the layouts within the QScrollArea. – eyllanesc Oct 24 '21 at 18:11
  • 1
    @eyllanesc I know, but the problem is that the OP has set the layout *on* the QScrollArea, and never used `setWidget()`. So, the cause of the problem and its explanation (the *answer*) are different, even if the *solution* is eventually the same. – musicamante Oct 24 '21 at 18:18
  • @musicamante There are several types of answers: The one that explains the cause of the error and the solution, and the one that shows the correct form. Both ways are solutions, so mark it as a duplicate. The duplicate does not invalidate your answer, the duplicate only links questions. – eyllanesc Oct 24 '21 at 18:20
  • @eyllanesc I know it doesn't invalidate it, but conceptually speaking, this *is* a different question: I'm not worried about my answer, but the fact that the question could theoretically be still open to other answers (the fact that there *could* actually be *other* answers is irrelevant), while marking it as duplicate results in its closure. Mine is more a matter of principle, but, hey, we don't have to agree :-) – musicamante Oct 24 '21 at 18:28

1 Answers1

1

A QScrollArea is not the container of the widgets that you want to scroll, but only the "viewer" for the actual widget (the container) that is actually being scrolled.

You should not set a layout for the scroll area, but create a widget, set a layout for that widget, and then use setWidget().

You also need to use setWidgetResizable to ensure that the container widget is properly resized leaving sufficient space to all the managed widgets and eventually show the scroll bars when required.

I suggest you to carefully read the QScrollArea documentation in order to better understand how it works.

class LayerParamsBox(QGroupBox):
    def __init__(self):
        # ...
        contents = QWidget()
        self.scroll_area_layout = QHBoxLayout(contents)
        self.scroll_area.setWidget(contents)
        self.scroll_area.setWidgetResizable(True)
        # ...

    def add_layer(self, layer, n):
        inner_box = QGroupBox()
        self.scroll_area_layout.addWidget(inner_box)
        # ...
musicamante
  • 41,230
  • 6
  • 33
  • 58