How to create a scrollable QVBoxLayout?

Ross picture Ross · Jul 4, 2011 · Viewed 29.2k times · Source

I'm trying to put a QVBoxLayout inside a QScrollArea in order for it to be scrollable vertically. However items don't seem to be added to it.

I saw a suggestion that I ought to create an inner widget that the ScrollArea uses and to place the layout inside that, although it doesn't seem to have worked. My structure is supposed to look like this:

+-------------------------------
| QScrollArea(realmScroll)
| +----------------------------
| | QWidget(realmScrollInner)
| | +-------------------------
| | | QVBoxLayout(realmLayout)

And the code to do this:

# Irrelevant, added for context (this works)
centralWidget = QWidget(self)
self.container = QVBoxLayout(centralWidget)
centralWidget.setLayout(self.container)
self.setCentralWidget(centralWidget)

# Where trouble starts
self.realmScroll = QScrollArea(self.container.widget())
self.realmScroll.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded)

self.realmLayout = QVBoxLayout(self.container.widget())

self.realmScrollInner = QWidget(self.realmScroll)
self.realmScrollInner.setLayout(self.realmLayout)

self.realmScroll.setWidget(self.realmScrollInner)
self.container.addWidget(self.realmScroll)

# Doesn't add to realmLayout
self.realmLayout.addWidget(QLabel("test"))

I'm still learning Qt (2 days in), so in-depth answers to where I'm going wrong would be appreciated.

Update:

It seems that the addWidget(QLabel()) works right up until the realmScrollInner has been set as realmScroll's widget. Since I'd like to add elements after the UI has been displayed I have to do this, which I'm not sure is really correct:

self.realmLayout.addWidget(QLabel("test"))

# realmScrollInner bound to realmScroll
realmScroll.setWidget(realmScrollInner)
self.container.addWidget(realmScroll)

# Access realmScroll's widget and then layout to add
realmScroll.widget().layout().addWidget(QLabel("test"))

But if you remove that first call to addWidget before the widget has been bound (so the layout has no widgets), then bind to the ScrollArea widgets added afterwards are not displayed. Perhaps the ScrollArea needs repainting (although I don't see a method for that)?

Update 2: Calling repaint() on realmScroll or its contained widget does nothing, as does calling activate/update() on the layout.

Answer

Ross picture Ross · Jul 4, 2011

It turned out that I was lead down a wrong path by putting the layout as the layout of a widget. The actual way to do this is as simple as:

scrollarea = QScrollArea(parent.widget())
layout = QVBoxLayout(scrollarea)
realmScroll.setWidget(layout.widget())

layout.addWidget(QLabel("Test"))

Which I'm pretty sure I tried originally, but hey it's working.

However this adds an issue that the layout's items are shrunk vertically instead of causing the scrollarea to add a scrollbar.